Ticket #48040: 48040.diff
| File 48040.diff, 430.5 KB (added by , 7 years ago) |
|---|
-
src/wp-includes/ID3/getid3.lib.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 7 ///////////////////////////////////////////////////////////////// 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 8 // // 9 9 // getid3.lib.php - part of getID3() // 10 // See readme.txt for more details//10 // see readme.txt for more details // 11 11 // /// 12 12 ///////////////////////////////////////////////////////////////// 13 13 … … 14 14 15 15 class getid3_lib 16 16 { 17 17 /** 18 * @param string $string 19 * @param bool $hex 20 * @param bool $spaces 21 * @param string $htmlencoding 22 * 23 * @return string 24 */ 18 25 public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') { 19 26 $returnstring = ''; 20 27 for ($i = 0; $i < strlen($string); $i++) { 21 28 if ($hex) { 22 $returnstring .= str_pad(dechex(ord($string {$i})), 2, '0', STR_PAD_LEFT);29 $returnstring .= str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT); 23 30 } else { 24 $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string {$i}) ? $string{$i}: '¤');31 $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string[$i]) ? $string[$i] : '¤'); 25 32 } 26 33 if ($spaces) { 27 34 $returnstring .= ' '; … … 36 43 return $returnstring; 37 44 } 38 45 46 /** 47 * Truncates a floating-point number at the decimal point. 48 * 49 * @param float $floatnumber 50 * 51 * @return float|int returns int (if possible, otherwise float) 52 */ 39 53 public static function trunc($floatnumber) { 40 // truncates a floating-point number at the decimal point41 // returns int (if possible, otherwise float)42 54 if ($floatnumber >= 1) { 43 55 $truncatednumber = floor($floatnumber); 44 56 } elseif ($floatnumber <= -1) { … … 52 64 return $truncatednumber; 53 65 } 54 66 55 67 /** 68 * @param int|null $variable 69 * @param int $increment 70 * 71 * @return bool 72 */ 56 73 public static function safe_inc(&$variable, $increment=1) { 57 74 if (isset($variable)) { 58 75 $variable += $increment; … … 62 79 return true; 63 80 } 64 81 82 /** 83 * @param int|float $floatnum 84 * 85 * @return int|float 86 */ 65 87 public static function CastAsInt($floatnum) { 66 88 // convert to float if not already 67 89 $floatnum = (float) $floatnum; … … 77 99 return $floatnum; 78 100 } 79 101 102 /** 103 * @param int $num 104 * 105 * @return bool 106 */ 80 107 public static function intValueSupported($num) { 81 108 // check if integers are 64-bit 82 109 static $hasINT64 = null; … … 93 120 return false; 94 121 } 95 122 123 /** 124 * @param string $fraction 125 * 126 * @return float 127 */ 96 128 public static function DecimalizeFraction($fraction) { 97 129 list($numerator, $denominator) = explode('/', $fraction); 98 130 return $numerator / ($denominator ? $denominator : 1); 99 131 } 100 132 101 133 /** 134 * @param string $binarynumerator 135 * 136 * @return float 137 */ 102 138 public static function DecimalBinary2Float($binarynumerator) { 103 139 $numerator = self::Bin2Dec($binarynumerator); 104 140 $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator))); … … 105 141 return ($numerator / $denominator); 106 142 } 107 143 108 144 /** 145 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html 146 * 147 * @param string $binarypointnumber 148 * @param int $maxbits 149 * 150 * @return array 151 */ 109 152 public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) { 110 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html111 153 if (strpos($binarypointnumber, '.') === false) { 112 154 $binarypointnumber = '0.'.$binarypointnumber; 113 } elseif ($binarypointnumber {0}== '.') {155 } elseif ($binarypointnumber[0] == '.') { 114 156 $binarypointnumber = '0'.$binarypointnumber; 115 157 } 116 158 $exponent = 0; 117 while (($binarypointnumber {0}!= '1') || (substr($binarypointnumber, 1, 1) != '.')) {159 while (($binarypointnumber[0] != '1') || (substr($binarypointnumber, 1, 1) != '.')) { 118 160 if (substr($binarypointnumber, 1, 1) == '.') { 119 161 $exponent--; 120 162 $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3); … … 122 164 $pointpos = strpos($binarypointnumber, '.'); 123 165 $exponent += ($pointpos - 1); 124 166 $binarypointnumber = str_replace('.', '', $binarypointnumber); 125 $binarypointnumber = $binarypointnumber {0}.'.'.substr($binarypointnumber, 1);167 $binarypointnumber = $binarypointnumber[0].'.'.substr($binarypointnumber, 1); 126 168 } 127 169 } 128 170 $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT); … … 129 171 return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent); 130 172 } 131 173 132 174 /** 175 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html 176 * 177 * @param float $floatvalue 178 * 179 * @return string 180 */ 133 181 public static function Float2BinaryDecimal($floatvalue) { 134 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html135 182 $maxbits = 128; // to how many bits of precision should the calculations be taken? 136 183 $intpart = self::trunc($floatvalue); 137 184 $floatpart = abs($floatvalue - $intpart); … … 145 192 return $binarypointnumber; 146 193 } 147 194 148 195 /** 196 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html 197 * 198 * @param float $floatvalue 199 * @param int $bits 200 * 201 * @return string|false 202 */ 149 203 public static function Float2String($floatvalue, $bits) { 150 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html 204 $exponentbits = 0; 205 $fractionbits = 0; 151 206 switch ($bits) { 152 207 case 32: 153 208 $exponentbits = 8; … … 176 231 return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false); 177 232 } 178 233 179 234 /** 235 * @param string $byteword 236 * 237 * @return float|false 238 */ 180 239 public static function LittleEndian2Float($byteword) { 181 240 return self::BigEndian2Float(strrev($byteword)); 182 241 } 183 242 184 243 /** 244 * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic 245 * 246 * @link http://www.psc.edu/general/software/packages/ieee/ieee.html 247 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html 248 * 249 * @param string $byteword 250 * 251 * @return float|false 252 */ 185 253 public static function BigEndian2Float($byteword) { 186 // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic187 // http://www.psc.edu/general/software/packages/ieee/ieee.html188 // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html189 190 254 $bitword = self::BigEndian2Bin($byteword); 191 255 if (!$bitword) { 192 256 return 0; 193 257 } 194 $signbit = $bitword{0}; 258 $signbit = $bitword[0]; 259 $floatvalue = 0; 260 $exponentbits = 0; 261 $fractionbits = 0; 195 262 196 263 switch (strlen($byteword) * 8) { 197 264 case 32: … … 208 275 // 80-bit Apple SANE format 209 276 // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ 210 277 $exponentstring = substr($bitword, 1, 15); 211 $isnormalized = intval($bitword {16});278 $isnormalized = intval($bitword[16]); 212 279 $fractionstring = substr($bitword, 17, 63); 213 280 $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383); 214 281 $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring); … … 259 326 return (float) $floatvalue; 260 327 } 261 328 262 329 /** 330 * @param string $byteword 331 * @param bool $synchsafe 332 * @param bool $signed 333 * 334 * @return int|float|false 335 * @throws Exception 336 */ 263 337 public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) { 264 338 $intvalue = 0; 265 339 $bytewordlen = strlen($byteword); … … 269 343 for ($i = 0; $i < $bytewordlen; $i++) { 270 344 if ($synchsafe) { // disregard MSB, effectively 7-bit bytes 271 345 //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems 272 $intvalue += (ord($byteword {$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);346 $intvalue += (ord($byteword[$i]) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7); 273 347 } else { 274 $intvalue += ord($byteword {$i}) * pow(256, ($bytewordlen - 1 - $i));348 $intvalue += ord($byteword[$i]) * pow(256, ($bytewordlen - 1 - $i)); 275 349 } 276 350 } 277 351 if ($signed && !$synchsafe) { … … 288 362 return self::CastAsInt($intvalue); 289 363 } 290 364 291 365 /** 366 * @param string $byteword 367 * @param bool $signed 368 * 369 * @return int|float|false 370 */ 292 371 public static function LittleEndian2Int($byteword, $signed=false) { 293 372 return self::BigEndian2Int(strrev($byteword), false, $signed); 294 373 } 295 374 375 /** 376 * @param string $byteword 377 * 378 * @return string 379 */ 296 380 public static function LittleEndian2Bin($byteword) { 297 381 return self::BigEndian2Bin(strrev($byteword)); 298 382 } 299 383 384 /** 385 * @param string $byteword 386 * 387 * @return string 388 */ 300 389 public static function BigEndian2Bin($byteword) { 301 390 $binvalue = ''; 302 391 $bytewordlen = strlen($byteword); 303 392 for ($i = 0; $i < $bytewordlen; $i++) { 304 $binvalue .= str_pad(decbin(ord($byteword {$i})), 8, '0', STR_PAD_LEFT);393 $binvalue .= str_pad(decbin(ord($byteword[$i])), 8, '0', STR_PAD_LEFT); 305 394 } 306 395 return $binvalue; 307 396 } 308 397 309 398 /** 399 * @param int $number 400 * @param int $minbytes 401 * @param bool $synchsafe 402 * @param bool $signed 403 * 404 * @return string 405 * @throws Exception 406 */ 310 407 public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) { 311 408 if ($number < 0) { 312 409 throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers'); … … 327 424 return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT); 328 425 } 329 426 330 427 /** 428 * @param int $number 429 * 430 * @return string 431 */ 331 432 public static function Dec2Bin($number) { 332 433 while ($number >= 256) { 333 434 $bytes[] = (($number / 256) - (floor($number / 256))) * 256; … … 341 442 return $binstring; 342 443 } 343 444 344 445 /** 446 * @param string $binstring 447 * @param bool $signed 448 * 449 * @return int|float 450 */ 345 451 public static function Bin2Dec($binstring, $signed=false) { 346 452 $signmult = 1; 347 453 if ($signed) { 348 if ($binstring {0}== '1') {454 if ($binstring[0] == '1') { 349 455 $signmult = -1; 350 456 } 351 457 $binstring = substr($binstring, 1); … … 357 463 return self::CastAsInt($decvalue * $signmult); 358 464 } 359 465 360 466 /** 467 * @param string $binstring 468 * 469 * @return string 470 */ 361 471 public static function Bin2String($binstring) { 362 472 // return 'hi' for input of '0110100001101001' 363 473 $string = ''; … … 368 478 return $string; 369 479 } 370 480 371 481 /** 482 * @param int $number 483 * @param int $minbytes 484 * @param bool $synchsafe 485 * 486 * @return string 487 */ 372 488 public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { 373 489 $intstring = ''; 374 490 while ($number > 0) { … … 383 499 return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); 384 500 } 385 501 386 502 /** 503 * @param array $array1 504 * @param array $array2 505 * 506 * @return array|false 507 */ 387 508 public static function array_merge_clobber($array1, $array2) { 388 509 // written by kcØhireability*com 389 510 // taken from http://www.php.net/manual/en/function.array-merge-recursive.php … … 401 522 return $newarray; 402 523 } 403 524 404 525 /** 526 * @param array $array1 527 * @param array $array2 528 * 529 * @return array|false 530 */ 405 531 public static function array_merge_noclobber($array1, $array2) { 406 532 if (!is_array($array1) || !is_array($array2)) { 407 533 return false; … … 417 543 return $newarray; 418 544 } 419 545 546 /** 547 * @param array $array1 548 * @param array $array2 549 * 550 * @return array|false|null 551 */ 420 552 public static function flipped_array_merge_noclobber($array1, $array2) { 421 553 if (!is_array($array1) || !is_array($array2)) { 422 554 return false; … … 431 563 return array_flip($newarray); 432 564 } 433 565 434 566 /** 567 * @param array $theArray 568 * 569 * @return bool 570 */ 435 571 public static function ksort_recursive(&$theArray) { 436 572 ksort($theArray); 437 573 foreach ($theArray as $key => $value) { … … 442 578 return true; 443 579 } 444 580 581 /** 582 * @param string $filename 583 * @param int $numextensions 584 * 585 * @return string 586 */ 445 587 public static function fileextension($filename, $numextensions=1) { 446 588 if (strstr($filename, '.')) { 447 589 $reversedfilename = strrev($filename); … … 457 599 return ''; 458 600 } 459 601 460 602 /** 603 * @param int $seconds 604 * 605 * @return string 606 */ 461 607 public static function PlaytimeString($seconds) { 462 608 $sign = (($seconds < 0) ? '-' : ''); 463 609 $seconds = round(abs($seconds)); … … 467 613 return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT); 468 614 } 469 615 470 616 /** 617 * @param int $macdate 618 * 619 * @return int|float 620 */ 471 621 public static function DateMac2Unix($macdate) { 472 622 // Macintosh timestamp: seconds since 00:00h January 1, 1904 473 623 // UNIX timestamp: seconds since 00:00h January 1, 1970 … … 474 624 return self::CastAsInt($macdate - 2082844800); 475 625 } 476 626 477 627 /** 628 * @param string $rawdata 629 * 630 * @return float 631 */ 478 632 public static function FixedPoint8_8($rawdata) { 479 633 return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8)); 480 634 } 481 635 482 636 /** 637 * @param string $rawdata 638 * 639 * @return float 640 */ 483 641 public static function FixedPoint16_16($rawdata) { 484 642 return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16)); 485 643 } 486 644 487 645 /** 646 * @param string $rawdata 647 * 648 * @return float 649 */ 488 650 public static function FixedPoint2_30($rawdata) { 489 651 $binarystring = self::BigEndian2Bin($rawdata); 490 652 return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30)); … … 491 653 } 492 654 493 655 656 /** 657 * @param string $ArrayPath 658 * @param string $Separator 659 * @param mixed $Value 660 * 661 * @return array 662 */ 494 663 public static function CreateDeepArray($ArrayPath, $Separator, $Value) { 495 664 // assigns $Value to a nested array path: 496 665 // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt') … … 507 676 return $ReturnedArray; 508 677 } 509 678 679 /** 680 * @param array $arraydata 681 * @param bool $returnkey 682 * 683 * @return int|false 684 */ 510 685 public static function array_max($arraydata, $returnkey=false) { 511 686 $maxvalue = false; 512 687 $maxkey = false; … … 521 696 return ($returnkey ? $maxkey : $maxvalue); 522 697 } 523 698 699 /** 700 * @param array $arraydata 701 * @param bool $returnkey 702 * 703 * @return int|false 704 */ 524 705 public static function array_min($arraydata, $returnkey=false) { 525 706 $minvalue = false; 526 707 $minkey = false; … … 535 716 return ($returnkey ? $minkey : $minvalue); 536 717 } 537 718 719 /** 720 * @param string $XMLstring 721 * 722 * @return array|false 723 */ 538 724 public static function XML2array($XMLstring) { 539 725 if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) { 540 726 // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html … … 548 734 return false; 549 735 } 550 736 737 /** 738 * @param SimpleXMLElement|array $XMLobject 739 * 740 * @return array 741 */ 551 742 public static function SimpleXMLelement2array($XMLobject) { 552 743 if (!is_object($XMLobject) && !is_array($XMLobject)) { 553 744 return $XMLobject; 554 745 } 555 $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);746 $XMLarray = $XMLobject instanceof SimpleXMLElement ? get_object_vars($XMLobject) : $XMLobject; 556 747 foreach ($XMLarray as $key => $value) { 557 748 $XMLarray[$key] = self::SimpleXMLelement2array($value); 558 749 } … … 559 750 return $XMLarray; 560 751 } 561 752 562 563 // Allan Hansen <ahØartemis*dk> 564 // self::md5_data() - returns md5sum for a file from startuing position to absolute end position 753 /** 754 * Returns checksum for a file from starting position to absolute end position. 755 * 756 * @param string $file 757 * @param int $offset 758 * @param int $end 759 * @param string $algorithm 760 * 761 * @return string|false 762 * @throws getid3_exception 763 */ 565 764 public static function hash_data($file, $offset, $end, $algorithm) { 566 static $tempdir = '';567 765 if (!self::intValueSupported($end)) { 568 766 return false; 569 767 } 570 switch ($algorithm) { 571 case 'md5': 572 $hash_function = 'md5_file'; 573 $unix_call = 'md5sum'; 574 $windows_call = 'md5sum.exe'; 575 $hash_length = 32; 576 break; 768 if (!in_array($algorithm, array('md5', 'sha1'))) { 769 throw new getid3_exception('Invalid algorithm ('.$algorithm.') in self::hash_data()'); 770 } 577 771 578 case 'sha1':579 $hash_function = 'sha1_file';580 $unix_call = 'sha1sum';581 $windows_call = 'sha1sum.exe';582 $hash_length = 40;583 break;584 585 default:586 throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');587 break;588 }589 772 $size = $end - $offset; 590 while (true) {591 if (GETID3_OS_ISWINDOWS) {592 773 593 // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data 594 // Fall back to create-temp-file method: 595 if ($algorithm == 'sha1') { 596 break; 597 } 598 599 $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call); 600 foreach ($RequiredFiles as $required_file) { 601 if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { 602 // helper apps not available - fall back to old method 603 break 2; 604 } 605 } 606 $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | '; 607 $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | '; 608 $commandline .= GETID3_HELPERAPPSDIR.$windows_call; 609 610 } else { 611 612 $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | '; 613 $commandline .= 'tail -c'.$size.' | '; 614 $commandline .= $unix_call; 615 616 } 617 if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { 618 //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm'); 619 break; 620 } 621 return substr(`$commandline`, 0, $hash_length); 774 $fp = fopen($file, 'rb'); 775 fseek($fp, $offset); 776 $ctx = hash_init($algorithm); 777 while ($size > 0) { 778 $buffer = fread($fp, min($size, getID3::FREAD_BUFFER_SIZE)); 779 hash_update($ctx, $buffer); 780 $size -= getID3::FREAD_BUFFER_SIZE; 622 781 } 782 $hash = hash_final($ctx); 783 fclose($fp); 623 784 624 if (empty($tempdir)) { 625 // yes this is ugly, feel free to suggest a better way 626 require_once(dirname(__FILE__).'/getid3.php'); 627 $getid3_temp = new getID3(); 628 $tempdir = $getid3_temp->tempdir; 629 unset($getid3_temp); 630 } 631 // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir 632 if (($data_filename = tempnam($tempdir, 'gI3')) === false) { 633 // can't find anywhere to create a temp file, just fail 634 return false; 635 } 636 637 // Init 638 $result = false; 639 640 // copy parts of file 641 try { 642 self::CopyFileParts($file, $data_filename, $offset, $end - $offset); 643 $result = $hash_function($data_filename); 644 } catch (Exception $e) { 645 throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage()); 646 } 647 unlink($data_filename); 648 return $result; 785 return $hash; 649 786 } 650 787 788 /** 789 * @param string $filename_source 790 * @param string $filename_dest 791 * @param int $offset 792 * @param int $length 793 * 794 * @return bool 795 * @throws Exception 796 * 797 * @deprecated Unused, may be removed in future versions of getID3 798 */ 651 799 public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) { 652 800 if (!self::intValueSupported($offset + $length)) { 653 801 throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit'); … … 660 808 $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite); 661 809 $byteslefttowrite -= $byteswritten; 662 810 } 811 fclose($fp_dest); 663 812 return true; 664 813 } else { 814 fclose($fp_src); 665 815 throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source); 666 816 } 667 fclose($fp_dest);668 817 } else { 669 818 throw new Exception('failed to create file for writing '.$filename_dest); 670 819 } 671 fclose($fp_src);672 820 } else { 673 821 throw new Exception('failed to open file for reading '.$filename_source); 674 822 } 675 return false;676 823 } 677 824 825 /** 826 * @param int $charval 827 * 828 * @return string 829 */ 678 830 public static function iconv_fallback_int_utf8($charval) { 679 831 if ($charval < 128) { 680 832 // 0bbbbbbb … … 698 850 return $newcharstring; 699 851 } 700 852 701 // ISO-8859-1 => UTF-8 853 /** 854 * ISO-8859-1 => UTF-8 855 * 856 * @param string $string 857 * @param bool $bom 858 * 859 * @return string 860 */ 702 861 public static function iconv_fallback_iso88591_utf8($string, $bom=false) { 703 862 if (function_exists('utf8_encode')) { 704 863 return utf8_encode($string); … … 709 868 $newcharstring .= "\xEF\xBB\xBF"; 710 869 } 711 870 for ($i = 0; $i < strlen($string); $i++) { 712 $charval = ord($string {$i});871 $charval = ord($string[$i]); 713 872 $newcharstring .= self::iconv_fallback_int_utf8($charval); 714 873 } 715 874 return $newcharstring; 716 875 } 717 876 718 // ISO-8859-1 => UTF-16BE 877 /** 878 * ISO-8859-1 => UTF-16BE 879 * 880 * @param string $string 881 * @param bool $bom 882 * 883 * @return string 884 */ 719 885 public static function iconv_fallback_iso88591_utf16be($string, $bom=false) { 720 886 $newcharstring = ''; 721 887 if ($bom) { … … 722 888 $newcharstring .= "\xFE\xFF"; 723 889 } 724 890 for ($i = 0; $i < strlen($string); $i++) { 725 $newcharstring .= "\x00".$string {$i};891 $newcharstring .= "\x00".$string[$i]; 726 892 } 727 893 return $newcharstring; 728 894 } 729 895 730 // ISO-8859-1 => UTF-16LE 896 /** 897 * ISO-8859-1 => UTF-16LE 898 * 899 * @param string $string 900 * @param bool $bom 901 * 902 * @return string 903 */ 731 904 public static function iconv_fallback_iso88591_utf16le($string, $bom=false) { 732 905 $newcharstring = ''; 733 906 if ($bom) { … … 734 907 $newcharstring .= "\xFF\xFE"; 735 908 } 736 909 for ($i = 0; $i < strlen($string); $i++) { 737 $newcharstring .= $string {$i}."\x00";910 $newcharstring .= $string[$i]."\x00"; 738 911 } 739 912 return $newcharstring; 740 913 } 741 914 742 // ISO-8859-1 => UTF-16LE (BOM) 915 /** 916 * ISO-8859-1 => UTF-16LE (BOM) 917 * 918 * @param string $string 919 * 920 * @return string 921 */ 743 922 public static function iconv_fallback_iso88591_utf16($string) { 744 923 return self::iconv_fallback_iso88591_utf16le($string, true); 745 924 } 746 925 747 // UTF-8 => ISO-8859-1 926 /** 927 * UTF-8 => ISO-8859-1 928 * 929 * @param string $string 930 * 931 * @return string 932 */ 748 933 public static function iconv_fallback_utf8_iso88591($string) { 749 934 if (function_exists('utf8_decode')) { 750 935 return utf8_decode($string); … … 754 939 $offset = 0; 755 940 $stringlength = strlen($string); 756 941 while ($offset < $stringlength) { 757 if ((ord($string {$offset}) | 0x07) == 0xF7) {942 if ((ord($string[$offset]) | 0x07) == 0xF7) { 758 943 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb 759 $charval = ((ord($string {($offset + 0)}) & 0x07) << 18) &760 ((ord($string {($offset + 1)}) & 0x3F) << 12) &761 ((ord($string {($offset + 2)}) & 0x3F) << 6) &762 (ord($string {($offset + 3)}) & 0x3F);944 $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) & 945 ((ord($string[($offset + 1)]) & 0x3F) << 12) & 946 ((ord($string[($offset + 2)]) & 0x3F) << 6) & 947 (ord($string[($offset + 3)]) & 0x3F); 763 948 $offset += 4; 764 } elseif ((ord($string {$offset}) | 0x0F) == 0xEF) {949 } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) { 765 950 // 1110bbbb 10bbbbbb 10bbbbbb 766 $charval = ((ord($string {($offset + 0)}) & 0x0F) << 12) &767 ((ord($string {($offset + 1)}) & 0x3F) << 6) &768 (ord($string {($offset + 2)}) & 0x3F);951 $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) & 952 ((ord($string[($offset + 1)]) & 0x3F) << 6) & 953 (ord($string[($offset + 2)]) & 0x3F); 769 954 $offset += 3; 770 } elseif ((ord($string {$offset}) | 0x1F) == 0xDF) {955 } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) { 771 956 // 110bbbbb 10bbbbbb 772 $charval = ((ord($string {($offset + 0)}) & 0x1F) << 6) &773 (ord($string {($offset + 1)}) & 0x3F);957 $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) & 958 (ord($string[($offset + 1)]) & 0x3F); 774 959 $offset += 2; 775 } elseif ((ord($string {$offset}) | 0x7F) == 0x7F) {960 } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) { 776 961 // 0bbbbbbb 777 $charval = ord($string {$offset});962 $charval = ord($string[$offset]); 778 963 $offset += 1; 779 964 } else { 780 965 // error? throw some kind of warning here? … … 788 973 return $newcharstring; 789 974 } 790 975 791 // UTF-8 => UTF-16BE 976 /** 977 * UTF-8 => UTF-16BE 978 * 979 * @param string $string 980 * @param bool $bom 981 * 982 * @return string 983 */ 792 984 public static function iconv_fallback_utf8_utf16be($string, $bom=false) { 793 985 $newcharstring = ''; 794 986 if ($bom) { … … 797 989 $offset = 0; 798 990 $stringlength = strlen($string); 799 991 while ($offset < $stringlength) { 800 if ((ord($string {$offset}) | 0x07) == 0xF7) {992 if ((ord($string[$offset]) | 0x07) == 0xF7) { 801 993 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb 802 $charval = ((ord($string {($offset + 0)}) & 0x07) << 18) &803 ((ord($string {($offset + 1)}) & 0x3F) << 12) &804 ((ord($string {($offset + 2)}) & 0x3F) << 6) &805 (ord($string {($offset + 3)}) & 0x3F);994 $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) & 995 ((ord($string[($offset + 1)]) & 0x3F) << 12) & 996 ((ord($string[($offset + 2)]) & 0x3F) << 6) & 997 (ord($string[($offset + 3)]) & 0x3F); 806 998 $offset += 4; 807 } elseif ((ord($string {$offset}) | 0x0F) == 0xEF) {999 } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) { 808 1000 // 1110bbbb 10bbbbbb 10bbbbbb 809 $charval = ((ord($string {($offset + 0)}) & 0x0F) << 12) &810 ((ord($string {($offset + 1)}) & 0x3F) << 6) &811 (ord($string {($offset + 2)}) & 0x3F);1001 $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) & 1002 ((ord($string[($offset + 1)]) & 0x3F) << 6) & 1003 (ord($string[($offset + 2)]) & 0x3F); 812 1004 $offset += 3; 813 } elseif ((ord($string {$offset}) | 0x1F) == 0xDF) {1005 } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) { 814 1006 // 110bbbbb 10bbbbbb 815 $charval = ((ord($string {($offset + 0)}) & 0x1F) << 6) &816 (ord($string {($offset + 1)}) & 0x3F);1007 $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) & 1008 (ord($string[($offset + 1)]) & 0x3F); 817 1009 $offset += 2; 818 } elseif ((ord($string {$offset}) | 0x7F) == 0x7F) {1010 } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) { 819 1011 // 0bbbbbbb 820 $charval = ord($string {$offset});1012 $charval = ord($string[$offset]); 821 1013 $offset += 1; 822 1014 } else { 823 1015 // error? throw some kind of warning here? … … 831 1023 return $newcharstring; 832 1024 } 833 1025 834 // UTF-8 => UTF-16LE 1026 /** 1027 * UTF-8 => UTF-16LE 1028 * 1029 * @param string $string 1030 * @param bool $bom 1031 * 1032 * @return string 1033 */ 835 1034 public static function iconv_fallback_utf8_utf16le($string, $bom=false) { 836 1035 $newcharstring = ''; 837 1036 if ($bom) { … … 840 1039 $offset = 0; 841 1040 $stringlength = strlen($string); 842 1041 while ($offset < $stringlength) { 843 if ((ord($string {$offset}) | 0x07) == 0xF7) {1042 if ((ord($string[$offset]) | 0x07) == 0xF7) { 844 1043 // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb 845 $charval = ((ord($string {($offset + 0)}) & 0x07) << 18) &846 ((ord($string {($offset + 1)}) & 0x3F) << 12) &847 ((ord($string {($offset + 2)}) & 0x3F) << 6) &848 (ord($string {($offset + 3)}) & 0x3F);1044 $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) & 1045 ((ord($string[($offset + 1)]) & 0x3F) << 12) & 1046 ((ord($string[($offset + 2)]) & 0x3F) << 6) & 1047 (ord($string[($offset + 3)]) & 0x3F); 849 1048 $offset += 4; 850 } elseif ((ord($string {$offset}) | 0x0F) == 0xEF) {1049 } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) { 851 1050 // 1110bbbb 10bbbbbb 10bbbbbb 852 $charval = ((ord($string {($offset + 0)}) & 0x0F) << 12) &853 ((ord($string {($offset + 1)}) & 0x3F) << 6) &854 (ord($string {($offset + 2)}) & 0x3F);1051 $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) & 1052 ((ord($string[($offset + 1)]) & 0x3F) << 6) & 1053 (ord($string[($offset + 2)]) & 0x3F); 855 1054 $offset += 3; 856 } elseif ((ord($string {$offset}) | 0x1F) == 0xDF) {1055 } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) { 857 1056 // 110bbbbb 10bbbbbb 858 $charval = ((ord($string {($offset + 0)}) & 0x1F) << 6) &859 (ord($string {($offset + 1)}) & 0x3F);1057 $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) & 1058 (ord($string[($offset + 1)]) & 0x3F); 860 1059 $offset += 2; 861 } elseif ((ord($string {$offset}) | 0x7F) == 0x7F) {1060 } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) { 862 1061 // 0bbbbbbb 863 $charval = ord($string {$offset});1062 $charval = ord($string[$offset]); 864 1063 $offset += 1; 865 1064 } else { 866 1065 // error? maybe throw some warning here? … … 874 1073 return $newcharstring; 875 1074 } 876 1075 877 // UTF-8 => UTF-16LE (BOM) 1076 /** 1077 * UTF-8 => UTF-16LE (BOM) 1078 * 1079 * @param string $string 1080 * 1081 * @return string 1082 */ 878 1083 public static function iconv_fallback_utf8_utf16($string) { 879 1084 return self::iconv_fallback_utf8_utf16le($string, true); 880 1085 } 881 1086 882 // UTF-16BE => UTF-8 1087 /** 1088 * UTF-16BE => UTF-8 1089 * 1090 * @param string $string 1091 * 1092 * @return string 1093 */ 883 1094 public static function iconv_fallback_utf16be_utf8($string) { 884 1095 if (substr($string, 0, 2) == "\xFE\xFF") { 885 1096 // strip BOM … … 893 1104 return $newcharstring; 894 1105 } 895 1106 896 // UTF-16LE => UTF-8 1107 /** 1108 * UTF-16LE => UTF-8 1109 * 1110 * @param string $string 1111 * 1112 * @return string 1113 */ 897 1114 public static function iconv_fallback_utf16le_utf8($string) { 898 1115 if (substr($string, 0, 2) == "\xFF\xFE") { 899 1116 // strip BOM … … 907 1124 return $newcharstring; 908 1125 } 909 1126 910 // UTF-16BE => ISO-8859-1 1127 /** 1128 * UTF-16BE => ISO-8859-1 1129 * 1130 * @param string $string 1131 * 1132 * @return string 1133 */ 911 1134 public static function iconv_fallback_utf16be_iso88591($string) { 912 1135 if (substr($string, 0, 2) == "\xFE\xFF") { 913 1136 // strip BOM … … 921 1144 return $newcharstring; 922 1145 } 923 1146 924 // UTF-16LE => ISO-8859-1 1147 /** 1148 * UTF-16LE => ISO-8859-1 1149 * 1150 * @param string $string 1151 * 1152 * @return string 1153 */ 925 1154 public static function iconv_fallback_utf16le_iso88591($string) { 926 1155 if (substr($string, 0, 2) == "\xFF\xFE") { 927 1156 // strip BOM … … 935 1164 return $newcharstring; 936 1165 } 937 1166 938 // UTF-16 (BOM) => ISO-8859-1 1167 /** 1168 * UTF-16 (BOM) => ISO-8859-1 1169 * 1170 * @param string $string 1171 * 1172 * @return string 1173 */ 939 1174 public static function iconv_fallback_utf16_iso88591($string) { 940 1175 $bom = substr($string, 0, 2); 941 1176 if ($bom == "\xFE\xFF") { … … 946 1181 return $string; 947 1182 } 948 1183 949 // UTF-16 (BOM) => UTF-8 1184 /** 1185 * UTF-16 (BOM) => UTF-8 1186 * 1187 * @param string $string 1188 * 1189 * @return string 1190 */ 950 1191 public static function iconv_fallback_utf16_utf8($string) { 951 1192 $bom = substr($string, 0, 2); 952 1193 if ($bom == "\xFE\xFF") { … … 957 1198 return $string; 958 1199 } 959 1200 1201 /** 1202 * @param string $in_charset 1203 * @param string $out_charset 1204 * @param string $string 1205 * 1206 * @return string 1207 * @throws Exception 1208 */ 960 1209 public static function iconv_fallback($in_charset, $out_charset, $string) { 961 1210 962 1211 if ($in_charset == $out_charset) { … … 963 1212 return $string; 964 1213 } 965 1214 966 // mb_convert_encoding() avail ble1215 // mb_convert_encoding() available 967 1216 if (function_exists('mb_convert_encoding')) { 1217 if ((strtoupper($in_charset) == 'UTF-16') && (substr($string, 0, 2) != "\xFE\xFF") && (substr($string, 0, 2) != "\xFF\xFE")) { 1218 // if BOM missing, mb_convert_encoding will mishandle the conversion, assume UTF-16BE and prepend appropriate BOM 1219 $string = "\xFF\xFE".$string; 1220 } 1221 if ((strtoupper($in_charset) == 'UTF-16') && (strtoupper($out_charset) == 'UTF-8')) { 1222 if (($string == "\xFF\xFE") || ($string == "\xFE\xFF")) { 1223 // if string consists of only BOM, mb_convert_encoding will return the BOM unmodified 1224 return ''; 1225 } 1226 } 968 1227 if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) { 969 1228 switch ($out_charset) { 970 1229 case 'ISO-8859-1': … … 974 1233 return $converted_string; 975 1234 } 976 1235 return $string; 977 } 978 // iconv() avail ble979 elseif (function_exists('iconv')) {1236 1237 // iconv() available 1238 } elseif (function_exists('iconv')) { 980 1239 if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { 981 1240 switch ($out_charset) { 982 1241 case 'ISO-8859-1': … … 1017 1276 throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset); 1018 1277 } 1019 1278 1279 /** 1280 * @param mixed $data 1281 * @param string $charset 1282 * 1283 * @return mixed 1284 */ 1020 1285 public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') { 1021 1286 if (is_string($data)) { 1022 1287 return self::MultiByteCharString2HTML($data, $charset); … … 1031 1296 return $data; 1032 1297 } 1033 1298 1299 /** 1300 * @param string|int|float $string 1301 * @param string $charset 1302 * 1303 * @return string 1304 */ 1034 1305 public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') { 1035 1306 $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string 1036 1307 $HTMLstring = ''; … … 1069 1340 case 'utf-8': 1070 1341 $strlen = strlen($string); 1071 1342 for ($i = 0; $i < $strlen; $i++) { 1072 $char_ord_val = ord($string {$i});1343 $char_ord_val = ord($string[$i]); 1073 1344 $charval = 0; 1074 1345 if ($char_ord_val < 0x80) { 1075 1346 $charval = $char_ord_val; 1076 1347 } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) { 1077 1348 $charval = (($char_ord_val & 0x07) << 18); 1078 $charval += ((ord($string {++$i}) & 0x3F) << 12);1079 $charval += ((ord($string {++$i}) & 0x3F) << 6);1080 $charval += (ord($string {++$i}) & 0x3F);1349 $charval += ((ord($string[++$i]) & 0x3F) << 12); 1350 $charval += ((ord($string[++$i]) & 0x3F) << 6); 1351 $charval += (ord($string[++$i]) & 0x3F); 1081 1352 } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) { 1082 1353 $charval = (($char_ord_val & 0x0F) << 12); 1083 $charval += ((ord($string {++$i}) & 0x3F) << 6);1084 $charval += (ord($string {++$i}) & 0x3F);1354 $charval += ((ord($string[++$i]) & 0x3F) << 6); 1355 $charval += (ord($string[++$i]) & 0x3F); 1085 1356 } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) { 1086 1357 $charval = (($char_ord_val & 0x1F) << 6); 1087 $charval += (ord($string {++$i}) & 0x3F);1358 $charval += (ord($string[++$i]) & 0x3F); 1088 1359 } 1089 1360 if (($charval >= 32) && ($charval <= 127)) { 1090 1361 $HTMLstring .= htmlentities(chr($charval)); … … 1123 1394 return $HTMLstring; 1124 1395 } 1125 1396 1126 1127 1397 /** 1398 * @param int $namecode 1399 * 1400 * @return string 1401 */ 1128 1402 public static function RGADnameLookup($namecode) { 1129 1403 static $RGADname = array(); 1130 1404 if (empty($RGADname)) { … … 1136 1410 return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : ''); 1137 1411 } 1138 1412 1139 1413 /** 1414 * @param int $originatorcode 1415 * 1416 * @return string 1417 */ 1140 1418 public static function RGADoriginatorLookup($originatorcode) { 1141 1419 static $RGADoriginator = array(); 1142 1420 if (empty($RGADoriginator)) { … … 1149 1427 return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : ''); 1150 1428 } 1151 1429 1152 1430 /** 1431 * @param int $rawadjustment 1432 * @param int $signbit 1433 * 1434 * @return float 1435 */ 1153 1436 public static function RGADadjustmentLookup($rawadjustment, $signbit) { 1154 $adjustment = $rawadjustment / 10;1437 $adjustment = (float) $rawadjustment / 10; 1155 1438 if ($signbit == 1) { 1156 1439 $adjustment *= -1; 1157 1440 } 1158 return (float)$adjustment;1441 return $adjustment; 1159 1442 } 1160 1443 1161 1444 /** 1445 * @param int $namecode 1446 * @param int $originatorcode 1447 * @param int $replaygain 1448 * 1449 * @return string 1450 */ 1162 1451 public static function RGADgainString($namecode, $originatorcode, $replaygain) { 1163 1452 if ($replaygain < 0) { 1164 1453 $signbit = '1'; … … 1174 1463 return $gainstring; 1175 1464 } 1176 1465 1466 /** 1467 * @param float $amplitude 1468 * 1469 * @return float 1470 */ 1177 1471 public static function RGADamplitude2dB($amplitude) { 1178 1472 return 20 * log10($amplitude); 1179 1473 } 1180 1474 1181 1475 /** 1476 * @param string $imgData 1477 * @param array $imageinfo 1478 * 1479 * @return array|false 1480 */ 1182 1481 public static function GetDataImageSize($imgData, &$imageinfo=array()) { 1183 1482 static $tempdir = ''; 1184 1483 if (empty($tempdir)) { … … 1213 1512 return $GetDataImageSize; 1214 1513 } 1215 1514 1515 /** 1516 * @param string $mime_type 1517 * 1518 * @return string 1519 */ 1216 1520 public static function ImageExtFromMime($mime_type) { 1217 1521 // temporary way, works OK for now, but should be reworked in the future 1218 1522 return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type); 1219 1523 } 1220 1524 1221 public static function ImageTypesLookup($imagetypeid) { 1222 static $ImageTypesLookup = array(); 1223 if (empty($ImageTypesLookup)) { 1224 $ImageTypesLookup[1] = 'gif'; 1225 $ImageTypesLookup[2] = 'jpeg'; 1226 $ImageTypesLookup[3] = 'png'; 1227 $ImageTypesLookup[4] = 'swf'; 1228 $ImageTypesLookup[5] = 'psd'; 1229 $ImageTypesLookup[6] = 'bmp'; 1230 $ImageTypesLookup[7] = 'tiff (little-endian)'; 1231 $ImageTypesLookup[8] = 'tiff (big-endian)'; 1232 $ImageTypesLookup[9] = 'jpc'; 1233 $ImageTypesLookup[10] = 'jp2'; 1234 $ImageTypesLookup[11] = 'jpx'; 1235 $ImageTypesLookup[12] = 'jb2'; 1236 $ImageTypesLookup[13] = 'swc'; 1237 $ImageTypesLookup[14] = 'iff'; 1238 } 1239 return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : ''); 1240 } 1241 1525 /** 1526 * @param array $ThisFileInfo 1527 * 1528 * @return bool 1529 */ 1242 1530 public static function CopyTagsToComments(&$ThisFileInfo) { 1243 1531 1244 1532 // Copy all entries from ['tags'] into common ['comments'] … … 1326 1614 return true; 1327 1615 } 1328 1616 1329 1617 /** 1618 * @param string $key 1619 * @param int $begin 1620 * @param int $end 1621 * @param string $file 1622 * @param string $name 1623 * 1624 * @return string 1625 */ 1330 1626 public static function EmbeddedLookup($key, $begin, $end, $file, $name) { 1331 1627 1332 1628 // Cached … … 1373 1669 return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : ''); 1374 1670 } 1375 1671 1672 /** 1673 * @param string $filename 1674 * @param string $sourcefile 1675 * @param bool $DieOnFailure 1676 * 1677 * @return bool 1678 * @throws Exception 1679 */ 1376 1680 public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) { 1377 1681 global $GETID3_ERRORARRAY; 1378 1682 … … 1393 1697 return false; 1394 1698 } 1395 1699 1700 /** 1701 * @param string $string 1702 * 1703 * @return string 1704 */ 1396 1705 public static function trimNullByte($string) { 1397 1706 return trim($string, "\x00"); 1398 1707 } 1399 1708 1709 /** 1710 * @param string $path 1711 * 1712 * @return float|bool 1713 */ 1400 1714 public static function getFileSizeSyscall($path) { 1401 1715 $filesize = false; 1402 1716 … … 1421 1735 return $filesize; 1422 1736 } 1423 1737 1738 /** 1739 * @param string $filename 1740 * 1741 * @return string|false 1742 */ 1743 public static function truepath($filename) { 1744 // 2017-11-08: this could use some improvement, patches welcome 1745 if (preg_match('#^(\\\\\\\\|//)[a-z0-9]#i', $filename, $matches)) { 1746 // PHP's built-in realpath function does not work on UNC Windows shares 1747 $goodpath = array(); 1748 foreach (explode('/', str_replace('\\', '/', $filename)) as $part) { 1749 if ($part == '.') { 1750 continue; 1751 } 1752 if ($part == '..') { 1753 if (count($goodpath)) { 1754 array_pop($goodpath); 1755 } else { 1756 // cannot step above this level, already at top level 1757 return false; 1758 } 1759 } else { 1760 $goodpath[] = $part; 1761 } 1762 } 1763 return implode(DIRECTORY_SEPARATOR, $goodpath); 1764 } 1765 return realpath($filename); 1766 } 1424 1767 1425 1768 /** 1426 * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268) 1427 * @param string $path A path. 1428 * @param string $suffix If the name component ends in suffix this will also be cut off. 1429 * @return string 1430 */ 1769 * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268) 1770 * 1771 * @param string $path A path. 1772 * @param string $suffix If the name component ends in suffix this will also be cut off. 1773 * 1774 * @return string 1775 */ 1431 1776 public static function mb_basename($path, $suffix = null) { 1432 1777 $splited = preg_split('#/#', rtrim($path, '/ ')); 1433 1778 return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1); -
src/wp-includes/ID3/getid3.php
1 1 <?php 2 2 ///////////////////////////////////////////////////////////////// 3 3 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 7 ///////////////////////////////////////////////////////////////// 4 // available at https://github.com/JamesHeinrich/getID3 // 5 // or https://www.getid3.org // 6 // or http://getid3.sourceforge.net // 8 7 // // 9 8 // Please see readme.txt for more information // 10 9 // /// … … 26 25 define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8)); 27 26 } 28 27 28 /* 29 https://www.getid3.org/phpBB3/viewtopic.php?t=2114 30 If you are running into a the problem where filenames with special characters are being handled 31 incorrectly by external helper programs (e.g. metaflac), notably with the special characters removed, 32 and you are passing in the filename in UTF8 (typically via a HTML form), try uncommenting this line: 33 */ 34 //setlocale(LC_CTYPE, 'en_US.UTF-8'); 35 29 36 // attempt to define temp dir as something flexible but reliable 30 37 $temp_dir = ini_get('upload_tmp_dir'); 31 38 if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) { … … 74 81 75 82 class getID3 76 83 { 77 / / public: Settings78 public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE79 public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'84 /* 85 * Settings 86 */ 80 87 81 // public: Optional tag checks - disable for speed. 82 public $option_tag_id3v1 = true; // Read and process ID3v1 tags 83 public $option_tag_id3v2 = true; // Read and process ID3v2 tags 84 public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags 85 public $option_tag_apetag = true; // Read and process APE tags 86 public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding 87 public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities 88 /** 89 * CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE 90 * 91 * @var string 92 */ 93 public $encoding = 'UTF-8'; 88 94 89 // public: Optional tag/comment calucations 90 public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc 95 /** 96 * Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252' 97 * 98 * @var string 99 */ 100 public $encoding_id3v1 = 'ISO-8859-1'; 91 101 92 // public: Optional handling of embedded attachments (e.g. images) 93 public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility 102 /* 103 * Optional tag checks - disable for speed. 104 */ 94 105 95 // public: Optional calculations 96 public $option_md5_data = false; // Get MD5 sum of data part - slow 97 public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG 98 public $option_sha1_data = false; // Get SHA1 sum of data part - slow 99 public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX) 106 /** 107 * Read and process ID3v1 tags 108 * 109 * @var bool 110 */ 111 public $option_tag_id3v1 = true; 100 112 101 // public: Read buffer size in bytes 113 /** 114 * Read and process ID3v2 tags 115 * 116 * @var bool 117 */ 118 public $option_tag_id3v2 = true; 119 120 /** 121 * Read and process Lyrics3 tags 122 * 123 * @var bool 124 */ 125 public $option_tag_lyrics3 = true; 126 127 /** 128 * Read and process APE tags 129 * 130 * @var bool 131 */ 132 public $option_tag_apetag = true; 133 134 /** 135 * Copy tags to root key 'tags' and encode to $this->encoding 136 * 137 * @var bool 138 */ 139 public $option_tags_process = true; 140 141 /** 142 * Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities 143 * 144 * @var bool 145 */ 146 public $option_tags_html = true; 147 148 /* 149 * Optional tag/comment calculations 150 */ 151 152 /** 153 * Calculate additional info such as bitrate, channelmode etc 154 * 155 * @var bool 156 */ 157 public $option_extra_info = true; 158 159 /* 160 * Optional handling of embedded attachments (e.g. images) 161 */ 162 163 /** 164 * Defaults to true (ATTACHMENTS_INLINE) for backward compatibility 165 * 166 * @var bool|string 167 */ 168 public $option_save_attachments = true; 169 170 /* 171 * Optional calculations 172 */ 173 174 /** 175 * Get MD5 sum of data part - slow 176 * 177 * @var bool 178 */ 179 public $option_md5_data = false; 180 181 /** 182 * Use MD5 of source file if availble - only FLAC and OptimFROG 183 * 184 * @var bool 185 */ 186 public $option_md5_data_source = false; 187 188 /** 189 * Get SHA1 sum of data part - slow 190 * 191 * @var bool 192 */ 193 public $option_sha1_data = false; 194 195 /** 196 * Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on 197 * PHP_INT_MAX) 198 * 199 * @var bool|null 200 */ 201 public $option_max_2gb_check; 202 203 /** 204 * Read buffer size in bytes 205 * 206 * @var int 207 */ 102 208 public $option_fread_buffer_size = 32768; 103 209 104 210 // Public variables 105 public $filename; // Filename of file being analysed. 106 public $fp; // Filepointer to file being analysed. 107 public $info; // Result array. 211 212 /** 213 * Filename of file being analysed. 214 * 215 * @var string 216 */ 217 public $filename; 218 219 /** 220 * Filepointer to file being analysed. 221 * 222 * @var resource 223 */ 224 public $fp; 225 226 /** 227 * Result array. 228 * 229 * @var array 230 */ 231 public $info; 232 233 /** 234 * @var string 235 */ 108 236 public $tempdir = GETID3_TEMP_DIR; 237 238 /** 239 * @var int 240 */ 109 241 public $memory_limit = 0; 110 242 111 // Protected variables 243 /** 244 * @var string 245 */ 112 246 protected $startup_error = ''; 247 248 /** 249 * @var string 250 */ 113 251 protected $startup_warning = ''; 114 252 115 const VERSION = '1.9.1 4-201706111222';253 const VERSION = '1.9.17-201907240906'; 116 254 const FREAD_BUFFER_SIZE = 32768; 117 255 118 256 const ATTACHMENTS_NONE = false; 119 257 const ATTACHMENTS_INLINE = true; 120 258 121 // public: constructor122 259 public function __construct() { 123 260 261 // Check for PHP version 262 $required_php_version = '5.3.0'; 263 if (version_compare(PHP_VERSION, $required_php_version, '<')) { 264 $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION."\n"; 265 return; 266 } 267 124 268 // Check memory 125 269 $this->memory_limit = ini_get('memory_limit'); 126 270 if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) { … … 176 320 177 321 // Needed for Windows only: 178 322 // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC 179 // as well as other helper functions such as head, tail, md5sum,etc323 // as well as other helper functions such as head, etc 180 324 // This path cannot contain spaces, but the below code will attempt to get the 181 325 // 8.3-equivalent path automatically 182 326 // IMPORTANT: This path must include the trailing slash … … 219 363 echo $this->startup_error; 220 364 throw new getid3_exception($this->startup_error); 221 365 } 222 223 return true;224 366 } 225 367 368 /** 369 * @return string 370 */ 226 371 public function version() { 227 372 return self::VERSION; 228 373 } 229 374 375 /** 376 * @return int 377 */ 230 378 public function fread_buffer_size() { 231 379 return $this->option_fread_buffer_size; 232 380 } 233 381 234 235 // public: setOption 382 /** 383 * @param array $optArray 384 * 385 * @return bool 386 */ 236 387 public function setOption($optArray) { 237 388 if (!is_array($optArray) || empty($optArray)) { 238 389 return false; … … 246 397 return true; 247 398 } 248 399 249 250 public function openfile($filename, $filesize=null) { 400 /** 401 * @param string $filename 402 * @param int $filesize 403 * 404 * @return bool 405 * 406 * @throws getid3_exception 407 */ 408 public function openfile($filename, $filesize=null, $fp=null) { 251 409 try { 252 410 if (!empty($this->startup_error)) { 253 411 throw new getid3_exception($this->startup_error); … … 270 428 } 271 429 272 430 $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); 273 $filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);431 //$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename); 274 432 275 433 // open local file 276 //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720 277 if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { 434 //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720 435 if (($fp != null) && ((get_resource_type($fp) == 'file') || (get_resource_type($fp) == 'stream'))) { 436 $this->fp = $fp; 437 } elseif ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { 278 438 // great 279 439 } else { 280 440 $errormessagelist = array(); … … 331 491 } elseif (getid3_lib::intValueSupported($real_filesize)) { 332 492 unset($this->info['filesize']); 333 493 fclose($this->fp); 334 throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize , 3).'GB, please report to info@getid3.org');494 throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize / 1073741824, 3).'GB, please report to info@getid3.org'); 335 495 } 336 496 $this->info['filesize'] = $real_filesize; 337 $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize , 3).'GB) and is not properly supported by PHP.');497 $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize / 1073741824, 3).'GB) and is not properly supported by PHP.'); 338 498 } 339 499 } 340 500 … … 346 506 return false; 347 507 } 348 508 349 // public: analyze file 350 public function analyze($filename, $filesize=null, $original_filename='') { 509 /** 510 * analyze file 511 * 512 * @param string $filename 513 * @param int $filesize 514 * @param string $original_filename 515 * 516 * @return array 517 */ 518 public function analyze($filename, $filesize=null, $original_filename='', $fp=null) { 351 519 try { 352 if (!$this->openfile($filename, $filesize )) {520 if (!$this->openfile($filename, $filesize, $fp)) { 353 521 return $this->info; 354 522 } 355 523 … … 383 551 $header = fread($this->fp, 10); 384 552 if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) { 385 553 $this->info['id3v2']['header'] = true; 386 $this->info['id3v2']['majorversion'] = ord($header {3});387 $this->info['id3v2']['minorversion'] = ord($header {4});554 $this->info['id3v2']['majorversion'] = ord($header[3]); 555 $this->info['id3v2']['minorversion'] = ord($header[4]); 388 556 $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length 389 557 } 390 558 } … … 497 665 } 498 666 499 667 500 // private: error handling 668 /** 669 * Error handling. 670 * 671 * @param string $message 672 * 673 * @return array 674 */ 501 675 public function error($message) { 502 676 $this->CleanUp(); 503 677 if (!isset($this->info['error'])) { … … 508 682 } 509 683 510 684 511 // private: warning handling 685 /** 686 * Warning handling. 687 * 688 * @param string $message 689 * 690 * @return bool 691 */ 512 692 public function warning($message) { 513 693 $this->info['warning'][] = $message; 514 694 return true; … … 515 695 } 516 696 517 697 518 // private: CleanUp 698 /** 699 * @return bool 700 */ 519 701 private function CleanUp() { 520 702 521 703 // remove possible empty keys … … 562 744 return true; 563 745 } 564 746 565 566 // return array containing information about all supported formats 747 /** 748 * Return array containing information about all supported formats. 749 * 750 * @return array 751 */ 567 752 public function GetFileFormatArray() { 568 753 static $format_info = array(); 569 754 if (empty($format_info)) { … … 584 769 'pattern' => '^ADIF', 585 770 'group' => 'audio', 586 771 'module' => 'aac', 587 'mime_type' => 'a pplication/octet-stream',772 'mime_type' => 'audio/aac', 588 773 'fail_ape' => 'WARNING', 589 774 ), 590 775 … … 602 787 'pattern' => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]', 603 788 'group' => 'audio', 604 789 'module' => 'aac', 605 'mime_type' => 'a pplication/octet-stream',790 'mime_type' => 'audio/aac', 606 791 'fail_ape' => 'WARNING', 607 792 ), 608 793 … … 649 834 650 835 // DSS - audio - Digital Speech Standard 651 836 'dss' => array( 652 'pattern' => '^[\\x02-\\x0 6]ds[s2]',837 'pattern' => '^[\\x02-\\x08]ds[s2]', 653 838 'group' => 'audio', 654 839 'module' => 'dss', 655 840 'mime_type' => 'application/octet-stream', … … 668 853 'pattern' => '^fLaC', 669 854 'group' => 'audio', 670 855 'module' => 'flac', 671 'mime_type' => 'audio/ x-flac',856 'mime_type' => 'audio/flac', 672 857 ), 673 858 674 859 // LA - audio - Lossless Audio (LA) … … 700 885 'pattern' => '^MAC ', 701 886 'group' => 'audio', 702 887 'module' => 'monkey', 703 'mime_type' => 'a pplication/octet-stream',888 'mime_type' => 'audio/x-monkeys-audio', 704 889 ), 705 890 706 891 // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available … … 889 1074 'pattern' => '^(RIFF|SDSS|FORM)', 890 1075 'group' => 'audio-video', 891 1076 'module' => 'riff', 892 'mime_type' => 'audio/ x-wav',1077 'mime_type' => 'audio/wav', 893 1078 'fail_ape' => 'WARNING', 894 1079 ), 895 1080 … … 1053 1238 'pattern' => '^\\x1F\\x8B\\x08', 1054 1239 'group' => 'archive', 1055 1240 'module' => 'gzip', 1056 'mime_type' => 'application/ x-gzip',1241 'mime_type' => 'application/gzip', 1057 1242 'fail_id3' => 'ERROR', 1058 1243 'fail_ape' => 'ERROR', 1059 1244 ), … … 1068 1253 'fail_ape' => 'ERROR', 1069 1254 ), 1070 1255 1256 // XZ - data - XZ compressed data 1257 'xz' => array( 1258 'pattern' => '^\\xFD7zXZ\\x00', 1259 'group' => 'archive', 1260 'module' => 'xz', 1261 'mime_type' => 'application/x-xz', 1262 'fail_id3' => 'ERROR', 1263 'fail_ape' => 'ERROR', 1264 ), 1071 1265 1266 1072 1267 // Misc other formats 1073 1268 1074 1269 // PAR2 - data - Parity Volume Set Specification 2.0 … … 1115 1310 return $format_info; 1116 1311 } 1117 1312 1118 1119 1313 /** 1314 * @param string $filedata 1315 * @param string $filename 1316 * 1317 * @return mixed|false 1318 */ 1120 1319 public function GetFileFormat(&$filedata, $filename='') { 1121 1320 // this function will determine the format of a file based on usually 1122 1321 // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG, … … 1135 1334 1136 1335 1137 1336 if (preg_match('#\\.mp[123a]$#i', $filename)) { 1138 // Too many mp3 encoders on the market put ga bage in front of mpeg files1337 // Too many mp3 encoders on the market put garbage in front of mpeg files 1139 1338 // use assume format on these if format detection failed 1140 1339 $GetFileFormatArray = $this->GetFileFormatArray(); 1141 1340 $info = $GetFileFormatArray['mp3']; … … 1154 1353 return false; 1155 1354 } 1156 1355 1157 1158 // converts array to $encoding charset from $this->encoding 1356 /** 1357 * Converts array to $encoding charset from $this->encoding. 1358 * 1359 * @param array $array 1360 * @param string $encoding 1361 */ 1159 1362 public function CharConvert(&$array, $encoding) { 1160 1363 1161 1364 // identical encoding - end here … … 1178 1381 } 1179 1382 } 1180 1383 1181 1384 /** 1385 * @return bool 1386 */ 1182 1387 public function HandleAllTags() { 1183 1388 1184 1389 // key name => array (tag name, character encoding) … … 1233 1438 } 1234 1439 } 1235 1440 if ($tag_key == 'picture') { 1441 // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere 1236 1442 unset($this->info[$comment_name]['comments'][$tag_key]); 1237 1443 } 1238 1444 } … … 1246 1452 1247 1453 if ($this->option_tags_html) { 1248 1454 foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { 1455 if ($tag_key == 'picture') { 1456 // Do not to try to convert binary picture data to HTML 1457 // https://github.com/JamesHeinrich/getID3/issues/178 1458 continue; 1459 } 1249 1460 $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']); 1250 1461 } 1251 1462 } … … 1254 1465 1255 1466 } 1256 1467 1257 // pictures can take up a lot of space, and we don't need multiple copies of them 1258 // let there be a single copy in [comments][picture], and not elsewhere 1468 // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere 1259 1469 if (!empty($this->info['tags'])) { 1260 1470 $unset_keys = array('tags', 'tags_html'); 1261 1471 foreach ($this->info['tags'] as $tagtype => $tagarray) { … … 1301 1511 return true; 1302 1512 } 1303 1513 1514 /** 1515 * @param string $algorithm 1516 * 1517 * @return array|bool 1518 */ 1304 1519 public function getHashdata($algorithm) { 1305 1520 switch ($algorithm) { 1306 1521 case 'md5': … … 1365 1580 1366 1581 } else { 1367 1582 1368 $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';1369 1583 $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; 1370 1584 $VorbisCommentError = `$commandline`; 1371 1585 … … 1424 1638 return true; 1425 1639 } 1426 1640 1427 1428 1641 public function ChannelsBitratePlaytimeCalculations() { 1429 1642 1430 1643 // set channelmode on audio … … 1489 1702 } 1490 1703 } 1491 1704 1492 1705 /** 1706 * @return bool 1707 */ 1493 1708 public function CalculateCompressionRatioVideo() { 1494 1709 if (empty($this->info['video'])) { 1495 1710 return false; … … 1537 1752 return true; 1538 1753 } 1539 1754 1540 1755 /** 1756 * @return bool 1757 */ 1541 1758 public function CalculateCompressionRatioAudio() { 1542 1759 if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) { 1543 1760 return false; … … 1554 1771 return true; 1555 1772 } 1556 1773 1557 1774 /** 1775 * @return bool 1776 */ 1558 1777 public function CalculateReplayGain() { 1559 1778 if (isset($this->info['replay_gain'])) { 1560 1779 if (!isset($this->info['replay_gain']['reference_volume'])) { 1561 $this->info['replay_gain']['reference_volume'] = (double)89.0;1780 $this->info['replay_gain']['reference_volume'] = 89.0; 1562 1781 } 1563 1782 if (isset($this->info['replay_gain']['track']['adjustment'])) { 1564 1783 $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; … … 1577 1796 return true; 1578 1797 } 1579 1798 1799 /** 1800 * @return bool 1801 */ 1580 1802 public function ProcessAudioStreams() { 1581 1803 if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) { 1582 1804 if (!isset($this->info['audio']['streams'])) { … … 1590 1812 return true; 1591 1813 } 1592 1814 1815 /** 1816 * @return string|bool 1817 */ 1593 1818 public function getid3_tempnam() { 1594 1819 return tempnam($this->tempdir, 'gI3'); 1595 1820 } 1596 1821 1822 /** 1823 * @param string $name 1824 * 1825 * @return bool 1826 * 1827 * @throws getid3_exception 1828 */ 1597 1829 public function include_module($name) { 1598 1830 //if (!file_exists($this->include_path.'module.'.$name.'.php')) { 1599 1831 if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) { … … 1603 1835 return true; 1604 1836 } 1605 1837 1606 public static function is_writable ($filename) { 1607 $ret = is_writable($filename); 1838 /** 1839 * @param string $filename 1840 * 1841 * @return bool 1842 */ 1843 public static function is_writable ($filename) { 1844 $ret = is_writable($filename); 1845 if (!$ret) { 1846 $perms = fileperms($filename); 1847 $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002); 1848 } 1849 return $ret; 1850 } 1608 1851 1609 if (!$ret) {1610 $perms = fileperms($filename);1611 $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);1612 }1613 1614 return $ret;1615 }1616 1617 1852 } 1618 1853 1619 1854 1620 abstract class getid3_handler { 1855 abstract class getid3_handler 1856 { 1621 1857 1622 1858 /** 1623 1859 * @var getID3 … … 1624 1860 */ 1625 1861 protected $getid3; // pointer 1626 1862 1627 protected $data_string_flag = false; // analyzing filepointer or string 1628 protected $data_string = ''; // string to analyze 1629 protected $data_string_position = 0; // seek position in string 1630 protected $data_string_length = 0; // string length 1863 /** 1864 * Analyzing filepointer or string. 1865 * 1866 * @var bool 1867 */ 1868 protected $data_string_flag = false; 1631 1869 1632 private $dependency_to = null; 1870 /** 1871 * String to analyze. 1872 * 1873 * @var string 1874 */ 1875 protected $data_string = ''; 1633 1876 1877 /** 1878 * Seek position in string. 1879 * 1880 * @var int 1881 */ 1882 protected $data_string_position = 0; 1634 1883 1884 /** 1885 * String length. 1886 * 1887 * @var int 1888 */ 1889 protected $data_string_length = 0; 1890 1891 /** 1892 * @var string 1893 */ 1894 private $dependency_to; 1895 1896 /** 1897 * getid3_handler constructor. 1898 * 1899 * @param getID3 $getid3 1900 * @param string $call_module 1901 */ 1635 1902 public function __construct(getID3 $getid3, $call_module=null) { 1636 1903 $this->getid3 = $getid3; 1637 1904 … … 1640 1907 } 1641 1908 } 1642 1909 1643 1644 // Analyze from file pointer 1910 /** 1911 * Analyze from file pointer. 1912 * 1913 * @return bool 1914 */ 1645 1915 abstract public function Analyze(); 1646 1916 1647 1648 // Analyze from string instead 1917 /** 1918 * Analyze from string instead. 1919 * 1920 * @param string $string 1921 */ 1649 1922 public function AnalyzeString($string) { 1650 1923 // Enter string mode 1651 1924 $this->setStringMode($string); … … 1671 1944 $this->data_string_flag = false; 1672 1945 } 1673 1946 1947 /** 1948 * @param string $string 1949 */ 1674 1950 public function setStringMode($string) { 1675 1951 $this->data_string_flag = true; 1676 1952 $this->data_string = $string; … … 1677 1953 $this->data_string_length = strlen($string); 1678 1954 } 1679 1955 1956 /** 1957 * @return int|bool 1958 */ 1680 1959 protected function ftell() { 1681 1960 if ($this->data_string_flag) { 1682 1961 return $this->data_string_position; … … 1684 1963 return ftell($this->getid3->fp); 1685 1964 } 1686 1965 1966 /** 1967 * @param int $bytes 1968 * 1969 * @return string|false 1970 * 1971 * @throws getid3_exception 1972 */ 1687 1973 protected function fread($bytes) { 1688 1974 if ($this->data_string_flag) { 1689 1975 $this->data_string_position += $bytes; … … 1696 1982 1697 1983 //return fread($this->getid3->fp, $bytes); 1698 1984 /* 1699 * http ://www.getid3.org/phpBB3/viewtopic.php?t=19301985 * https://www.getid3.org/phpBB3/viewtopic.php?t=1930 1700 1986 * "I found out that the root cause for the problem was how getID3 uses the PHP system function fread(). 1701 1987 * It seems to assume that fread() would always return as many bytes as were requested. 1702 1988 * However, according the PHP manual (http://php.net/manual/en/function.fread.php), this is the case only with regular local files, but not e.g. with Linux pipes. … … 1704 1990 */ 1705 1991 $contents = ''; 1706 1992 do { 1993 //if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) { 1994 if (($this->getid3->memory_limit > 0) && (($bytes / $this->getid3->memory_limit) > 0.99)) { // enable a more-fuzzy match to prevent close misses generating errors like "PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33554464 bytes)" 1995 throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10); 1996 } 1707 1997 $part = fread($this->getid3->fp, $bytes); 1708 1998 $partLength = strlen($part); 1709 1999 $bytes -= $partLength; … … 1712 2002 return $contents; 1713 2003 } 1714 2004 2005 /** 2006 * @param int $bytes 2007 * @param int $whence 2008 * 2009 * @return int 2010 * 2011 * @throws getid3_exception 2012 */ 1715 2013 protected function fseek($bytes, $whence=SEEK_SET) { 1716 2014 if ($this->data_string_flag) { 1717 2015 switch ($whence) { … … 1742 2040 return fseek($this->getid3->fp, $bytes, $whence); 1743 2041 } 1744 2042 2043 /** 2044 * @return bool 2045 */ 1745 2046 protected function feof() { 1746 2047 if ($this->data_string_flag) { 1747 2048 return $this->data_string_position >= $this->data_string_length; … … 1749 2050 return feof($this->getid3->fp); 1750 2051 } 1751 2052 2053 /** 2054 * @param string $module 2055 * 2056 * @return bool 2057 */ 1752 2058 final protected function isDependencyFor($module) { 1753 2059 return $this->dependency_to == $module; 1754 2060 } 1755 2061 2062 /** 2063 * @param string $text 2064 * 2065 * @return bool 2066 */ 1756 2067 protected function error($text) { 1757 2068 $this->getid3->info['error'][] = $text; 1758 2069 … … 1759 2070 return false; 1760 2071 } 1761 2072 2073 /** 2074 * @param string $text 2075 * 2076 * @return bool 2077 */ 1762 2078 protected function warning($text) { 1763 2079 return $this->getid3->warning($text); 1764 2080 } 1765 2081 2082 /** 2083 * @param string $text 2084 */ 1766 2085 protected function notice($text) { 1767 2086 // does nothing for now 1768 2087 } 1769 2088 2089 /** 2090 * @param string $name 2091 * @param int $offset 2092 * @param int $length 2093 * @param string $image_mime 2094 * 2095 * @return string|null 2096 * 2097 * @throws Exception 2098 * @throws getid3_exception 2099 */ 1770 2100 public function saveAttachment($name, $offset, $length, $image_mime=null) { 1771 2101 try { 1772 2102 … … 1820 2150 // close and remove dest file if created 1821 2151 if (isset($fp_dest) && is_resource($fp_dest)) { 1822 2152 fclose($fp_dest); 2153 } 2154 2155 if (isset($dest) && file_exists($dest)) { 1823 2156 unlink($dest); 1824 2157 } 1825 2158 -
src/wp-includes/ID3/license.txt
1 1 ///////////////////////////////////////////////////////////////// 2 2 /// getID3() by James Heinrich <info@getid3.org> // 3 3 // available at http://getid3.sourceforge.net // 4 // or http ://www.getid3.org//4 // or https://www.getid3.org // 5 5 // also https://github.com/JamesHeinrich/getID3 // 6 6 ///////////////////////////////////////////////////////////////// 7 7 … … 18 18 19 19 GNU LGPL: https://gnu.org/licenses/lgpl.html (v3) 20 20 21 Mozilla MPL: http ://www.mozilla.org/MPL/2.0/(v2)21 Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2) 22 22 23 getID3 Commercial License: http ://getid3.org/#gCL (payment required)23 getID3 Commercial License: https://www.getid3.org/#gCL (payment required) 24 24 25 25 ***************************************************************** 26 26 ***************************************************************** -
src/wp-includes/ID3/module.audio-video.asf.php
1 1 <?php 2 2 ///////////////////////////////////////////////////////////////// 3 3 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 4 // available at https://github.com/JamesHeinrich/getID3 // 5 // or https://www.getid3.org // 6 // or http://getid3.sourceforge.net // 7 // see readme.txt for more details // 7 8 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 9 // // 11 10 // module.audio-video.asf.php // 12 11 // module for analyzing ASF, WMA and WMV files // … … 16 15 17 16 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); 18 17 19 class getid3_asf extends getid3_handler { 20 18 class getid3_asf extends getid3_handler 19 { 20 /** 21 * @param getID3 $getid3 22 */ 21 23 public function __construct(getID3 $getid3) { 22 24 parent::__construct($getid3); // extends getid3_handler::__construct() 23 25 … … 30 32 } 31 33 } 32 34 35 /** 36 * @return bool 37 */ 33 38 public function Analyze() { 34 39 $info = &$this->getid3->info; 35 40 … … 83 88 $NextObjectOffset = $this->ftell(); 84 89 $ASFHeaderData = $this->fread($thisfile_asf_headerobject['objectsize'] - 30); 85 90 $offset = 0; 91 $thisfile_asf_streambitratepropertiesobject = array(); 92 $thisfile_asf_codeclistobject = array(); 86 93 87 94 for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) { 88 95 $NextObjectGUID = substr($ASFHeaderData, $offset, 16); … … 790 797 case 'wm/tracknumber': 791 798 case 'tracknumber': 792 799 // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character) 793 $thisfile_asf_comments['track '] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));794 foreach ($thisfile_asf_comments['track '] as $key => $value) {800 $thisfile_asf_comments['track_number'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 801 foreach ($thisfile_asf_comments['track_number'] as $key => $value) { 795 802 if (preg_match('/^[0-9\x00]+$/', $value)) { 796 $thisfile_asf_comments['track '][$key] = intval(str_replace("\x00", '', $value));803 $thisfile_asf_comments['track_number'][$key] = intval(str_replace("\x00", '', $value)); 797 804 } 798 805 } 799 806 break; 800 807 801 808 case 'wm/track': 802 if (empty($thisfile_asf_comments['track '])) {803 $thisfile_asf_comments['track '] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));809 if (empty($thisfile_asf_comments['track_number'])) { 810 $thisfile_asf_comments['track_number'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); 804 811 } 805 812 break; 806 813 … … 970 977 break; 971 978 } 972 979 } 973 if (isset($thisfile_asf_streambitrateproperties ['bitrate_records_count'])) {980 if (isset($thisfile_asf_streambitratepropertiesobject['bitrate_records_count'])) { 974 981 $ASFbitrateAudio = 0; 975 982 $ASFbitrateVideo = 0; 976 for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties ['bitrate_records_count']; $BitrateRecordsCounter++) {983 for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { 977 984 if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { 978 985 switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { 979 986 case 1: 980 $ASFbitrateVideo += $thisfile_asf_streambitrateproperties ['bitrate_records'][$BitrateRecordsCounter]['bitrate'];987 $ASFbitrateVideo += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate']; 981 988 break; 982 989 983 990 case 2: 984 $ASFbitrateAudio += $thisfile_asf_streambitrateproperties ['bitrate_records'][$BitrateRecordsCounter]['bitrate'];991 $ASFbitrateAudio += $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate']; 985 992 break; 986 993 987 994 default: … … 1440 1447 return true; 1441 1448 } 1442 1449 1450 /** 1451 * @param int $CodecListType 1452 * 1453 * @return string 1454 */ 1443 1455 public static function codecListObjectTypeLookup($CodecListType) { 1444 1456 static $lookup = array( 1445 1457 0x0001 => 'Video Codec', … … 1450 1462 return (isset($lookup[$CodecListType]) ? $lookup[$CodecListType] : 'Invalid Codec Type'); 1451 1463 } 1452 1464 1465 /** 1466 * @return array 1467 */ 1453 1468 public static function KnownGUIDs() { 1454 1469 static $GUIDarray = array( 1455 1470 'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A', … … 1564 1579 return $GUIDarray; 1565 1580 } 1566 1581 1582 /** 1583 * @param string $GUIDstring 1584 * 1585 * @return string|false 1586 */ 1567 1587 public static function GUIDname($GUIDstring) { 1568 1588 static $GUIDarray = array(); 1569 1589 if (empty($GUIDarray)) { … … 1572 1592 return array_search($GUIDstring, $GUIDarray); 1573 1593 } 1574 1594 1595 /** 1596 * @param int $id 1597 * 1598 * @return string 1599 */ 1575 1600 public static function ASFIndexObjectIndexTypeLookup($id) { 1576 1601 static $ASFIndexObjectIndexTypeLookup = array(); 1577 1602 if (empty($ASFIndexObjectIndexTypeLookup)) { … … 1582 1607 return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid'); 1583 1608 } 1584 1609 1610 /** 1611 * @param string $GUIDstring 1612 * 1613 * @return string 1614 */ 1585 1615 public static function GUIDtoBytestring($GUIDstring) { 1586 1616 // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way: 1587 1617 // first 4 bytes are in little-endian order … … 1617 1647 return $hexbytecharstring; 1618 1648 } 1619 1649 1650 /** 1651 * @param string $Bytestring 1652 * 1653 * @return string 1654 */ 1620 1655 public static function BytestringToGUID($Bytestring) { 1621 $GUIDstring = str_pad(dechex(ord($Bytestring {3})), 2, '0', STR_PAD_LEFT);1622 $GUIDstring .= str_pad(dechex(ord($Bytestring {2})), 2, '0', STR_PAD_LEFT);1623 $GUIDstring .= str_pad(dechex(ord($Bytestring {1})), 2, '0', STR_PAD_LEFT);1624 $GUIDstring .= str_pad(dechex(ord($Bytestring {0})), 2, '0', STR_PAD_LEFT);1656 $GUIDstring = str_pad(dechex(ord($Bytestring[3])), 2, '0', STR_PAD_LEFT); 1657 $GUIDstring .= str_pad(dechex(ord($Bytestring[2])), 2, '0', STR_PAD_LEFT); 1658 $GUIDstring .= str_pad(dechex(ord($Bytestring[1])), 2, '0', STR_PAD_LEFT); 1659 $GUIDstring .= str_pad(dechex(ord($Bytestring[0])), 2, '0', STR_PAD_LEFT); 1625 1660 $GUIDstring .= '-'; 1626 $GUIDstring .= str_pad(dechex(ord($Bytestring {5})), 2, '0', STR_PAD_LEFT);1627 $GUIDstring .= str_pad(dechex(ord($Bytestring {4})), 2, '0', STR_PAD_LEFT);1661 $GUIDstring .= str_pad(dechex(ord($Bytestring[5])), 2, '0', STR_PAD_LEFT); 1662 $GUIDstring .= str_pad(dechex(ord($Bytestring[4])), 2, '0', STR_PAD_LEFT); 1628 1663 $GUIDstring .= '-'; 1629 $GUIDstring .= str_pad(dechex(ord($Bytestring {7})), 2, '0', STR_PAD_LEFT);1630 $GUIDstring .= str_pad(dechex(ord($Bytestring {6})), 2, '0', STR_PAD_LEFT);1664 $GUIDstring .= str_pad(dechex(ord($Bytestring[7])), 2, '0', STR_PAD_LEFT); 1665 $GUIDstring .= str_pad(dechex(ord($Bytestring[6])), 2, '0', STR_PAD_LEFT); 1631 1666 $GUIDstring .= '-'; 1632 $GUIDstring .= str_pad(dechex(ord($Bytestring {8})), 2, '0', STR_PAD_LEFT);1633 $GUIDstring .= str_pad(dechex(ord($Bytestring {9})), 2, '0', STR_PAD_LEFT);1667 $GUIDstring .= str_pad(dechex(ord($Bytestring[8])), 2, '0', STR_PAD_LEFT); 1668 $GUIDstring .= str_pad(dechex(ord($Bytestring[9])), 2, '0', STR_PAD_LEFT); 1634 1669 $GUIDstring .= '-'; 1635 $GUIDstring .= str_pad(dechex(ord($Bytestring {10})), 2, '0', STR_PAD_LEFT);1636 $GUIDstring .= str_pad(dechex(ord($Bytestring {11})), 2, '0', STR_PAD_LEFT);1637 $GUIDstring .= str_pad(dechex(ord($Bytestring {12})), 2, '0', STR_PAD_LEFT);1638 $GUIDstring .= str_pad(dechex(ord($Bytestring {13})), 2, '0', STR_PAD_LEFT);1639 $GUIDstring .= str_pad(dechex(ord($Bytestring {14})), 2, '0', STR_PAD_LEFT);1640 $GUIDstring .= str_pad(dechex(ord($Bytestring {15})), 2, '0', STR_PAD_LEFT);1670 $GUIDstring .= str_pad(dechex(ord($Bytestring[10])), 2, '0', STR_PAD_LEFT); 1671 $GUIDstring .= str_pad(dechex(ord($Bytestring[11])), 2, '0', STR_PAD_LEFT); 1672 $GUIDstring .= str_pad(dechex(ord($Bytestring[12])), 2, '0', STR_PAD_LEFT); 1673 $GUIDstring .= str_pad(dechex(ord($Bytestring[13])), 2, '0', STR_PAD_LEFT); 1674 $GUIDstring .= str_pad(dechex(ord($Bytestring[14])), 2, '0', STR_PAD_LEFT); 1675 $GUIDstring .= str_pad(dechex(ord($Bytestring[15])), 2, '0', STR_PAD_LEFT); 1641 1676 1642 1677 return strtoupper($GUIDstring); 1643 1678 } 1644 1679 1680 /** 1681 * @param int $FILETIME 1682 * @param bool $round 1683 * 1684 * @return float|int 1685 */ 1645 1686 public static function FILETIMEtoUNIXtime($FILETIME, $round=true) { 1646 1687 // FILETIME is a 64-bit unsigned integer representing 1647 1688 // the number of 100-nanosecond intervals since January 1, 1601 … … 1653 1694 return ($FILETIME - 116444736000000000) / 10000000; 1654 1695 } 1655 1696 1697 /** 1698 * @param int $WMpictureType 1699 * 1700 * @return string 1701 */ 1656 1702 public static function WMpictureTypeLookup($WMpictureType) { 1657 1703 static $lookup = null; 1658 1704 if ($lookup === null) { … … 1684 1730 return (isset($lookup[$WMpictureType]) ? $lookup[$WMpictureType] : ''); 1685 1731 } 1686 1732 1733 /** 1734 * @param string $asf_header_extension_object_data 1735 * @param int $unhandled_sections 1736 * 1737 * @return array 1738 */ 1687 1739 public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) { 1688 1740 // http://msdn.microsoft.com/en-us/library/bb643323.aspx 1689 1741 … … 1930 1982 return $HeaderExtensionObjectParsed; 1931 1983 } 1932 1984 1933 1985 /** 1986 * @param int $id 1987 * 1988 * @return string 1989 */ 1934 1990 public static function metadataLibraryObjectDataTypeLookup($id) { 1935 1991 static $lookup = array( 1936 1992 0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters … … 1944 2000 return (isset($lookup[$id]) ? $lookup[$id] : 'invalid'); 1945 2001 } 1946 2002 2003 /** 2004 * @param string $data 2005 * 2006 * @return array 2007 */ 1947 2008 public function ASF_WMpicture(&$data) { 1948 2009 //typedef struct _WMPicture{ 1949 2010 // LPWSTR pwszMIMEType; … … 1994 2055 return $WMpicture; 1995 2056 } 1996 2057 1997 1998 // Remove terminator 00 00 and convert UTF-16LE to Latin-1 2058 /** 2059 * Remove terminator 00 00 and convert UTF-16LE to Latin-1. 2060 * 2061 * @param string $string 2062 * 2063 * @return string 2064 */ 1999 2065 public static function TrimConvert($string) { 2000 2066 return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' '); 2001 2067 } 2002 2068 2003 2004 // Remove terminator 00 00 2069 /** 2070 * Remove terminator 00 00. 2071 * 2072 * @param string $string 2073 * 2074 * @return string 2075 */ 2005 2076 public static function TrimTerm($string) { 2006 2077 // remove terminator, only if present (it should be, but...) 2007 2078 if (substr($string, -2) === "\x00\x00") { -
src/wp-includes/ID3/module.audio-video.flv.php
1 1 <?php 2 2 ///////////////////////////////////////////////////////////////// 3 3 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 4 // available at https://github.com/JamesHeinrich/getID3 // 5 // or https://www.getid3.org // 6 // or http://getid3.sourceforge.net // 7 // see readme.txt for more details // 8 ///////////////////////////////////////////////////////////////// 7 9 // // 10 // module.audio-video.flv.php // 11 // module for analyzing Shockwave Flash Video files // 12 // dependencies: NONE // 13 // // 14 ///////////////////////////////////////////////////////////////// 15 // // 8 16 // FLV module by Seth Kaufman <sethØwhirl-i-gig*com> // 9 17 // // 10 18 // * version 0.1 (26 June 2005) // 11 19 // // 12 // //13 20 // * version 0.1.1 (15 July 2005) // 14 21 // minor modifications by James Heinrich <info@getid3.org> // 15 22 // // … … 43 50 // handle GETID3_FLV_VIDEO_VP6FLV_ALPHA // 44 51 // improved AVCSequenceParameterSetReader::readData() // 45 52 // by Xander Schouwerwou <schouwerwouØgmail*com> // 46 // //47 /////////////////////////////////////////////////////////////////48 // //49 // module.audio-video.flv.php //50 // module for analyzing Shockwave Flash Video files //51 // dependencies: NONE //52 53 // /// 53 54 ///////////////////////////////////////////////////////////////// 54 55 … … 73 74 define('H264_PROFILE_HIGH444', 144); 74 75 define('H264_PROFILE_HIGH444_PREDICTIVE', 244); 75 76 76 class getid3_flv extends getid3_handler {77 77 class getid3_flv extends getid3_handler 78 { 78 79 const magic = 'FLV'; 79 80 80 public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration 81 /** 82 * Break out of the loop if too many frames have been scanned; only scan this 83 * many if meta frame does not contain useful duration. 84 * 85 * @var int 86 */ 87 public $max_frames = 100000; 81 88 89 /** 90 * @return bool 91 */ 82 92 public function Analyze() { 83 93 $info = &$this->getid3->info; 84 94 … … 332 342 return true; 333 343 } 334 344 335 345 /** 346 * @param int $id 347 * 348 * @return string|false 349 */ 336 350 public static function audioFormatLookup($id) { 337 351 static $lookup = array( 338 352 0 => 'Linear PCM, platform endian', … … 355 369 return (isset($lookup[$id]) ? $lookup[$id] : false); 356 370 } 357 371 372 /** 373 * @param int $id 374 * 375 * @return int|false 376 */ 358 377 public static function audioRateLookup($id) { 359 378 static $lookup = array( 360 379 0 => 5500, … … 365 384 return (isset($lookup[$id]) ? $lookup[$id] : false); 366 385 } 367 386 387 /** 388 * @param int $id 389 * 390 * @return int|false 391 */ 368 392 public static function audioBitDepthLookup($id) { 369 393 static $lookup = array( 370 394 0 => 8, … … 373 397 return (isset($lookup[$id]) ? $lookup[$id] : false); 374 398 } 375 399 400 /** 401 * @param int $id 402 * 403 * @return string|false 404 */ 376 405 public static function videoCodecLookup($id) { 377 406 static $lookup = array( 378 407 GETID3_FLV_VIDEO_H263 => 'Sorenson H.263', … … 386 415 } 387 416 } 388 417 389 class AMFStream { 418 class AMFStream 419 { 420 /** 421 * @var string 422 */ 390 423 public $bytes; 424 425 /** 426 * @var int 427 */ 391 428 public $pos; 392 429 430 /** 431 * @param string $bytes 432 */ 393 433 public function __construct(&$bytes) { 394 434 $this->bytes =& $bytes; 395 435 $this->pos = 0; 396 436 } 397 437 398 public function readByte() { 399 return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1)); 438 /** 439 * @return int 440 */ 441 public function readByte() { // 8-bit 442 return ord(substr($this->bytes, $this->pos++, 1)); 400 443 } 401 444 402 public function readInt() { 445 /** 446 * @return int 447 */ 448 public function readInt() { // 16-bit 403 449 return ($this->readByte() << 8) + $this->readByte(); 404 450 } 405 451 406 public function readLong() { 452 /** 453 * @return int 454 */ 455 public function readLong() { // 32-bit 407 456 return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte(); 408 457 } 409 458 459 /** 460 * @return float|false 461 */ 410 462 public function readDouble() { 411 463 return getid3_lib::BigEndian2Float($this->read(8)); 412 464 } 413 465 466 /** 467 * @return string 468 */ 414 469 public function readUTF() { 415 470 $length = $this->readInt(); 416 471 return $this->read($length); 417 472 } 418 473 474 /** 475 * @return string 476 */ 419 477 public function readLongUTF() { 420 478 $length = $this->readLong(); 421 479 return $this->read($length); 422 480 } 423 481 482 /** 483 * @param int $length 484 * 485 * @return string 486 */ 424 487 public function read($length) { 425 488 $val = substr($this->bytes, $this->pos, $length); 426 489 $this->pos += $length; … … 427 490 return $val; 428 491 } 429 492 493 /** 494 * @return int 495 */ 430 496 public function peekByte() { 431 497 $pos = $this->pos; 432 498 $val = $this->readByte(); … … 434 500 return $val; 435 501 } 436 502 503 /** 504 * @return int 505 */ 437 506 public function peekInt() { 438 507 $pos = $this->pos; 439 508 $val = $this->readInt(); … … 441 510 return $val; 442 511 } 443 512 513 /** 514 * @return int 515 */ 444 516 public function peekLong() { 445 517 $pos = $this->pos; 446 518 $val = $this->readLong(); … … 448 520 return $val; 449 521 } 450 522 523 /** 524 * @return float|false 525 */ 451 526 public function peekDouble() { 452 527 $pos = $this->pos; 453 528 $val = $this->readDouble(); … … 455 530 return $val; 456 531 } 457 532 533 /** 534 * @return string 535 */ 458 536 public function peekUTF() { 459 537 $pos = $this->pos; 460 538 $val = $this->readUTF(); … … 462 540 return $val; 463 541 } 464 542 543 /** 544 * @return string 545 */ 465 546 public function peekLongUTF() { 466 547 $pos = $this->pos; 467 548 $val = $this->readLongUTF(); … … 470 551 } 471 552 } 472 553 473 class AMFReader { 554 class AMFReader 555 { 556 /** 557 * @var AMFStream 558 */ 474 559 public $stream; 475 560 476 public function __construct(&$stream) { 477 $this->stream =& $stream; 561 /** 562 * @param AMFStream $stream 563 */ 564 public function __construct(AMFStream $stream) { 565 $this->stream = $stream; 478 566 } 479 567 568 /** 569 * @return mixed 570 */ 480 571 public function readData() { 481 572 $value = null; 482 573 … … 547 638 return $value; 548 639 } 549 640 641 /** 642 * @return float|false 643 */ 550 644 public function readDouble() { 551 645 return $this->stream->readDouble(); 552 646 } 553 647 648 /** 649 * @return bool 650 */ 554 651 public function readBoolean() { 555 652 return $this->stream->readByte() == 1; 556 653 } 557 654 655 /** 656 * @return string 657 */ 558 658 public function readString() { 559 659 return $this->stream->readUTF(); 560 660 } 561 661 662 /** 663 * @return array 664 */ 562 665 public function readObject() { 563 666 // Get highest numerical index - ignored 564 667 // $highestIndex = $this->stream->readLong(); 565 668 566 669 $data = array(); 670 $key = null; 567 671 568 672 while ($key = $this->stream->readUTF()) { 569 673 $data[$key] = $this->readData(); … … 576 680 return $data; 577 681 } 578 682 683 /** 684 * @return array 685 */ 579 686 public function readMixedArray() { 580 687 // Get highest numerical index - ignored 581 688 $highestIndex = $this->stream->readLong(); 582 689 583 690 $data = array(); 691 $key = null; 584 692 585 693 while ($key = $this->stream->readUTF()) { 586 694 if (is_numeric($key)) { 587 $key = ( float) $key;695 $key = (int) $key; 588 696 } 589 697 $data[$key] = $this->readData(); 590 698 } … … 597 705 return $data; 598 706 } 599 707 708 /** 709 * @return array 710 */ 600 711 public function readArray() { 601 712 $length = $this->stream->readLong(); 602 713 $data = array(); … … 607 718 return $data; 608 719 } 609 720 721 /** 722 * @return float|false 723 */ 610 724 public function readDate() { 611 725 $timestamp = $this->stream->readDouble(); 612 726 $timezone = $this->stream->readInt(); … … 613 727 return $timestamp; 614 728 } 615 729 730 /** 731 * @return string 732 */ 616 733 public function readLongString() { 617 734 return $this->stream->readLongUTF(); 618 735 } 619 736 737 /** 738 * @return string 739 */ 620 740 public function readXML() { 621 741 return $this->stream->readLongUTF(); 622 742 } 623 743 744 /** 745 * @return array 746 */ 624 747 public function readTypedObject() { 625 748 $className = $this->stream->readUTF(); 626 749 return $this->readObject(); … … 627 750 } 628 751 } 629 752 630 class AVCSequenceParameterSetReader { 753 class AVCSequenceParameterSetReader 754 { 755 /** 756 * @var string 757 */ 631 758 public $sps; 632 759 public $start = 0; 633 760 public $currentBytes = 0; 634 761 public $currentBits = 0; 762 763 /** 764 * @var int 765 */ 635 766 public $width; 767 768 /** 769 * @var int 770 */ 636 771 public $height; 637 772 773 /** 774 * @param string $sps 775 */ 638 776 public function __construct($sps) { 639 777 $this->sps = $sps; 640 778 } … … 691 829 } 692 830 } 693 831 832 /** 833 * @param int $bits 834 */ 694 835 public function skipBits($bits) { 695 836 $newBits = $this->currentBits + $bits; 696 837 $this->currentBytes += (int)floor($newBits / 8); … … 697 838 $this->currentBits = $newBits % 8; 698 839 } 699 840 841 /** 842 * @return int 843 */ 700 844 public function getBit() { 701 845 $result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01; 702 846 $this->skipBits(1); … … 703 847 return $result; 704 848 } 705 849 850 /** 851 * @param int $bits 852 * 853 * @return int 854 */ 706 855 public function getBits($bits) { 707 856 $result = 0; 708 857 for ($i = 0; $i < $bits; $i++) { … … 711 860 return $result; 712 861 } 713 862 863 /** 864 * @return int 865 */ 714 866 public function expGolombUe() { 715 867 $significantBits = 0; 716 868 $bit = $this->getBit(); … … 726 878 return (1 << $significantBits) + $this->getBits($significantBits) - 1; 727 879 } 728 880 881 /** 882 * @return int 883 */ 729 884 public function expGolombSe() { 730 885 $result = $this->expGolombUe(); 731 886 if (($result & 0x01) == 0) { … … 735 890 } 736 891 } 737 892 893 /** 894 * @return int 895 */ 738 896 public function getWidth() { 739 897 return $this->width; 740 898 } 741 899 900 /** 901 * @return int 902 */ 742 903 public function getHeight() { 743 904 return $this->height; 744 905 } -
src/wp-includes/ID3/module.audio-video.matroska.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio-video.matriska.php // 12 12 // module for analyzing Matroska containers // … … 72 72 define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file. 73 73 define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible. 74 74 define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values: 75 define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the thedata was encrypted with.75 define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the data was encrypted with. 76 76 define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents. 77 77 define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with. 78 78 define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values: … … 215 215 */ 216 216 class getid3_matroska extends getid3_handler 217 217 { 218 // public options 219 public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE] 220 public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE] 218 /** 219 * If true, do not return information about CLUSTER chunks, since there's a lot of them 220 * and they're not usually useful [default: TRUE]. 221 * 222 * @var bool 223 */ 224 public static $hide_clusters = true; 221 225 222 // private parser settings/placeholders 226 /** 227 * True to parse the whole file, not only header [default: FALSE]. 228 * 229 * @var bool 230 */ 231 public static $parse_whole_file = false; 232 233 /* 234 * Private parser settings/placeholders. 235 */ 223 236 private $EBMLbuffer = ''; 224 237 private $EBMLbuffer_offset = 0; 225 238 private $EBMLbuffer_length = 0; … … 226 239 private $current_offset = 0; 227 240 private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID); 228 241 242 /** 243 * @return bool 244 */ 229 245 public function Analyze() 230 246 { 231 247 $info = &$this->getid3->info; … … 366 382 if (!empty($getid3_temp->info[$header_data_key])) { 367 383 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key]; 368 384 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { 369 foreach ($getid3_temp->info['audio'] as $ key => $value) {370 $track_info[$ key] = $value;385 foreach ($getid3_temp->info['audio'] as $sub_key => $value) { 386 $track_info[$sub_key] = $value; 371 387 } 372 388 } 373 389 } … … 421 437 if (!empty($getid3_temp->info['ogg'])) { 422 438 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg']; 423 439 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { 424 foreach ($getid3_temp->info['audio'] as $ key => $value) {425 $track_info[$ key] = $value;440 foreach ($getid3_temp->info['audio'] as $sub_key => $value) { 441 $track_info[$sub_key] = $value; 426 442 } 427 443 } 428 444 } … … 449 465 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); 450 466 451 467 $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']); 452 foreach ($parsed as $ key => $value) {453 if ($ key != 'raw') {454 $track_info[$ key] = $value;468 foreach ($parsed as $sub_key => $value) { 469 if ($sub_key != 'raw') { 470 $track_info[$sub_key] = $value; 455 471 } 456 472 } 457 473 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed; … … 496 512 return true; 497 513 } 498 514 515 /** 516 * @param array $info 517 */ 499 518 private function parseEBML(&$info) { 500 519 // http://www.matroska.org/technical/specs/index.html#EBMLBasics 501 520 $this->current_offset = $info['avdataoffset']; … … 1228 1247 } 1229 1248 } 1230 1249 1250 /** 1251 * @param int $min_data 1252 * 1253 * @return bool 1254 */ 1231 1255 private function EnsureBufferHasEnoughData($min_data=1024) { 1232 1256 if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) { 1233 1257 $read_bytes = max($min_data, $this->getid3->fread_buffer_size()); … … 1249 1273 return true; 1250 1274 } 1251 1275 1276 /** 1277 * @return int|float|false 1278 */ 1252 1279 private function readEBMLint() { 1253 1280 $actual_offset = $this->current_offset - $this->EBMLbuffer_offset; 1254 1281 … … 1281 1308 return $int_value; 1282 1309 } 1283 1310 1311 /** 1312 * @param int $length 1313 * @param bool $check_buffer 1314 * 1315 * @return string|false 1316 */ 1284 1317 private function readEBMLelementData($length, $check_buffer=false) { 1285 1318 if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) { 1286 1319 return false; … … 1290 1323 return $data; 1291 1324 } 1292 1325 1326 /** 1327 * @param array $element 1328 * @param int $parent_end 1329 * @param array|bool $get_data 1330 * 1331 * @return bool 1332 */ 1293 1333 private function getEBMLelement(&$element, $parent_end, $get_data=false) { 1294 1334 if ($this->current_offset >= $parent_end) { 1295 1335 return false; … … 1326 1366 return true; 1327 1367 } 1328 1368 1369 /** 1370 * @param string $type 1371 * @param int $line 1372 * @param array $element 1373 */ 1329 1374 private function unhandledElement($type, $line, $element) { 1330 1375 // warn only about unknown and missed elements, not about unuseful 1331 1376 if (!in_array($element['id'], $this->unuseful_elements)) { … … 1338 1383 } 1339 1384 } 1340 1385 1386 /** 1387 * @param array $SimpleTagArray 1388 * 1389 * @return bool 1390 */ 1341 1391 private function ExtractCommentsSimpleTag($SimpleTagArray) { 1342 1392 if (!empty($SimpleTagArray['SimpleTag'])) { 1343 1393 foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) { … … 1353 1403 return true; 1354 1404 } 1355 1405 1406 /** 1407 * @param int $parent_end 1408 * 1409 * @return array 1410 */ 1356 1411 private function HandleEMBLSimpleTag($parent_end) { 1357 1412 $simpletag_entry = array(); 1358 1413 … … 1383 1438 return $simpletag_entry; 1384 1439 } 1385 1440 1441 /** 1442 * @param array $element 1443 * @param int $block_type 1444 * @param array $info 1445 * 1446 * @return array 1447 */ 1386 1448 private function HandleEMBLClusterBlock($element, $block_type, &$info) { 1387 1449 // http://www.matroska.org/technical/specs/index.html#block_structure 1388 1450 // http://www.matroska.org/technical/specs/index.html#simpleblock_structure … … 1446 1508 return $block_data; 1447 1509 } 1448 1510 1511 /** 1512 * @param string $EBMLstring 1513 * 1514 * @return int|float|false 1515 */ 1449 1516 private static function EBML2Int($EBMLstring) { 1450 1517 // http://matroska.org/specs/ 1451 1518 … … 1488 1555 return getid3_lib::BigEndian2Int($EBMLstring); 1489 1556 } 1490 1557 1558 /** 1559 * @param int $EBMLdatestamp 1560 * 1561 * @return float 1562 */ 1491 1563 private static function EBMLdate2unix($EBMLdatestamp) { 1492 1564 // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC) 1493 1565 // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC … … 1494 1566 return round(($EBMLdatestamp / 1000000000) + 978307200); 1495 1567 } 1496 1568 1569 /** 1570 * @param int $target_type 1571 * 1572 * @return string|int 1573 */ 1497 1574 public static function TargetTypeValue($target_type) { 1498 1575 // http://www.matroska.org/technical/specs/tagging/index.html 1499 1576 static $TargetTypeValue = array(); … … 1509 1586 return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type); 1510 1587 } 1511 1588 1589 /** 1590 * @param int $lacingtype 1591 * 1592 * @return string|int 1593 */ 1512 1594 public static function BlockLacingType($lacingtype) { 1513 1595 // http://matroska.org/technical/specs/index.html#block_structure 1514 1596 static $BlockLacingType = array(); … … 1521 1603 return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype); 1522 1604 } 1523 1605 1606 /** 1607 * @param string $codecid 1608 * 1609 * @return string 1610 */ 1524 1611 public static function CodecIDtoCommonName($codecid) { 1525 1612 // http://www.matroska.org/technical/specs/codecid/index.html 1526 1613 static $CodecIDlist = array(); … … 1557 1644 return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid); 1558 1645 } 1559 1646 1647 /** 1648 * @param int $value 1649 * 1650 * @return string 1651 */ 1560 1652 private static function EBMLidName($value) { 1561 1653 static $EBMLidList = array(); 1562 1654 if (empty($EBMLidList)) { … … 1755 1847 return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value)); 1756 1848 } 1757 1849 1850 /** 1851 * @param int $value 1852 * 1853 * @return string 1854 */ 1758 1855 public static function displayUnit($value) { 1759 1856 // http://www.matroska.org/technical/specs/index.html#DisplayUnit 1760 1857 static $units = array( … … 1766 1863 return (isset($units[$value]) ? $units[$value] : 'unknown'); 1767 1864 } 1768 1865 1866 /** 1867 * @param array $streams 1868 * 1869 * @return array 1870 */ 1769 1871 private static function getDefaultStreamInfo($streams) 1770 1872 { 1873 $stream = array(); 1771 1874 foreach (array_reverse($streams) as $stream) { 1772 1875 if ($stream['default']) { 1773 1876 break; -
src/wp-includes/ID3/module.audio-video.quicktime.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio-video.quicktime.php // 12 12 // module for analyzing Quicktime and MP3-in-MP4 files // … … 24 24 public $ReturnAtomData = true; 25 25 public $ParseAllPossibleAtoms = false; 26 26 27 /** 28 * @return bool 29 */ 27 30 public function Analyze() { 28 31 $info = &$this->getid3->info; 29 32 … … 35 38 36 39 $offset = 0; 37 40 $atomcounter = 0; 38 $atom_data_read_buffer_size = max($this->getid3->option_fread_buffer_size * 1024, ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : 1024)); // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]41 $atom_data_read_buffer_size = $info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : $this->getid3->option_fread_buffer_size * 1024; // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB] 39 42 while ($offset < $info['avdataend']) { 40 43 if (!getid3_lib::intValueSupported($offset)) { 41 44 $this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions'); … … 162 165 if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) { 163 166 $info['audio']['bitrate'] = $info['bitrate']; 164 167 } 168 if (!empty($info['bitrate']) && !empty($info['audio']['bitrate']) && empty($info['video']['bitrate']) && !empty($info['video']['frame_rate']) && !empty($info['video']['resolution_x']) && ($info['bitrate'] > $info['audio']['bitrate'])) { 169 $info['video']['bitrate'] = $info['bitrate'] - $info['audio']['bitrate']; 170 } 165 171 if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) { 166 172 foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) { 167 173 $samples_per_second = $samples_count / $info['playtime_seconds']; … … 193 199 if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) { 194 200 $info['video']['dataformat'] = 'quicktime'; 195 201 } 202 if (isset($info['video']) && ($info['mime_type'] == 'audio/mp4') && empty($info['video']['resolution_x']) && empty($info['video']['resolution_y'])) { 203 unset($info['video']); 204 } 196 205 197 206 return true; 198 207 } 199 208 209 /** 210 * @param string $atomname 211 * @param int $atomsize 212 * @param string $atom_data 213 * @param int $baseoffset 214 * @param array $atomHierarchy 215 * @param bool $ParseAllPossibleAtoms 216 * 217 * @return array|false 218 */ 200 219 public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { 201 220 // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm 202 221 // https://code.google.com/p/mp4v2/wiki/iTunesMetadata … … 203 222 204 223 $info = &$this->getid3->info; 205 224 206 $atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see http ://www.getid3.org/phpBB3/viewtopic.php?t=1717225 $atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see https://www.getid3.org/phpBB3/viewtopic.php?t=1717 207 226 array_push($atomHierarchy, $atomname); 208 227 $atom_structure['hierarchy'] = implode(' ', $atomHierarchy); 209 228 $atom_structure['name'] = $atomname; 210 229 $atom_structure['size'] = $atomsize; 211 230 $atom_structure['offset'] = $baseoffset; 212 switch ($atomname) { 213 case 'moov': // MOVie container atom 214 case 'trak': // TRAcK container atom 215 case 'clip': // CLIPping container atom 216 case 'matt': // track MATTe container atom 217 case 'edts': // EDiTS container atom 218 case 'tref': // Track REFerence container atom 219 case 'mdia': // MeDIA container atom 220 case 'minf': // Media INFormation container atom 221 case 'dinf': // Data INFormation container atom 222 case 'udta': // User DaTA container atom 223 case 'cmov': // Compressed MOVie container atom 224 case 'rmra': // Reference Movie Record Atom 225 case 'rmda': // Reference Movie Descriptor Atom 226 case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR) 227 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 228 break; 231 if (substr($atomname, 0, 3) == "\x00\x00\x00") { 232 // https://github.com/JamesHeinrich/getID3/issues/139 233 $atomname = getid3_lib::BigEndian2Int($atomname); 234 $atom_structure['name'] = $atomname; 235 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 236 } else { 237 switch ($atomname) { 238 case 'moov': // MOVie container atom 239 case 'trak': // TRAcK container atom 240 case 'clip': // CLIPping container atom 241 case 'matt': // track MATTe container atom 242 case 'edts': // EDiTS container atom 243 case 'tref': // Track REFerence container atom 244 case 'mdia': // MeDIA container atom 245 case 'minf': // Media INFormation container atom 246 case 'dinf': // Data INFormation container atom 247 case 'udta': // User DaTA container atom 248 case 'cmov': // Compressed MOVie container atom 249 case 'rmra': // Reference Movie Record Atom 250 case 'rmda': // Reference Movie Descriptor Atom 251 case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR) 252 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 253 break; 229 254 230 case 'ilst': // Item LiST container atom 231 if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) { 232 // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted 233 $allnumericnames = true; 234 foreach ($atom_structure['subatoms'] as $subatomarray) { 235 if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) { 236 $allnumericnames = false; 237 break; 238 } 239 } 240 if ($allnumericnames) { 241 $newData = array(); 255 case 'ilst': // Item LiST container atom 256 if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) { 257 // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted 258 $allnumericnames = true; 242 259 foreach ($atom_structure['subatoms'] as $subatomarray) { 243 foreach ($subatomarray['subatoms'] as $newData_subatomarray) { 244 unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']); 245 $newData[$subatomarray['name']] = $newData_subatomarray; 260 if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) { 261 $allnumericnames = false; 246 262 break; 247 263 } 248 264 } 249 $atom_structure['data'] = $newData; 250 unset($atom_structure['subatoms']); 265 if ($allnumericnames) { 266 $newData = array(); 267 foreach ($atom_structure['subatoms'] as $subatomarray) { 268 foreach ($subatomarray['subatoms'] as $newData_subatomarray) { 269 unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']); 270 $newData[$subatomarray['name']] = $newData_subatomarray; 271 break; 272 } 273 } 274 $atom_structure['data'] = $newData; 275 unset($atom_structure['subatoms']); 276 } 251 277 } 252 } 253 break; 278 break; 254 279 255 case "\x00\x00\x00\x01": 256 case "\x00\x00\x00\x02": 257 case "\x00\x00\x00\x03": 258 case "\x00\x00\x00\x04": 259 case "\x00\x00\x00\x05": 260 $atomname = getid3_lib::BigEndian2Int($atomname); 261 $atom_structure['name'] = $atomname; 262 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 263 break; 264 265 case 'stbl': // Sample TaBLe container atom 266 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 267 $isVideo = false; 268 $framerate = 0; 269 $framecount = 0; 270 foreach ($atom_structure['subatoms'] as $key => $value_array) { 271 if (isset($value_array['sample_description_table'])) { 272 foreach ($value_array['sample_description_table'] as $key2 => $value_array2) { 273 if (isset($value_array2['data_format'])) { 274 switch ($value_array2['data_format']) { 275 case 'avc1': 276 case 'mp4v': 277 // video data 278 $isVideo = true; 279 break; 280 case 'mp4a': 281 // audio data 282 break; 280 case 'stbl': // Sample TaBLe container atom 281 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 282 $isVideo = false; 283 $framerate = 0; 284 $framecount = 0; 285 foreach ($atom_structure['subatoms'] as $key => $value_array) { 286 if (isset($value_array['sample_description_table'])) { 287 foreach ($value_array['sample_description_table'] as $key2 => $value_array2) { 288 if (isset($value_array2['data_format'])) { 289 switch ($value_array2['data_format']) { 290 case 'avc1': 291 case 'mp4v': 292 // video data 293 $isVideo = true; 294 break; 295 case 'mp4a': 296 // audio data 297 break; 298 } 283 299 } 284 300 } 285 } 286 } elseif (isset($value_array['time_to_sample_table'])) {287 foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {288 if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {289 $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);290 $framecount = $value_array2['sample_count'];301 } elseif (isset($value_array['time_to_sample_table'])) { 302 foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) { 303 if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) { 304 $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3); 305 $framecount = $value_array2['sample_count']; 306 } 291 307 } 292 308 } 293 309 } 294 } 295 if ($isVideo && $framerate) { 296 $info['quicktime']['video']['frame_rate'] = $framerate; 297 $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate']; 298 } 299 if ($isVideo && $framecount) { 300 $info['quicktime']['video']['frame_count'] = $framecount; 301 } 302 break; 310 if ($isVideo && $framerate) { 311 $info['quicktime']['video']['frame_rate'] = $framerate; 312 $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate']; 313 } 314 if ($isVideo && $framecount) { 315 $info['quicktime']['video']['frame_count'] = $framecount; 316 } 317 break; 303 318 304 319 305 case "\xA9".'alb': // ALBum306 case "\xA9".'ART': //307 case "\xA9".'art': // ARTist308 case "\xA9".'aut': //309 case "\xA9".'cmt': // CoMmenT310 case "\xA9".'com': // COMposer311 case "\xA9".'cpy': //312 case "\xA9".'day': // content created year313 case "\xA9".'dir': //314 case "\xA9".'ed1': //315 case "\xA9".'ed2': //316 case "\xA9".'ed3': //317 case "\xA9".'ed4': //318 case "\xA9".'ed5': //319 case "\xA9".'ed6': //320 case "\xA9".'ed7': //321 case "\xA9".'ed8': //322 case "\xA9".'ed9': //323 case "\xA9".'enc': //324 case "\xA9".'fmt': //325 case "\xA9".'gen': // GENre326 case "\xA9".'grp': // GRouPing327 case "\xA9".'hst': //328 case "\xA9".'inf': //329 case "\xA9".'lyr': // LYRics330 case "\xA9".'mak': //331 case "\xA9".'mod': //332 case "\xA9".'nam': // full NAMe333 case "\xA9".'ope': //334 case "\xA9".'PRD': //335 case "\xA9".'prf': //336 case "\xA9".'req': //337 case "\xA9".'src': //338 case "\xA9".'swr': //339 case "\xA9".'too': // encoder340 case "\xA9".'trk': // TRacK341 case "\xA9".'url': //342 case "\xA9".'wrn': //343 case "\xA9".'wrt': // WRiTer344 case '----': // itunes specific345 case 'aART': // Album ARTist346 case 'akID': // iTunes store account type347 case 'apID': // Purchase Account348 case 'atID': //349 case 'catg': // CaTeGory350 case 'cmID': //351 case 'cnID': //352 case 'covr': // COVeR artwork353 case 'cpil': // ComPILation354 case 'cprt': // CoPyRighT355 case 'desc': // DESCription356 case 'disk': // DISK number357 case 'egid': // Episode Global ID358 case 'geID': //359 case 'gnre': // GeNRE360 case 'hdvd': // HD ViDeo361 case 'keyw': // KEYWord362 case 'ldes': // Long DEScription363 case 'pcst': // PodCaST364 case 'pgap': // GAPless Playback365 case 'plID': //366 case 'purd': // PURchase Date367 case 'purl': // Podcast URL368 case 'rati': //369 case 'rndu': //370 case 'rpdu': //371 case 'rtng': // RaTiNG372 case 'sfID': // iTunes store country373 case 'soaa': // SOrt Album Artist374 case 'soal': // SOrt ALbum375 case 'soar': // SOrt ARtist376 case 'soco': // SOrt COmposer377 case 'sonm': // SOrt NaMe378 case 'sosn': // SOrt Show Name379 case 'stik': //380 case 'tmpo': // TeMPO (BPM)381 case 'trkn': // TRacK Number382 case 'tven': // tvEpisodeID383 case 'tves': // TV EpiSode384 case 'tvnn': // TV Network Name385 case 'tvsh': // TV SHow Name386 case 'tvsn': // TV SeasoN387 if ($atom_parent == 'udta') {388 // User data atom handler389 $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));390 $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));391 $atom_structure['data'] = substr($atom_data, 4);320 case "\xA9".'alb': // ALBum 321 case "\xA9".'ART': // 322 case "\xA9".'art': // ARTist 323 case "\xA9".'aut': // 324 case "\xA9".'cmt': // CoMmenT 325 case "\xA9".'com': // COMposer 326 case "\xA9".'cpy': // 327 case "\xA9".'day': // content created year 328 case "\xA9".'dir': // 329 case "\xA9".'ed1': // 330 case "\xA9".'ed2': // 331 case "\xA9".'ed3': // 332 case "\xA9".'ed4': // 333 case "\xA9".'ed5': // 334 case "\xA9".'ed6': // 335 case "\xA9".'ed7': // 336 case "\xA9".'ed8': // 337 case "\xA9".'ed9': // 338 case "\xA9".'enc': // 339 case "\xA9".'fmt': // 340 case "\xA9".'gen': // GENre 341 case "\xA9".'grp': // GRouPing 342 case "\xA9".'hst': // 343 case "\xA9".'inf': // 344 case "\xA9".'lyr': // LYRics 345 case "\xA9".'mak': // 346 case "\xA9".'mod': // 347 case "\xA9".'nam': // full NAMe 348 case "\xA9".'ope': // 349 case "\xA9".'PRD': // 350 case "\xA9".'prf': // 351 case "\xA9".'req': // 352 case "\xA9".'src': // 353 case "\xA9".'swr': // 354 case "\xA9".'too': // encoder 355 case "\xA9".'trk': // TRacK 356 case "\xA9".'url': // 357 case "\xA9".'wrn': // 358 case "\xA9".'wrt': // WRiTer 359 case '----': // itunes specific 360 case 'aART': // Album ARTist 361 case 'akID': // iTunes store account type 362 case 'apID': // Purchase Account 363 case 'atID': // 364 case 'catg': // CaTeGory 365 case 'cmID': // 366 case 'cnID': // 367 case 'covr': // COVeR artwork 368 case 'cpil': // ComPILation 369 case 'cprt': // CoPyRighT 370 case 'desc': // DESCription 371 case 'disk': // DISK number 372 case 'egid': // Episode Global ID 373 case 'geID': // 374 case 'gnre': // GeNRE 375 case 'hdvd': // HD ViDeo 376 case 'keyw': // KEYWord 377 case 'ldes': // Long DEScription 378 case 'pcst': // PodCaST 379 case 'pgap': // GAPless Playback 380 case 'plID': // 381 case 'purd': // PURchase Date 382 case 'purl': // Podcast URL 383 case 'rati': // 384 case 'rndu': // 385 case 'rpdu': // 386 case 'rtng': // RaTiNG 387 case 'sfID': // iTunes store country 388 case 'soaa': // SOrt Album Artist 389 case 'soal': // SOrt ALbum 390 case 'soar': // SOrt ARtist 391 case 'soco': // SOrt COmposer 392 case 'sonm': // SOrt NaMe 393 case 'sosn': // SOrt Show Name 394 case 'stik': // 395 case 'tmpo': // TeMPO (BPM) 396 case 'trkn': // TRacK Number 397 case 'tven': // tvEpisodeID 398 case 'tves': // TV EpiSode 399 case 'tvnn': // TV Network Name 400 case 'tvsh': // TV SHow Name 401 case 'tvsn': // TV SeasoN 402 if ($atom_parent == 'udta') { 403 // User data atom handler 404 $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); 405 $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); 406 $atom_structure['data'] = substr($atom_data, 4); 392 407 393 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); 394 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { 395 $info['comments']['language'][] = $atom_structure['language']; 396 } 397 } else { 398 // Apple item list box atom handler 399 $atomoffset = 0; 400 if (substr($atom_data, 2, 2) == "\x10\xB5") { 401 // not sure what it means, but observed on iPhone4 data. 402 // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data 403 while ($atomoffset < strlen($atom_data)) { 404 $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2)); 405 $boxsmalltype = substr($atom_data, $atomoffset + 2, 2); 406 $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize); 407 if ($boxsmallsize <= 1) { 408 $this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset)); 409 $atom_structure['data'] = null; 410 $atomoffset = strlen($atom_data); 411 break; 412 } 413 switch ($boxsmalltype) { 414 case "\x10\xB5": 415 $atom_structure['data'] = $boxsmalldata; 416 break; 417 default: 418 $this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset); 419 $atom_structure['data'] = $atom_data; 420 break; 421 } 422 $atomoffset += (4 + $boxsmallsize); 408 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); 409 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { 410 $info['comments']['language'][] = $atom_structure['language']; 423 411 } 424 412 } else { 425 while ($atomoffset < strlen($atom_data)) { 426 $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4)); 427 $boxtype = substr($atom_data, $atomoffset + 4, 4); 428 $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8); 429 if ($boxsize <= 1) { 430 $this->warning('Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset)); 431 $atom_structure['data'] = null; 432 $atomoffset = strlen($atom_data); 433 break; 413 // Apple item list box atom handler 414 $atomoffset = 0; 415 if (substr($atom_data, 2, 2) == "\x10\xB5") { 416 // not sure what it means, but observed on iPhone4 data. 417 // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data 418 while ($atomoffset < strlen($atom_data)) { 419 $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2)); 420 $boxsmalltype = substr($atom_data, $atomoffset + 2, 2); 421 $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize); 422 if ($boxsmallsize <= 1) { 423 $this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset)); 424 $atom_structure['data'] = null; 425 $atomoffset = strlen($atom_data); 426 break; 427 } 428 switch ($boxsmalltype) { 429 case "\x10\xB5": 430 $atom_structure['data'] = $boxsmalldata; 431 break; 432 default: 433 $this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset); 434 $atom_structure['data'] = $atom_data; 435 break; 436 } 437 $atomoffset += (4 + $boxsmallsize); 434 438 } 435 $atomoffset += $boxsize; 436 437 switch ($boxtype) { 438 case 'mean': 439 case 'name': 440 $atom_structure[$boxtype] = substr($boxdata, 4); 439 } else { 440 while ($atomoffset < strlen($atom_data)) { 441 $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4)); 442 $boxtype = substr($atom_data, $atomoffset + 4, 4); 443 $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8); 444 if ($boxsize <= 1) { 445 $this->warning('Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset)); 446 $atom_structure['data'] = null; 447 $atomoffset = strlen($atom_data); 441 448 break; 449 } 450 $atomoffset += $boxsize; 442 451 443 case 'data': 444 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1)); 445 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3)); 446 switch ($atom_structure['flags_raw']) { 447 case 0: // data flag 448 case 21: // tmpo/cpil flag 449 switch ($atomname) { 450 case 'cpil': 451 case 'hdvd': 452 case 'pcst': 453 case 'pgap': 454 // 8-bit integer (boolean) 455 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); 456 break; 452 switch ($boxtype) { 453 case 'mean': 454 case 'name': 455 $atom_structure[$boxtype] = substr($boxdata, 4); 456 break; 457 457 458 case 'tmpo': 459 // 16-bit integer 460 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2)); 461 break; 458 case 'data': 459 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1)); 460 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3)); 461 switch ($atom_structure['flags_raw']) { 462 case 0: // data flag 463 case 21: // tmpo/cpil flag 464 switch ($atomname) { 465 case 'cpil': 466 case 'hdvd': 467 case 'pcst': 468 case 'pgap': 469 // 8-bit integer (boolean) 470 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); 471 break; 462 472 463 case 'disk': 464 case 'trkn': 465 // binary 466 $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2)); 467 $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2)); 468 $atom_structure['data'] = empty($num) ? '' : $num; 469 $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total; 470 break; 473 case 'tmpo': 474 // 16-bit integer 475 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2)); 476 break; 471 477 472 case 'gnre': 473 // enum 474 $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); 475 $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1); 476 break; 478 case 'disk': 479 case 'trkn': 480 // binary 481 $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2)); 482 $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2)); 483 $atom_structure['data'] = empty($num) ? '' : $num; 484 $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total; 485 break; 477 486 478 case 'rtng':479 // 8-bit integer480 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));481 $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);482 break;487 case 'gnre': 488 // enum 489 $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); 490 $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1); 491 break; 483 492 484 case 'stik':485 // 8-bit integer (enum)486 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));487 $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);488 break;493 case 'rtng': 494 // 8-bit integer 495 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); 496 $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]); 497 break; 489 498 490 case 'sfID':491 // 32-bit integer492 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));493 $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);494 break;499 case 'stik': 500 // 8-bit integer (enum) 501 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); 502 $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]); 503 break; 495 504 496 case 'egid': 497 case 'purl': 498 $atom_structure['data'] = substr($boxdata, 8); 499 break; 505 case 'sfID': 506 // 32-bit integer 507 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); 508 $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]); 509 break; 500 510 501 case 'plID':502 // 64-bit integer503 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8));504 break;511 case 'egid': 512 case 'purl': 513 $atom_structure['data'] = substr($boxdata, 8); 514 break; 505 515 506 case 'covr': 507 $atom_structure['data'] = substr($boxdata, 8); 516 case 'plID': 517 // 64-bit integer 518 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8)); 519 break; 520 521 case 'covr': 522 $atom_structure['data'] = substr($boxdata, 8); 523 // not a foolproof check, but better than nothing 524 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) { 525 $atom_structure['image_mime'] = 'image/jpeg'; 526 } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) { 527 $atom_structure['image_mime'] = 'image/png'; 528 } elseif (preg_match('#^GIF#', $atom_structure['data'])) { 529 $atom_structure['image_mime'] = 'image/gif'; 530 } 531 break; 532 533 case 'atID': 534 case 'cnID': 535 case 'geID': 536 case 'tves': 537 case 'tvsn': 538 default: 539 // 32-bit integer 540 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); 541 } 542 break; 543 544 case 1: // text flag 545 case 13: // image flag 546 default: 547 $atom_structure['data'] = substr($boxdata, 8); 548 if ($atomname == 'covr') { 508 549 // not a foolproof check, but better than nothing 509 550 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) { 510 551 $atom_structure['image_mime'] = 'image/jpeg'; … … 513 554 } elseif (preg_match('#^GIF#', $atom_structure['data'])) { 514 555 $atom_structure['image_mime'] = 'image/gif'; 515 556 } 516 break;517 518 case 'atID':519 case 'cnID':520 case 'geID':521 case 'tves':522 case 'tvsn':523 default:524 // 32-bit integer525 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));526 }527 break;528 529 case 1: // text flag530 case 13: // image flag531 default:532 $atom_structure['data'] = substr($boxdata, 8);533 if ($atomname == 'covr') {534 // not a foolproof check, but better than nothing535 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {536 $atom_structure['image_mime'] = 'image/jpeg';537 } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {538 $atom_structure['image_mime'] = 'image/png';539 } elseif (preg_match('#^GIF#', $atom_structure['data'])) {540 $atom_structure['image_mime'] = 'image/gif';541 557 } 542 } 543 break; 558 break; 544 559 545 }546 break;560 } 561 break; 547 562 548 default:549 $this->warning('Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset);550 $atom_structure['data'] = $atom_data;563 default: 564 $this->warning('Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset); 565 $atom_structure['data'] = $atom_data; 551 566 567 } 552 568 } 553 569 } 554 570 } 555 } 556 $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']); 557 break; 571 $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']); 572 break; 558 573 559 574 560 case 'play': // auto-PLAY atom561 $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));575 case 'play': // auto-PLAY atom 576 $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 562 577 563 $info['quicktime']['autoplay'] = $atom_structure['autoplay'];564 break;578 $info['quicktime']['autoplay'] = $atom_structure['autoplay']; 579 break; 565 580 566 581 567 case 'WLOC': // Window LOCation atom568 $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));569 $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));570 break;582 case 'WLOC': // Window LOCation atom 583 $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); 584 $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); 585 break; 571 586 572 587 573 case 'LOOP': // LOOPing atom574 case 'SelO': // play SELection Only atom575 case 'AllF': // play ALL Frames atom576 $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);577 break;588 case 'LOOP': // LOOPing atom 589 case 'SelO': // play SELection Only atom 590 case 'AllF': // play ALL Frames atom 591 $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data); 592 break; 578 593 579 594 580 case 'name': //581 case 'MCPS': // Media Cleaner PRo582 case '@PRM': // adobe PReMiere version583 case '@PRQ': // adobe PRemiere Quicktime version584 $atom_structure['data'] = $atom_data;585 break;595 case 'name': // 596 case 'MCPS': // Media Cleaner PRo 597 case '@PRM': // adobe PReMiere version 598 case '@PRQ': // adobe PRemiere Quicktime version 599 $atom_structure['data'] = $atom_data; 600 break; 586 601 587 602 588 case 'cmvd': // Compressed MooV Data atom589 // Code by ubergeekØubergeek*tv based on information from590 // http://developer.apple.com/quicktime/icefloe/dispatch012.html591 $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));603 case 'cmvd': // Compressed MooV Data atom 604 // Code by ubergeekØubergeek*tv based on information from 605 // http://developer.apple.com/quicktime/icefloe/dispatch012.html 606 $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 592 607 593 $CompressedFileData = substr($atom_data, 4);594 if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {595 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);596 } else {597 $this->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']);598 }599 break;608 $CompressedFileData = substr($atom_data, 4); 609 if ($UncompressedHeader = @gzuncompress($CompressedFileData)) { 610 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms); 611 } else { 612 $this->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']); 613 } 614 break; 600 615 601 616 602 case 'dcom': // Data COMpression atom603 $atom_structure['compression_id'] = $atom_data;604 $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);605 break;617 case 'dcom': // Data COMpression atom 618 $atom_structure['compression_id'] = $atom_data; 619 $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data); 620 break; 606 621 607 622 608 case 'rdrf': // Reference movie Data ReFerence atom609 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));610 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));611 $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);623 case 'rdrf': // Reference movie Data ReFerence atom 624 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 625 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 626 $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001); 612 627 613 $atom_structure['reference_type_name'] = substr($atom_data, 4, 4);614 $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));615 switch ($atom_structure['reference_type_name']) {616 case 'url ':617 $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12));618 break;628 $atom_structure['reference_type_name'] = substr($atom_data, 4, 4); 629 $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 630 switch ($atom_structure['reference_type_name']) { 631 case 'url ': 632 $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12)); 633 break; 619 634 620 case 'alis':621 $atom_structure['file_alias'] = substr($atom_data, 12);622 break;635 case 'alis': 636 $atom_structure['file_alias'] = substr($atom_data, 12); 637 break; 623 638 624 case 'rsrc':625 $atom_structure['resource_alias'] = substr($atom_data, 12);626 break;639 case 'rsrc': 640 $atom_structure['resource_alias'] = substr($atom_data, 12); 641 break; 627 642 628 default:629 $atom_structure['data'] = substr($atom_data, 12);630 break;631 }632 break;643 default: 644 $atom_structure['data'] = substr($atom_data, 12); 645 break; 646 } 647 break; 633 648 634 649 635 case 'rmqu': // Reference Movie QUality atom636 $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);637 break;650 case 'rmqu': // Reference Movie QUality atom 651 $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data); 652 break; 638 653 639 654 640 case 'rmcs': // Reference Movie Cpu Speed atom641 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));642 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000643 $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));644 break;655 case 'rmcs': // Reference Movie Cpu Speed atom 656 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 657 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 658 $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 659 break; 645 660 646 661 647 case 'rmvc': // Reference Movie Version Check atom648 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));649 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000650 $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4);651 $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));652 $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));653 $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));654 break;662 case 'rmvc': // Reference Movie Version Check atom 663 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 664 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 665 $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4); 666 $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 667 $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 668 $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2)); 669 break; 655 670 656 671 657 case 'rmcd': // Reference Movie Component check atom658 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));659 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000660 $atom_structure['component_type'] = substr($atom_data, 4, 4);661 $atom_structure['component_subtype'] = substr($atom_data, 8, 4);662 $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);663 $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));664 $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));665 $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));666 break;672 case 'rmcd': // Reference Movie Component check atom 673 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 674 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 675 $atom_structure['component_type'] = substr($atom_data, 4, 4); 676 $atom_structure['component_subtype'] = substr($atom_data, 8, 4); 677 $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4); 678 $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); 679 $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); 680 $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4)); 681 break; 667 682 668 683 669 case 'rmdr': // Reference Movie Data Rate atom670 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));671 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000672 $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));684 case 'rmdr': // Reference Movie Data Rate atom 685 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 686 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 687 $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 673 688 674 $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;675 break;689 $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10; 690 break; 676 691 677 692 678 case 'rmla': // Reference Movie Language Atom679 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));680 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000681 $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));693 case 'rmla': // Reference Movie Language Atom 694 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 695 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 696 $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 682 697 683 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);684 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {685 $info['comments']['language'][] = $atom_structure['language'];686 }687 break;698 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); 699 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { 700 $info['comments']['language'][] = $atom_structure['language']; 701 } 702 break; 688 703 689 704 690 case 'rmla': // Reference Movie Language Atom 691 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 692 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 693 $atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 694 break; 705 case 'ptv ': // Print To Video - defines a movie's full screen mode 706 // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm 707 $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); 708 $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000 709 $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000 710 $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1)); 711 $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1)); 695 712 713 $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag']; 714 $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag']; 696 715 697 case 'ptv ': // Print To Video - defines a movie's full screen mode 698 // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm 699 $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); 700 $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000 701 $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000 702 $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1)); 703 $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1)); 716 $ptv_lookup[0] = 'normal'; 717 $ptv_lookup[1] = 'double'; 718 $ptv_lookup[2] = 'half'; 719 $ptv_lookup[3] = 'full'; 720 $ptv_lookup[4] = 'current'; 721 if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { 722 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; 723 } else { 724 $this->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')'); 725 } 726 break; 704 727 705 $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];706 $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];707 728 708 $ptv_lookup[0] = 'normal'; 709 $ptv_lookup[1] = 'double'; 710 $ptv_lookup[2] = 'half'; 711 $ptv_lookup[3] = 'full'; 712 $ptv_lookup[4] = 'current'; 713 if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { 714 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; 715 } else { 716 $this->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')'); 717 } 718 break; 729 case 'stsd': // Sample Table Sample Description atom 730 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 731 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 732 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 719 733 734 // see: https://github.com/JamesHeinrich/getID3/issues/111 735 // Some corrupt files have been known to have high bits set in the number_entries field 736 // This field shouldn't really need to be 32-bits, values stores are likely in the range 1-100000 737 // Workaround: mask off the upper byte and throw a warning if it's nonzero 738 if ($atom_structure['number_entries'] > 0x000FFFFF) { 739 if ($atom_structure['number_entries'] > 0x00FFFFFF) { 740 $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Ignoring upper byte and interpreting this as 0x'.getid3_lib::PrintHexBytes(substr($atom_data, 5, 3), true, false).' = '.($atom_structure['number_entries'] & 0x00FFFFFF)); 741 $atom_structure['number_entries'] = ($atom_structure['number_entries'] & 0x00FFFFFF); 742 } else { 743 $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Please report this to info@getid3.org referencing bug report #111'); 744 } 745 } 720 746 721 case 'stsd': // Sample Table Sample Description atom 722 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 723 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 724 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 747 $stsdEntriesDataOffset = 8; 748 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 749 $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4)); 750 $stsdEntriesDataOffset += 4; 751 $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4); 752 $stsdEntriesDataOffset += 4; 753 $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6)); 754 $stsdEntriesDataOffset += 6; 755 $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2)); 756 $stsdEntriesDataOffset += 2; 757 $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); 758 $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); 725 759 726 // see: https://github.com/JamesHeinrich/getID3/issues/111 727 // Some corrupt files have been known to have high bits set in the number_entries field 728 // This field shouldn't really need to be 32-bits, values stores are likely in the range 1-100000 729 // Workaround: mask off the upper byte and throw a warning if it's nonzero 730 if ($atom_structure['number_entries'] > 0x000FFFFF) { 731 if ($atom_structure['number_entries'] > 0x00FFFFFF) { 732 $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Ignoring upper byte and interpreting this as 0x'.getid3_lib::PrintHexBytes(substr($atom_data, 5, 3), true, false).' = '.($atom_structure['number_entries'] & 0x00FFFFFF)); 733 $atom_structure['number_entries'] = ($atom_structure['number_entries'] & 0x00FFFFFF); 734 } else { 735 $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Please report this to info@getid3.org referencing bug report #111'); 736 } 737 } 760 $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2)); 761 $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2)); 762 $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4); 738 763 739 $stsdEntriesDataOffset = 8; 740 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 741 $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4)); 742 $stsdEntriesDataOffset += 4; 743 $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4); 744 $stsdEntriesDataOffset += 4; 745 $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6)); 746 $stsdEntriesDataOffset += 6; 747 $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2)); 748 $stsdEntriesDataOffset += 2; 749 $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); 750 $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); 764 switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) { 751 765 752 $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2)); 753 $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2)); 754 $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4); 766 case "\x00\x00\x00\x00": 767 // audio tracks 768 $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2)); 769 $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2)); 770 $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2)); 771 $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2)); 772 $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4)); 755 773 756 switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) { 774 // video tracks 775 // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html 776 $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); 777 $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); 778 $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); 779 $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); 780 $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); 781 $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); 782 $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4)); 783 $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2)); 784 $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4); 785 $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2)); 786 $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2)); 757 787 758 case "\x00\x00\x00\x00": 759 // audio tracks 760 $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2)); 761 $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2)); 762 $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2)); 763 $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2)); 764 $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4)); 788 switch ($atom_structure['sample_description_table'][$i]['data_format']) { 789 case '2vuY': 790 case 'avc1': 791 case 'cvid': 792 case 'dvc ': 793 case 'dvcp': 794 case 'gif ': 795 case 'h263': 796 case 'jpeg': 797 case 'kpcd': 798 case 'mjpa': 799 case 'mjpb': 800 case 'mp4v': 801 case 'png ': 802 case 'raw ': 803 case 'rle ': 804 case 'rpza': 805 case 'smc ': 806 case 'SVQ1': 807 case 'SVQ3': 808 case 'tiff': 809 case 'v210': 810 case 'v216': 811 case 'v308': 812 case 'v408': 813 case 'v410': 814 case 'yuv2': 815 $info['fileformat'] = 'mp4'; 816 $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 817 if ($this->QuicktimeVideoCodecLookup($info['video']['fourcc'])) { 818 $info['video']['fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($info['video']['fourcc']); 819 } 765 820 766 // video tracks 767 // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html 768 $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); 769 $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); 770 $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); 771 $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); 772 $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); 773 $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); 774 $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4)); 775 $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2)); 776 $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4); 777 $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2)); 778 $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2)); 821 // https://www.getid3.org/phpBB3/viewtopic.php?t=1550 822 //if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers 823 if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) { 824 // assume that values stored here are more important than values stored in [tkhd] atom 825 $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width']; 826 $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height']; 827 $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; 828 $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; 829 } 830 break; 779 831 780 switch ($atom_structure['sample_description_table'][$i]['data_format']) { 781 case '2vuY': 782 case 'avc1': 783 case 'cvid': 784 case 'dvc ': 785 case 'dvcp': 786 case 'gif ': 787 case 'h263': 788 case 'jpeg': 789 case 'kpcd': 790 case 'mjpa': 791 case 'mjpb': 792 case 'mp4v': 793 case 'png ': 794 case 'raw ': 795 case 'rle ': 796 case 'rpza': 797 case 'smc ': 798 case 'SVQ1': 799 case 'SVQ3': 800 case 'tiff': 801 case 'v210': 802 case 'v216': 803 case 'v308': 804 case 'v408': 805 case 'v410': 806 case 'yuv2': 807 $info['fileformat'] = 'mp4'; 808 $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 809 // http://www.getid3.org/phpBB3/viewtopic.php?t=1550 810 //if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers 811 if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) { 812 // assume that values stored here are more important than values stored in [tkhd] atom 813 $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width']; 814 $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height']; 815 $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; 816 $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; 817 } 818 break; 832 case 'qtvr': 833 $info['video']['dataformat'] = 'quicktimevr'; 834 break; 819 835 820 case 'qtvr': 821 $info['video']['dataformat'] = 'quicktimevr'; 822 break; 836 case 'mp4a': 837 default: 838 $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); 839 $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; 840 $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; 841 $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth']; 842 $info['audio']['codec'] = $info['quicktime']['audio']['codec']; 843 $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate']; 844 $info['audio']['channels'] = $info['quicktime']['audio']['channels']; 845 $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth']; 846 switch ($atom_structure['sample_description_table'][$i]['data_format']) { 847 case 'raw ': // PCM 848 case 'alac': // Apple Lossless Audio Codec 849 case 'sowt': // signed/two's complement (Little Endian) 850 case 'twos': // signed/two's complement (Big Endian) 851 case 'in24': // 24-bit Integer 852 case 'in32': // 32-bit Integer 853 case 'fl32': // 32-bit Floating Point 854 case 'fl64': // 64-bit Floating Point 855 $info['audio']['lossless'] = $info['quicktime']['audio']['lossless'] = true; 856 $info['audio']['bitrate'] = $info['quicktime']['audio']['bitrate'] = $info['audio']['channels'] * $info['audio']['bits_per_sample'] * $info['audio']['sample_rate']; 857 break; 858 default: 859 $info['audio']['lossless'] = false; 860 break; 861 } 862 break; 863 } 864 break; 823 865 824 case 'mp4a': 825 default: 826 $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); 827 $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; 828 $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; 829 $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth']; 830 $info['audio']['codec'] = $info['quicktime']['audio']['codec']; 831 $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate']; 832 $info['audio']['channels'] = $info['quicktime']['audio']['channels']; 833 $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth']; 834 switch ($atom_structure['sample_description_table'][$i]['data_format']) { 835 case 'raw ': // PCM 836 case 'alac': // Apple Lossless Audio Codec 837 $info['audio']['lossless'] = true; 838 break; 839 default: 840 $info['audio']['lossless'] = false; 841 break; 842 } 843 break; 844 } 845 break; 866 default: 867 switch ($atom_structure['sample_description_table'][$i]['data_format']) { 868 case 'mp4s': 869 $info['fileformat'] = 'mp4'; 870 break; 846 871 847 default: 848 switch ($atom_structure['sample_description_table'][$i]['data_format']) { 849 case 'mp4s': 850 $info['fileformat'] = 'mp4'; 851 break; 872 default: 873 // video atom 874 $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); 875 $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); 876 $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); 877 $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); 878 $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4)); 879 $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); 880 $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); 881 $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2)); 882 $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1)); 883 $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']); 884 $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2)); 885 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); 852 886 853 default: 854 // video atom 855 $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); 856 $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); 857 $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); 858 $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); 859 $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4)); 860 $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); 861 $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); 862 $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2)); 863 $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1)); 864 $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']); 865 $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2)); 866 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); 887 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); 888 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); 867 889 868 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); 869 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); 890 if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { 891 $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 892 $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); 893 $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']); 894 $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; 895 $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; 870 896 871 if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { 872 $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 873 $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); 874 $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']); 875 $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; 876 $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; 897 $info['video']['codec'] = $info['quicktime']['video']['codec']; 898 $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth']; 899 } 900 $info['video']['lossless'] = false; 901 $info['video']['pixel_aspect_ratio'] = (float) 1; 902 break; 903 } 904 break; 905 } 906 switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) { 907 case 'mp4a': 908 $info['audio']['dataformat'] = 'mp4'; 909 $info['quicktime']['audio']['codec'] = 'mp4'; 910 break; 877 911 878 $info['video']['codec'] = $info['quicktime']['video']['codec']; 879 $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth']; 880 } 881 $info['video']['lossless'] = false; 882 $info['video']['pixel_aspect_ratio'] = (float) 1; 883 break; 884 } 885 break; 886 } 887 switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) { 888 case 'mp4a': 889 $info['audio']['dataformat'] = 'mp4'; 890 $info['quicktime']['audio']['codec'] = 'mp4'; 891 break; 912 case '3ivx': 913 case '3iv1': 914 case '3iv2': 915 $info['video']['dataformat'] = '3ivx'; 916 break; 892 917 893 case '3ivx': 894 case '3iv1': 895 case '3iv2': 896 $info['video']['dataformat'] = '3ivx'; 897 break; 918 case 'xvid': 919 $info['video']['dataformat'] = 'xvid'; 920 break; 898 921 899 case 'xvid':900 $info['video']['dataformat'] = 'xvid';901 break;922 case 'mp4v': 923 $info['video']['dataformat'] = 'mpeg4'; 924 break; 902 925 903 case 'mp4v': 904 $info['video']['dataformat'] = 'mpeg4'; 905 break; 926 case 'divx': 927 case 'div1': 928 case 'div2': 929 case 'div3': 930 case 'div4': 931 case 'div5': 932 case 'div6': 933 $info['video']['dataformat'] = 'divx'; 934 break; 906 935 907 case 'divx': 908 case 'div1': 909 case 'div2': 910 case 'div3': 911 case 'div4': 912 case 'div5': 913 case 'div6': 914 $info['video']['dataformat'] = 'divx'; 915 break; 916 917 default: 918 // do nothing 919 break; 936 default: 937 // do nothing 938 break; 939 } 940 unset($atom_structure['sample_description_table'][$i]['data']); 920 941 } 921 unset($atom_structure['sample_description_table'][$i]['data']); 922 } 923 break; 942 break; 924 943 925 944 926 case 'stts': // Sample Table Time-to-Sample atom927 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));928 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000929 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));930 $sttsEntriesDataOffset = 8;931 //$FrameRateCalculatorArray = array();932 $frames_count = 0;945 case 'stts': // Sample Table Time-to-Sample atom 946 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 947 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 948 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 949 $sttsEntriesDataOffset = 8; 950 //$FrameRateCalculatorArray = array(); 951 $frames_count = 0; 933 952 934 $max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);935 if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {936 $this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries']/ 1048576).'MB).');937 }938 for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {939 $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));940 $sttsEntriesDataOffset += 4;941 $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));942 $sttsEntriesDataOffset += 4;953 $max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']); 954 if ($max_stts_entries_to_scan < $atom_structure['number_entries']) { 955 $this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($this->getid3->memory_limit / 1048576).'MB).'); 956 } 957 for ($i = 0; $i < $max_stts_entries_to_scan; $i++) { 958 $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4)); 959 $sttsEntriesDataOffset += 4; 960 $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4)); 961 $sttsEntriesDataOffset += 4; 943 962 944 $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];963 $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count']; 945 964 946 // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM 947 //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) { 948 // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration']; 949 // if ($stts_new_framerate <= 60) { 950 // // some atoms have durations of "1" giving a very large framerate, which probably is not right 951 // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate); 965 // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM 966 //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) { 967 // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration']; 968 // if ($stts_new_framerate <= 60) { 969 // // some atoms have durations of "1" giving a very large framerate, which probably is not right 970 // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate); 971 // } 972 //} 973 // 974 //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count']; 975 } 976 $info['quicktime']['stts_framecount'][] = $frames_count; 977 //$sttsFramesTotal = 0; 978 //$sttsSecondsTotal = 0; 979 //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) { 980 // if (($frames_per_second > 60) || ($frames_per_second < 1)) { 981 // // not video FPS information, probably audio information 982 // $sttsFramesTotal = 0; 983 // $sttsSecondsTotal = 0; 984 // break; 952 985 // } 986 // $sttsFramesTotal += $frame_count; 987 // $sttsSecondsTotal += $frame_count / $frames_per_second; 953 988 //} 954 // 955 //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count']; 956 } 957 $info['quicktime']['stts_framecount'][] = $frames_count; 958 //$sttsFramesTotal = 0; 959 //$sttsSecondsTotal = 0; 960 //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) { 961 // if (($frames_per_second > 60) || ($frames_per_second < 1)) { 962 // // not video FPS information, probably audio information 963 // $sttsFramesTotal = 0; 964 // $sttsSecondsTotal = 0; 965 // break; 966 // } 967 // $sttsFramesTotal += $frame_count; 968 // $sttsSecondsTotal += $frame_count / $frames_per_second; 969 //} 970 //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) { 971 // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) { 972 // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal; 973 // } 974 //} 975 break; 989 //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) { 990 // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) { 991 // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal; 992 // } 993 //} 994 break; 976 995 977 996 978 case 'stss': // Sample Table Sync Sample (key frames) atom 979 if ($ParseAllPossibleAtoms) { 980 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 981 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 982 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 983 $stssEntriesDataOffset = 8; 984 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 985 $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4)); 986 $stssEntriesDataOffset += 4; 997 case 'stss': // Sample Table Sync Sample (key frames) atom 998 if ($ParseAllPossibleAtoms) { 999 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1000 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1001 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1002 $stssEntriesDataOffset = 8; 1003 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1004 $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4)); 1005 $stssEntriesDataOffset += 4; 1006 } 987 1007 } 988 } 989 break; 1008 break; 990 1009 991 1010 992 case 'stsc': // Sample Table Sample-to-Chunk atom 993 if ($ParseAllPossibleAtoms) { 994 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 995 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 996 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 997 $stscEntriesDataOffset = 8; 998 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 999 $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); 1000 $stscEntriesDataOffset += 4; 1001 $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); 1002 $stscEntriesDataOffset += 4; 1003 $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); 1004 $stscEntriesDataOffset += 4; 1011 case 'stsc': // Sample Table Sample-to-Chunk atom 1012 if ($ParseAllPossibleAtoms) { 1013 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1014 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1015 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1016 $stscEntriesDataOffset = 8; 1017 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1018 $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); 1019 $stscEntriesDataOffset += 4; 1020 $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); 1021 $stscEntriesDataOffset += 4; 1022 $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); 1023 $stscEntriesDataOffset += 4; 1024 } 1005 1025 } 1006 } 1007 break; 1026 break; 1008 1027 1009 1028 1010 case 'stsz': // Sample Table SiZe atom 1011 if ($ParseAllPossibleAtoms) { 1012 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1013 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1014 $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1015 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1016 $stszEntriesDataOffset = 12; 1017 if ($atom_structure['sample_size'] == 0) { 1029 case 'stsz': // Sample Table SiZe atom 1030 if ($ParseAllPossibleAtoms) { 1031 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1032 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1033 $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1034 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1035 $stszEntriesDataOffset = 12; 1036 if ($atom_structure['sample_size'] == 0) { 1037 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1038 $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4)); 1039 $stszEntriesDataOffset += 4; 1040 } 1041 } 1042 } 1043 break; 1044 1045 1046 case 'stco': // Sample Table Chunk Offset atom 1047 if ($ParseAllPossibleAtoms) { 1048 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1049 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1050 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1051 $stcoEntriesDataOffset = 8; 1018 1052 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1019 $atom_structure[' sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));1020 $st szEntriesDataOffset += 4;1053 $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4)); 1054 $stcoEntriesDataOffset += 4; 1021 1055 } 1022 1056 } 1023 } 1024 break; 1057 break; 1025 1058 1026 1059 1027 case 'stco': // Sample Table Chunk Offset atom 1028 if ($ParseAllPossibleAtoms) { 1029 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1030 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1031 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1032 $stcoEntriesDataOffset = 8; 1033 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1034 $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4)); 1035 $stcoEntriesDataOffset += 4; 1060 case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files) 1061 if ($ParseAllPossibleAtoms) { 1062 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1063 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1064 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1065 $stcoEntriesDataOffset = 8; 1066 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1067 $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8)); 1068 $stcoEntriesDataOffset += 8; 1069 } 1036 1070 } 1037 } 1038 break; 1071 break; 1039 1072 1040 1073 1041 case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files) 1042 if ($ParseAllPossibleAtoms) { 1074 case 'dref': // Data REFerence atom 1043 1075 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1044 1076 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1045 1077 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1046 $ stcoEntriesDataOffset = 8;1078 $drefDataOffset = 8; 1047 1079 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1048 $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8)); 1049 $stcoEntriesDataOffset += 8; 1080 $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4)); 1081 $drefDataOffset += 4; 1082 $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4); 1083 $drefDataOffset += 4; 1084 $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1)); 1085 $drefDataOffset += 1; 1086 $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000 1087 $drefDataOffset += 3; 1088 $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); 1089 $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); 1090 1091 $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001); 1050 1092 } 1051 } 1052 break; 1093 break; 1053 1094 1054 1095 1055 case 'dref': // Data REFerence atom 1056 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1057 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1058 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1059 $drefDataOffset = 8; 1060 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { 1061 $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4)); 1062 $drefDataOffset += 4; 1063 $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4); 1064 $drefDataOffset += 4; 1065 $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1)); 1066 $drefDataOffset += 1; 1067 $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000 1068 $drefDataOffset += 3; 1069 $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); 1070 $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); 1096 case 'gmin': // base Media INformation atom 1097 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1098 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1099 $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 1100 $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); 1101 $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2)); 1102 $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); 1103 $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2)); 1104 $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2)); 1105 break; 1071 1106 1072 $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);1073 }1074 break;1075 1107 1108 case 'smhd': // Sound Media information HeaDer atom 1109 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1110 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1111 $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 1112 $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); 1113 break; 1076 1114 1077 case 'gmin': // base Media INformation atom1078 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1079 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x00001080 $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));1081 $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));1082 $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));1083 $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));1084 $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));1085 $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));1086 break;1087 1115 1116 case 'vmhd': // Video Media information HeaDer atom 1117 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1118 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1119 $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 1120 $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); 1121 $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2)); 1122 $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); 1088 1123 1089 case 'smhd': // Sound Media information HeaDer atom 1090 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1091 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1092 $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 1093 $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); 1094 break; 1124 $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001); 1125 break; 1095 1126 1096 1127 1097 case 'vmhd': // Video Media information HeaDer atom 1098 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1099 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1100 $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 1101 $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); 1102 $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2)); 1103 $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); 1128 case 'hdlr': // HanDLeR reference atom 1129 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1130 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1131 $atom_structure['component_type'] = substr($atom_data, 4, 4); 1132 $atom_structure['component_subtype'] = substr($atom_data, 8, 4); 1133 $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4); 1134 $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); 1135 $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); 1136 $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24)); 1104 1137 1105 $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001); 1106 break; 1138 if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) { 1139 $info['video']['dataformat'] = 'quicktimevr'; 1140 } 1141 break; 1107 1142 1108 1143 1109 case 'hdlr': // HanDLeR referenceatom1110 $atom_structure['version']= getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1111 $atom_structure['flags_raw']= getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x00001112 $atom_structure['component_type'] = substr($atom_data, 4, 4);1113 $atom_structure['component_subtype'] = substr($atom_data, 8, 4);1114 $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);1115 $atom_structure['component_flags_raw']= getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));1116 $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));1117 $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));1144 case 'mdhd': // MeDia HeaDer atom 1145 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1146 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1147 $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1148 $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1149 $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 1150 $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); 1151 $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2)); 1152 $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2)); 1118 1153 1119 if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) { 1120 $info['video']['dataformat'] = 'quicktimevr'; 1121 } 1122 break; 1154 if ($atom_structure['time_scale'] == 0) { 1155 $this->error('Corrupt Quicktime file: mdhd.time_scale == zero'); 1156 return false; 1157 } 1158 $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); 1123 1159 1160 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); 1161 $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); 1162 $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; 1163 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); 1164 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { 1165 $info['comments']['language'][] = $atom_structure['language']; 1166 } 1167 break; 1124 1168 1125 case 'mdhd': // MeDia HeaDer atom1126 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1127 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x00001128 $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));1129 $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));1130 $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));1131 $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));1132 $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));1133 $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));1134 1169 1135 if ($atom_structure['time_scale'] == 0) {1136 $ this->error('Corrupt Quicktime file: mdhd.time_scale == zero');1137 return false;1138 }1139 $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);1170 case 'pnot': // Preview atom 1171 $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format" 1172 $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00 1173 $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT' 1174 $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01 1140 1175 1141 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); 1142 $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); 1143 $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; 1144 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); 1145 if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { 1146 $info['comments']['language'][] = $atom_structure['language']; 1147 } 1148 break; 1176 $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']); 1177 break; 1149 1178 1150 1179 1151 case 'pnot': // Previewatom1152 $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format"1153 $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x001154 $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'1155 $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x011180 case 'crgn': // Clipping ReGioN atom 1181 $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box, 1182 $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields 1183 $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region. 1184 break; 1156 1185 1157 $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);1158 break;1159 1186 1187 case 'load': // track LOAD settings atom 1188 $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1189 $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1190 $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1191 $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 1160 1192 1161 case 'crgn': // Clipping ReGioN atom 1162 $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box, 1163 $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields 1164 $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region. 1165 break; 1193 $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020); 1194 $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100); 1195 break; 1166 1196 1167 1197 1168 case 'load': // track LOAD settings atom 1169 $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1170 $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1171 $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1172 $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 1198 case 'tmcd': // TiMe CoDe atom 1199 case 'chap': // CHAPter list atom 1200 case 'sync': // SYNChronization atom 1201 case 'scpt': // tranSCriPT atom 1202 case 'ssrc': // non-primary SouRCe atom 1203 for ($i = 0; $i < strlen($atom_data); $i += 4) { 1204 @$atom_structure['track_id'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4)); 1205 } 1206 break; 1173 1207 1174 $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);1175 $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100);1176 break;1177 1208 1209 case 'elst': // Edit LiST atom 1210 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1211 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1212 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1213 for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) { 1214 $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4)); 1215 $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4)); 1216 $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4)); 1217 } 1218 break; 1178 1219 1179 case 'tmcd': // TiMe CoDe atom1180 case 'chap': // CHAPter list atom1181 case 'sync': // SYNChronization atom1182 case 'scpt': // tranSCriPT atom1183 case 'ssrc': // non-primary SouRCe atom1184 for ($i = 0; $i < strlen($atom_data); $i += 4) {1185 @$atom_structure['track_id'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));1186 }1187 break;1188 1220 1221 case 'kmat': // compressed MATte atom 1222 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1223 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 1224 $atom_structure['matte_data_raw'] = substr($atom_data, 4); 1225 break; 1189 1226 1190 case 'elst': // Edit LiST atom1191 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1192 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x00001193 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));1194 for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {1195 $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));1196 $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));1197 $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));1198 }1199 break;1200 1227 1228 case 'ctab': // Color TABle atom 1229 $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000 1230 $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000 1231 $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1; 1232 for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) { 1233 $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2)); 1234 $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2)); 1235 $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2)); 1236 $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2)); 1237 } 1238 break; 1201 1239 1202 case 'kmat': // compressed MATte atom1203 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1204 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x00001205 $atom_structure['matte_data_raw'] = substr($atom_data, 4);1206 break;1207 1240 1241 case 'mvhd': // MoVie HeaDer atom 1242 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1243 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1244 $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1245 $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1246 $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 1247 $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); 1248 $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4)); 1249 $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2)); 1250 $atom_structure['reserved'] = substr($atom_data, 26, 10); 1251 $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4)); 1252 $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); 1253 $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4)); 1254 $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4)); 1255 $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); 1256 $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4)); 1257 $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4)); 1258 $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); 1259 $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4)); 1260 $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4)); 1261 $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4)); 1262 $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4)); 1263 $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4)); 1264 $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4)); 1265 $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4)); 1266 $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4)); 1208 1267 1209 case 'ctab': // Color TABle atom 1210 $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000 1211 $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000 1212 $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1; 1213 for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) { 1214 $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2)); 1215 $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2)); 1216 $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2)); 1217 $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2)); 1218 } 1219 break; 1268 if ($atom_structure['time_scale'] == 0) { 1269 $this->error('Corrupt Quicktime file: mvhd.time_scale == zero'); 1270 return false; 1271 } 1272 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); 1273 $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); 1274 $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); 1275 $info['quicktime']['display_scale'] = $atom_structure['matrix_a']; 1276 $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; 1277 break; 1220 1278 1221 1279 1222 case 'mvhd': // MoVie HeaDer atom 1223 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1224 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1225 $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1226 $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1227 $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 1228 $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); 1229 $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4)); 1230 $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2)); 1231 $atom_structure['reserved'] = substr($atom_data, 26, 10); 1232 $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4)); 1233 $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); 1234 $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4)); 1235 $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4)); 1236 $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); 1237 $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4)); 1238 $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4)); 1239 $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); 1240 $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4)); 1241 $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4)); 1242 $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4)); 1243 $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4)); 1244 $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4)); 1245 $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4)); 1246 $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4)); 1247 $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4)); 1280 case 'tkhd': // TracK HeaDer atom 1281 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1282 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1283 $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1284 $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1285 $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 1286 $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); 1287 $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); 1288 $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8)); 1289 $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2)); 1290 $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2)); 1291 $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2)); 1292 $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2)); 1293 // http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html 1294 // http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737 1295 $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); 1296 $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4)); 1297 $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4)); 1298 $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); 1299 $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4)); 1300 $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4)); 1301 $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); 1302 $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4)); 1303 $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4)); 1304 $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4)); 1305 $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4)); 1306 $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001); 1307 $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002); 1308 $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004); 1309 $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008); 1310 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); 1311 $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); 1248 1312 1249 if ($atom_structure['time_scale'] == 0) { 1250 $this->error('Corrupt Quicktime file: mvhd.time_scale == zero'); 1251 return false; 1252 } 1253 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); 1254 $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); 1255 $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); 1256 $info['quicktime']['display_scale'] = $atom_structure['matrix_a']; 1257 $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; 1258 break; 1313 // https://www.getid3.org/phpBB3/viewtopic.php?t=1908 1314 // attempt to compute rotation from matrix values 1315 // 2017-Dec-28: uncertain if 90/270 are correctly oriented; values returned by FixedPoint16_16 should perhaps be -1 instead of 65535(?) 1316 $matrixRotation = 0; 1317 switch ($atom_structure['matrix_a'].':'.$atom_structure['matrix_b'].':'.$atom_structure['matrix_c'].':'.$atom_structure['matrix_d']) { 1318 case '1:0:0:1': $matrixRotation = 0; break; 1319 case '0:1:65535:0': $matrixRotation = 90; break; 1320 case '65535:0:0:65535': $matrixRotation = 180; break; 1321 case '0:65535:1:0': $matrixRotation = 270; break; 1322 default: break; 1323 } 1259 1324 1325 // https://www.getid3.org/phpBB3/viewtopic.php?t=2468 1326 // The rotation matrix can appear in the Quicktime file multiple times, at least once for each track, 1327 // and it's possible that only the video track (or, in theory, one of the video tracks) is flagged as 1328 // rotated while the other tracks (e.g. audio) is tagged as rotation=0 (behavior noted on iPhone 8 Plus) 1329 // The correct solution would be to check if the TrackID associated with the rotation matrix is indeed 1330 // a video track (or the main video track) and only set the rotation then, but since information about 1331 // what track is what is not trivially there to be examined, the lazy solution is to set the rotation 1332 // if it is found to be nonzero, on the assumption that tracks that don't need it will have rotation set 1333 // to zero (and be effectively ignored) and the video track will have rotation set correctly, which will 1334 // either be zero and automatically correct, or nonzero and be set correctly. 1335 if (!isset($info['video']['rotate']) || (($info['video']['rotate'] == 0) && ($matrixRotation > 0))) { 1336 $info['quicktime']['video']['rotate'] = $info['video']['rotate'] = $matrixRotation; 1337 } 1260 1338 1261 case 'tkhd': // TracK HeaDer atom 1262 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1263 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1264 $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1265 $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); 1266 $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); 1267 $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); 1268 $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); 1269 $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8)); 1270 $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2)); 1271 $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2)); 1272 $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2)); 1273 $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2)); 1274 // http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html 1275 // http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737 1276 $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); 1277 $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4)); 1278 $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4)); 1279 $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); 1280 $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4)); 1281 $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4)); 1282 $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); 1283 $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4)); 1284 $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4)); 1285 $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4)); 1286 $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4)); 1287 $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001); 1288 $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002); 1289 $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004); 1290 $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008); 1291 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); 1292 $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); 1293 1294 if ($atom_structure['flags']['enabled'] == 1) { 1295 if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) { 1296 $info['video']['resolution_x'] = $atom_structure['width']; 1297 $info['video']['resolution_y'] = $atom_structure['height']; 1339 if ($atom_structure['flags']['enabled'] == 1) { 1340 if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) { 1341 $info['video']['resolution_x'] = $atom_structure['width']; 1342 $info['video']['resolution_y'] = $atom_structure['height']; 1343 } 1344 $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']); 1345 $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']); 1346 $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; 1347 $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; 1348 } else { 1349 // see: https://www.getid3.org/phpBB3/viewtopic.php?t=1295 1350 //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); } 1351 //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); } 1352 //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); } 1298 1353 } 1299 $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']); 1300 $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']); 1301 $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; 1302 $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; 1303 } else { 1304 // see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295 1305 //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); } 1306 //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); } 1307 //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); } 1308 } 1309 break; 1354 break; 1310 1355 1311 1356 1312 case 'iods': // Initial Object DeScriptor atom 1313 // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h 1314 // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html 1315 $offset = 0; 1316 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1317 $offset += 1; 1318 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3)); 1319 $offset += 3; 1320 $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1321 $offset += 1; 1322 $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); 1323 //$offset already adjusted by quicktime_read_mp4_descr_length() 1324 $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); 1325 $offset += 2; 1326 $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1327 $offset += 1; 1328 $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1329 $offset += 1; 1330 $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1331 $offset += 1; 1332 $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1333 $offset += 1; 1334 $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1335 $offset += 1; 1336 1337 $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields 1338 for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) { 1339 $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1357 case 'iods': // Initial Object DeScriptor atom 1358 // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h 1359 // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html 1360 $offset = 0; 1361 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1340 1362 $offset += 1; 1341 $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); 1363 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3)); 1364 $offset += 3; 1365 $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1366 $offset += 1; 1367 $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); 1342 1368 //$offset already adjusted by quicktime_read_mp4_descr_length() 1343 $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); 1344 $offset += 4; 1345 } 1369 $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); 1370 $offset += 2; 1371 $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1372 $offset += 1; 1373 $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1374 $offset += 1; 1375 $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1376 $offset += 1; 1377 $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1378 $offset += 1; 1379 $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1380 $offset += 1; 1346 1381 1347 $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']); 1348 $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']); 1349 break; 1382 $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields 1383 for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) { 1384 $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); 1385 $offset += 1; 1386 $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); 1387 //$offset already adjusted by quicktime_read_mp4_descr_length() 1388 $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); 1389 $offset += 4; 1390 } 1350 1391 1351 case 'ftyp': // FileTYPe (?) atom (for MP4 it seems) 1352 $atom_structure['signature'] = substr($atom_data, 0, 4); 1353 $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1354 $atom_structure['fourcc'] = substr($atom_data, 8, 4); 1355 break; 1392 $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']); 1393 $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']); 1394 break; 1356 1395 1357 case 'mdat': // Media DATa atom 1358 // 'mdat' contains the actual data for the audio/video, possibly also subtitles 1396 case 'ftyp': // FileTYPe (?) atom (for MP4 it seems) 1397 $atom_structure['signature'] = substr($atom_data, 0, 4); 1398 $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1399 $atom_structure['fourcc'] = substr($atom_data, 8, 4); 1400 break; 1359 1401 1360 /* due to lack of known documentation, this is a kludge implementation. If you know of documentation on how mdat is properly structed, please send it to info@getid3.org */ 1402 case 'mdat': // Media DATa atom 1403 // 'mdat' contains the actual data for the audio/video, possibly also subtitles 1361 1404 1362 // first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?) 1363 $mdat_offset = 0; 1364 while (true) { 1365 if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') { 1366 $mdat_offset += 8; 1367 } elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') { 1368 $mdat_offset += 8; 1369 } else { 1370 break; 1405 /* due to lack of known documentation, this is a kludge implementation. If you know of documentation on how mdat is properly structed, please send it to info@getid3.org */ 1406 1407 // first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?) 1408 $mdat_offset = 0; 1409 while (true) { 1410 if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') { 1411 $mdat_offset += 8; 1412 } elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') { 1413 $mdat_offset += 8; 1414 } else { 1415 break; 1416 } 1371 1417 } 1372 } 1418 if (substr($atom_data, $mdat_offset, 4) == 'GPRO') { 1419 $GOPRO_chunk_length = getid3_lib::LittleEndian2Int(substr($atom_data, $mdat_offset + 4, 4)); 1420 $GOPRO_offset = 8; 1421 $atom_structure['GPRO']['raw'] = substr($atom_data, $mdat_offset + 8, $GOPRO_chunk_length - 8); 1422 $atom_structure['GPRO']['firmware'] = substr($atom_structure['GPRO']['raw'], 0, 15); 1423 $atom_structure['GPRO']['unknown1'] = substr($atom_structure['GPRO']['raw'], 15, 16); 1424 $atom_structure['GPRO']['unknown2'] = substr($atom_structure['GPRO']['raw'], 31, 32); 1425 $atom_structure['GPRO']['unknown3'] = substr($atom_structure['GPRO']['raw'], 63, 16); 1426 $atom_structure['GPRO']['camera'] = substr($atom_structure['GPRO']['raw'], 79, 32); 1427 $info['quicktime']['camera']['model'] = rtrim($atom_structure['GPRO']['camera'], "\x00"); 1428 } 1373 1429 1374 // check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field1375 while (($mdat_offset < (strlen($atom_data) - 8))1376 && ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))1377 && ($chapter_string_length < 1000)1378 && ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))1379 && preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) {1380 list($dummy, $chapter_string_length_hex, $chapter_string) = $chapter_matches;1381 $mdat_offset += (2 + $chapter_string_length);1382 @$info['quicktime']['comments']['chapters'][] = $chapter_string;1430 // check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field 1431 while (($mdat_offset < (strlen($atom_data) - 8)) 1432 && ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2))) 1433 && ($chapter_string_length < 1000) 1434 && ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2)) 1435 && preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) { 1436 list($dummy, $chapter_string_length_hex, $chapter_string) = $chapter_matches; 1437 $mdat_offset += (2 + $chapter_string_length); 1438 @$info['quicktime']['comments']['chapters'][] = $chapter_string; 1383 1439 1384 // "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled)1385 if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-81386 $mdat_offset += 12;1387 }1388 }1440 // "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled) 1441 if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-8 1442 $mdat_offset += 12; 1443 } 1444 } 1389 1445 1446 if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) { 1390 1447 1391 if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) { 1448 $info['avdataoffset'] = $atom_structure['offset'] + 8; // $info['quicktime'][$atomname]['offset'] + 8; 1449 $OldAVDataEnd = $info['avdataend']; 1450 $info['avdataend'] = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size']; 1392 1451 1393 $info['avdataoffset'] = $atom_structure['offset'] + 8; // $info['quicktime'][$atomname]['offset'] + 8; 1394 $OldAVDataEnd = $info['avdataend']; 1395 $info['avdataend'] = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size']; 1396 1397 $getid3_temp = new getID3(); 1398 $getid3_temp->openfile($this->getid3->filename); 1399 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1400 $getid3_temp->info['avdataend'] = $info['avdataend']; 1401 $getid3_mp3 = new getid3_mp3($getid3_temp); 1402 if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode($this->fread(4)))) { 1403 $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false); 1404 if (!empty($getid3_temp->info['warning'])) { 1405 foreach ($getid3_temp->info['warning'] as $value) { 1406 $this->warning($value); 1452 $getid3_temp = new getID3(); 1453 $getid3_temp->openfile($this->getid3->filename); 1454 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1455 $getid3_temp->info['avdataend'] = $info['avdataend']; 1456 $getid3_mp3 = new getid3_mp3($getid3_temp); 1457 if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode($this->fread(4)))) { 1458 $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false); 1459 if (!empty($getid3_temp->info['warning'])) { 1460 foreach ($getid3_temp->info['warning'] as $value) { 1461 $this->warning($value); 1462 } 1407 1463 } 1408 }1409 if (!empty($getid3_temp->info['mpeg'])) {1410 $info['mpeg'] = $getid3_temp->info['mpeg'];1411 if (isset($info['mpeg']['audio'])) {1412 $info['audio']['dataformat'] = 'mp3';1413 $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));1414 $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];1415 $info['audio']['channels'] = $info['mpeg']['audio']['channels'];1416 $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];1417 $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);1418 $info['bitrate'] = $info['audio']['bitrate'];1464 if (!empty($getid3_temp->info['mpeg'])) { 1465 $info['mpeg'] = $getid3_temp->info['mpeg']; 1466 if (isset($info['mpeg']['audio'])) { 1467 $info['audio']['dataformat'] = 'mp3'; 1468 $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3'))); 1469 $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; 1470 $info['audio']['channels'] = $info['mpeg']['audio']['channels']; 1471 $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; 1472 $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); 1473 $info['bitrate'] = $info['audio']['bitrate']; 1474 } 1419 1475 } 1420 1476 } 1477 unset($getid3_mp3, $getid3_temp); 1478 $info['avdataend'] = $OldAVDataEnd; 1479 unset($OldAVDataEnd); 1480 1421 1481 } 1422 unset($getid3_mp3, $getid3_temp);1423 $info['avdataend'] = $OldAVDataEnd;1424 unset($OldAVDataEnd);1425 1482 1426 } 1483 unset($mdat_offset, $chapter_string_length, $chapter_matches); 1484 break; 1427 1485 1428 unset($mdat_offset, $chapter_string_length, $chapter_matches); 1429 break; 1486 case 'free': // FREE space atom 1487 case 'skip': // SKIP atom 1488 case 'wide': // 64-bit expansion placeholder atom 1489 // 'free', 'skip' and 'wide' are just padding, contains no useful data at all 1430 1490 1431 case 'free': // FREE space atom 1432 case 'skip': // SKIP atom 1433 case 'wide': // 64-bit expansion placeholder atom 1434 // 'free', 'skip' and 'wide' are just padding, contains no useful data at all 1491 // When writing QuickTime files, it is sometimes necessary to update an atom's size. 1492 // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom 1493 // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime 1494 // puts an 8-byte placeholder atom before any atoms it may have to update the size of. 1495 // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the 1496 // placeholder atom can be overwritten to obtain the necessary 8 extra bytes. 1497 // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ). 1498 break; 1435 1499 1436 // When writing QuickTime files, it is sometimes necessary to update an atom's size.1437 // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom1438 // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime1439 // puts an 8-byte placeholder atom before any atoms it may have to update the size of.1440 // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the1441 // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.1442 // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).1443 break;1444 1500 1501 case 'nsav': // NoSAVe atom 1502 // http://developer.apple.com/technotes/tn/tn2038.html 1503 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1504 break; 1445 1505 1446 case 'nsav': // NoSAVe atom 1447 // http://developer.apple.com/technotes/tn/tn2038.html 1448 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1449 break; 1506 case 'ctyp': // Controller TYPe atom (seen on QTVR) 1507 // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt 1508 // some controller names are: 1509 // 0x00 + 'std' for linear movie 1510 // 'none' for no controls 1511 $atom_structure['ctyp'] = substr($atom_data, 0, 4); 1512 $info['quicktime']['controller'] = $atom_structure['ctyp']; 1513 switch ($atom_structure['ctyp']) { 1514 case 'qtvr': 1515 $info['video']['dataformat'] = 'quicktimevr'; 1516 break; 1517 } 1518 break; 1450 1519 1451 case 'ctyp': // Controller TYPe atom (seen on QTVR) 1452 // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt 1453 // some controller names are: 1454 // 0x00 + 'std' for linear movie 1455 // 'none' for no controls 1456 $atom_structure['ctyp'] = substr($atom_data, 0, 4); 1457 $info['quicktime']['controller'] = $atom_structure['ctyp']; 1458 switch ($atom_structure['ctyp']) { 1459 case 'qtvr': 1460 $info['video']['dataformat'] = 'quicktimevr'; 1461 break; 1462 } 1463 break; 1520 case 'pano': // PANOrama track (seen on QTVR) 1521 $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1522 break; 1464 1523 1465 case 'pano': // PANOrama track (seen on QTVR) 1466 $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1467 break; 1524 case 'hint': // HINT track 1525 case 'hinf': // 1526 case 'hinv': // 1527 case 'hnti': // 1528 $info['quicktime']['hinting'] = true; 1529 break; 1468 1530 1469 case 'hint': // HINT track 1470 case 'hinf': // 1471 case 'hinv': // 1472 case 'hnti': // 1473 $info['quicktime']['hinting'] = true; 1474 break; 1531 case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR) 1532 for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) { 1533 $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4)); 1534 } 1535 break; 1475 1536 1476 case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)1477 for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {1478 $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));1479 }1480 break;1481 1537 1538 // Observed-but-not-handled atom types are just listed here to prevent warnings being generated 1539 case 'FXTC': // Something to do with Adobe After Effects (?) 1540 case 'PrmA': 1541 case 'code': 1542 case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html 1543 case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html 1544 // tapt seems to be used to compute the video size [https://www.getid3.org/phpBB3/viewtopic.php?t=838] 1545 // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html 1546 // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html 1547 case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1548 case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1549 case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1550 case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1551 //$atom_structure['data'] = $atom_data; 1552 break; 1482 1553 1483 // Observed-but-not-handled atom types are just listed here to prevent warnings being generated 1484 case 'FXTC': // Something to do with Adobe After Effects (?) 1485 case 'PrmA': 1486 case 'code': 1487 case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html 1488 case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html 1489 // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838] 1490 // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html 1491 // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html 1492 case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1493 case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1494 case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1495 case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html 1496 //$atom_structure['data'] = $atom_data; 1497 break; 1554 case "\xA9".'xyz': // GPS latitude+longitude+altitude 1555 $atom_structure['data'] = $atom_data; 1556 if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) { 1557 @list($all, $latitude, $longitude, $altitude) = $matches; 1558 $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude); 1559 $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude); 1560 if (!empty($altitude)) { 1561 $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude); 1562 } 1563 } else { 1564 $this->warning('QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.'); 1565 } 1566 break; 1498 1567 1499 case "\xA9".'xyz': // GPS latitude+longitude+altitude 1500 $atom_structure['data'] = $atom_data; 1501 if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) { 1502 @list($all, $latitude, $longitude, $altitude) = $matches; 1503 $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude); 1504 $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude); 1505 if (!empty($altitude)) { 1506 $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude); 1568 case 'NCDT': 1569 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1570 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 1571 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); 1572 break; 1573 case 'NCTH': // Nikon Camera THumbnail image 1574 case 'NCVW': // Nikon Camera preVieW image 1575 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1576 if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) { 1577 $atom_structure['data'] = $atom_data; 1578 $atom_structure['image_mime'] = 'image/jpeg'; 1579 $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image')); 1580 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']); 1507 1581 } 1508 } else { 1509 $this->warning('QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.'); 1510 } 1511 break; 1512 1513 case 'NCDT': 1514 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1515 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 1516 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); 1517 break; 1518 case 'NCTH': // Nikon Camera THumbnail image 1519 case 'NCVW': // Nikon Camera preVieW image 1520 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1521 if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) { 1582 break; 1583 case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG 1584 $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data); 1585 break; 1586 case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1587 case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1588 case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html 1522 1589 $atom_structure['data'] = $atom_data; 1523 $atom_structure['image_mime'] = 'image/jpeg'; 1524 $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image')); 1525 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']); 1526 } 1527 break; 1528 case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG 1529 $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data); 1530 break; 1531 case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1532 case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1533 case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html 1534 $atom_structure['data'] = $atom_data; 1535 break; 1590 break; 1536 1591 1537 case "\x00\x00\x00\x00":1538 // some kind of metacontainer, may contain a big data dump such as:1539 // 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 41540 // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt1592 case "\x00\x00\x00\x00": 1593 // some kind of metacontainer, may contain a big data dump such as: 1594 // 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 1595 // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt 1541 1596 1542 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1543 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));1544 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);1545 //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);1546 break;1597 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1598 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1599 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 1600 //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 1601 break; 1547 1602 1548 case 'meta': // METAdata atom1549 // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html1603 case 'meta': // METAdata atom 1604 // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html 1550 1605 1551 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1552 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));1553 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);1554 break;1606 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1607 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1608 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 1609 break; 1555 1610 1556 case 'data': // metaDATA atom1557 static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other1558 // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data1559 $atom_structure['language'] = substr($atom_data, 4 + 0, 2);1560 $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));1561 $atom_structure['data'] = substr($atom_data, 4 + 4);1562 $atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++];1611 case 'data': // metaDATA atom 1612 static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other 1613 // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data 1614 $atom_structure['language'] = substr($atom_data, 4 + 0, 2); 1615 $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2)); 1616 $atom_structure['data'] = substr($atom_data, 4 + 4); 1617 $atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++]; 1563 1618 1564 if ($atom_structure['key_name'] && $atom_structure['data']) {1565 @$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data'];1566 }1567 break;1619 if ($atom_structure['key_name'] && $atom_structure['data']) { 1620 @$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data']; 1621 } 1622 break; 1568 1623 1569 case 'keys': // KEYS that may be present in the metadata atom.1570 // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW211571 // The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom.1572 // This list is indexed starting with 1; 0 is a reserved index value. The metadata item keys atom is a full atom with an atom type of "keys".1573 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1574 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));1575 $atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));1576 $keys_atom_offset = 8;1577 for ($i = 1; $i <= $atom_structure['entry_count']; $i++) {1578 $atom_structure['keys'][$i]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4));1579 $atom_structure['keys'][$i]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4);1580 $atom_structure['keys'][$i]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8);1581 $keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace1624 case 'keys': // KEYS that may be present in the metadata atom. 1625 // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21 1626 // The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom. 1627 // This list is indexed starting with 1; 0 is a reserved index value. The metadata item keys atom is a full atom with an atom type of "keys". 1628 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1629 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1630 $atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1631 $keys_atom_offset = 8; 1632 for ($i = 1; $i <= $atom_structure['entry_count']; $i++) { 1633 $atom_structure['keys'][$i]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4)); 1634 $atom_structure['keys'][$i]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4); 1635 $atom_structure['keys'][$i]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8); 1636 $keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace 1582 1637 1583 $info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value'];1584 }1585 break;1638 $info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value']; 1639 } 1640 break; 1586 1641 1587 case 'gps ':1588 // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-2917301589 // The 'gps ' contains simple look up table made up of 8byte rows, that point to the 'free' atoms that contains the actual GPS data.1590 // The first row is version/metadata/notsure, I skip that.1591 // The following rows consist of 4byte address (absolute) and 4byte size (0x1000), these point to the GPS data in the file.1642 case 'gps ': 1643 // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730 1644 // The 'gps ' contains simple look up table made up of 8byte rows, that point to the 'free' atoms that contains the actual GPS data. 1645 // The first row is version/metadata/notsure, I skip that. 1646 // The following rows consist of 4byte address (absolute) and 4byte size (0x1000), these point to the GPS data in the file. 1592 1647 1593 $GPS_rowsize = 8; // 4 bytes for offset, 4 bytes for size 1594 if (strlen($atom_data) > 0) { 1595 if ((strlen($atom_data) % $GPS_rowsize) == 0) { 1596 $atom_structure['gps_toc'] = array(); 1597 foreach (str_split($atom_data, $GPS_rowsize) as $counter => $datapair) { 1598 $atom_structure['gps_toc'][] = unpack('Noffset/Nsize', substr($atom_data, $counter * $GPS_rowsize, $GPS_rowsize)); 1599 } 1600 1601 $atom_structure['gps_entries'] = array(); 1602 $previous_offset = $this->ftell(); 1603 foreach ($atom_structure['gps_toc'] as $key => $gps_pointer) { 1604 if ($key == 0) { 1605 // "The first row is version/metadata/notsure, I skip that." 1606 continue; 1648 $GPS_rowsize = 8; // 4 bytes for offset, 4 bytes for size 1649 if (strlen($atom_data) > 0) { 1650 if ((strlen($atom_data) % $GPS_rowsize) == 0) { 1651 $atom_structure['gps_toc'] = array(); 1652 foreach (str_split($atom_data, $GPS_rowsize) as $counter => $datapair) { 1653 $atom_structure['gps_toc'][] = unpack('Noffset/Nsize', substr($atom_data, $counter * $GPS_rowsize, $GPS_rowsize)); 1607 1654 } 1608 $this->fseek($gps_pointer['offset']);1609 $GPS_free_data = $this->fread($gps_pointer['size']);1610 1655 1611 /* 1612 // 2017-05-10: I see some of the data, notably the Hour-Minute-Second, but cannot reconcile the rest of the data. However, the NMEA "GPRMC" line is there and relatively easy to parse, so I'm using that instead 1656 $atom_structure['gps_entries'] = array(); 1657 $previous_offset = $this->ftell(); 1658 foreach ($atom_structure['gps_toc'] as $key => $gps_pointer) { 1659 if ($key == 0) { 1660 // "The first row is version/metadata/notsure, I skip that." 1661 continue; 1662 } 1663 $this->fseek($gps_pointer['offset']); 1664 $GPS_free_data = $this->fread($gps_pointer['size']); 1613 1665 1614 // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730 1615 // The structure of the GPS data atom (the 'free' atoms mentioned above) is following: 1616 // hour,minute,second,year,month,day,active,latitude_b,longitude_b,unknown2,latitude,longitude,speed = struct.unpack_from('<IIIIIIssssfff',data, 48) 1617 // For those unfamiliar with python struct: 1618 // I = int 1619 // s = is string (size 1, in this case) 1620 // f = float 1666 /* 1667 // 2017-05-10: I see some of the data, notably the Hour-Minute-Second, but cannot reconcile the rest of the data. However, the NMEA "GPRMC" line is there and relatively easy to parse, so I'm using that instead 1621 1668 1622 //$atom_structure['gps_entries'][$key] = unpack('Vhour/Vminute/Vsecond/Vyear/Vmonth/Vday/Vactive/Vlatitude_b/Vlongitude_b/Vunknown2/flatitude/flongitude/fspeed', substr($GPS_free_data, 48)); 1623 */ 1669 // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730 1670 // The structure of the GPS data atom (the 'free' atoms mentioned above) is following: 1671 // hour,minute,second,year,month,day,active,latitude_b,longitude_b,unknown2,latitude,longitude,speed = struct.unpack_from('<IIIIIIssssfff',data, 48) 1672 // For those unfamiliar with python struct: 1673 // I = int 1674 // s = is string (size 1, in this case) 1675 // f = float 1624 1676 1625 // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 1626 // $GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67 1627 // $GPRMC,002454,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3F 1628 // $GPRMC,094347.000,A,5342.0061,N,00737.9908,W,0.01,156.75,140217,,,A*7D 1629 if (preg_match('#\\$GPRMC,([0-9\\.]*),([AV]),([0-9\\.]*),([NS]),([0-9\\.]*),([EW]),([0-9\\.]*),([0-9\\.]*),([0-9]*),([0-9\\.]*),([EW]?)(,[A])?(\\*[0-9A-F]{2})#', $GPS_free_data, $matches)) { 1630 $GPS_this_GPRMC = array(); 1631 list( 1632 $GPS_this_GPRMC['raw']['gprmc'], 1633 $GPS_this_GPRMC['raw']['timestamp'], 1634 $GPS_this_GPRMC['raw']['status'], 1635 $GPS_this_GPRMC['raw']['latitude'], 1636 $GPS_this_GPRMC['raw']['latitude_direction'], 1637 $GPS_this_GPRMC['raw']['longitude'], 1638 $GPS_this_GPRMC['raw']['longitude_direction'], 1639 $GPS_this_GPRMC['raw']['knots'], 1640 $GPS_this_GPRMC['raw']['angle'], 1641 $GPS_this_GPRMC['raw']['datestamp'], 1642 $GPS_this_GPRMC['raw']['variation'], 1643 $GPS_this_GPRMC['raw']['variation_direction'], 1644 $dummy, 1645 $GPS_this_GPRMC['raw']['checksum'], 1646 ) = $matches; 1677 //$atom_structure['gps_entries'][$key] = unpack('Vhour/Vminute/Vsecond/Vyear/Vmonth/Vday/Vactive/Vlatitude_b/Vlongitude_b/Vunknown2/flatitude/flongitude/fspeed', substr($GPS_free_data, 48)); 1678 */ 1647 1679 1648 $hour = substr($GPS_this_GPRMC['raw']['timestamp'], 0, 2); 1649 $minute = substr($GPS_this_GPRMC['raw']['timestamp'], 2, 2); 1650 $second = substr($GPS_this_GPRMC['raw']['timestamp'], 4, 2); 1651 $ms = substr($GPS_this_GPRMC['raw']['timestamp'], 6); // may contain decimal seconds 1652 $day = substr($GPS_this_GPRMC['raw']['datestamp'], 0, 2); 1653 $month = substr($GPS_this_GPRMC['raw']['datestamp'], 2, 2); 1654 $year = substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2); 1655 $year += (($year > 90) ? 1900 : 2000); // complete lack of foresight: datestamps are stored with 2-digit years, take best guess 1656 $GPS_this_GPRMC['timestamp'] = $year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second.$ms; 1680 // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 1681 // $GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67 1682 // $GPRMC,002454,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3F 1683 // $GPRMC,094347.000,A,5342.0061,N,00737.9908,W,0.01,156.75,140217,,,A*7D 1684 if (preg_match('#\\$GPRMC,([0-9\\.]*),([AV]),([0-9\\.]*),([NS]),([0-9\\.]*),([EW]),([0-9\\.]*),([0-9\\.]*),([0-9]*),([0-9\\.]*),([EW]?)(,[A])?(\\*[0-9A-F]{2})#', $GPS_free_data, $matches)) { 1685 $GPS_this_GPRMC = array(); 1686 list( 1687 $GPS_this_GPRMC['raw']['gprmc'], 1688 $GPS_this_GPRMC['raw']['timestamp'], 1689 $GPS_this_GPRMC['raw']['status'], 1690 $GPS_this_GPRMC['raw']['latitude'], 1691 $GPS_this_GPRMC['raw']['latitude_direction'], 1692 $GPS_this_GPRMC['raw']['longitude'], 1693 $GPS_this_GPRMC['raw']['longitude_direction'], 1694 $GPS_this_GPRMC['raw']['knots'], 1695 $GPS_this_GPRMC['raw']['angle'], 1696 $GPS_this_GPRMC['raw']['datestamp'], 1697 $GPS_this_GPRMC['raw']['variation'], 1698 $GPS_this_GPRMC['raw']['variation_direction'], 1699 $dummy, 1700 $GPS_this_GPRMC['raw']['checksum'], 1701 ) = $matches; 1657 1702 1658 $GPS_this_GPRMC['active'] = ($GPS_this_GPRMC['raw']['status'] == 'A'); // A=Active,V=Void 1703 $hour = substr($GPS_this_GPRMC['raw']['timestamp'], 0, 2); 1704 $minute = substr($GPS_this_GPRMC['raw']['timestamp'], 2, 2); 1705 $second = substr($GPS_this_GPRMC['raw']['timestamp'], 4, 2); 1706 $ms = substr($GPS_this_GPRMC['raw']['timestamp'], 6); // may contain decimal seconds 1707 $day = substr($GPS_this_GPRMC['raw']['datestamp'], 0, 2); 1708 $month = substr($GPS_this_GPRMC['raw']['datestamp'], 2, 2); 1709 $year = substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2); 1710 $year += (($year > 90) ? 1900 : 2000); // complete lack of foresight: datestamps are stored with 2-digit years, take best guess 1711 $GPS_this_GPRMC['timestamp'] = $year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second.$ms; 1659 1712 1660 foreach (array('latitude','longitude') as $latlon) { 1661 preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches); 1662 list($dummy, $deg, $min) = $matches; 1663 $GPS_this_GPRMC[$latlon] = $deg + ($min / 60); 1664 } 1665 $GPS_this_GPRMC['latitude'] *= (($GPS_this_GPRMC['raw']['latitude_direction'] == 'S') ? -1 : 1); 1666 $GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1); 1713 $GPS_this_GPRMC['active'] = ($GPS_this_GPRMC['raw']['status'] == 'A'); // A=Active,V=Void 1667 1714 1668 $GPS_this_GPRMC['heading'] = $GPS_this_GPRMC['raw']['angle']; 1669 $GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots']; 1670 $GPS_this_GPRMC['speed_kmh'] = $GPS_this_GPRMC['raw']['knots'] * 1.852; 1671 if ($GPS_this_GPRMC['raw']['variation']) { 1672 $GPS_this_GPRMC['variation'] = $GPS_this_GPRMC['raw']['variation']; 1673 $GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1); 1715 foreach (array('latitude','longitude') as $latlon) { 1716 preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches); 1717 list($dummy, $deg, $min) = $matches; 1718 $GPS_this_GPRMC[$latlon] = $deg + ($min / 60); 1719 } 1720 $GPS_this_GPRMC['latitude'] *= (($GPS_this_GPRMC['raw']['latitude_direction'] == 'S') ? -1 : 1); 1721 $GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1); 1722 1723 $GPS_this_GPRMC['heading'] = $GPS_this_GPRMC['raw']['angle']; 1724 $GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots']; 1725 $GPS_this_GPRMC['speed_kmh'] = $GPS_this_GPRMC['raw']['knots'] * 1.852; 1726 if ($GPS_this_GPRMC['raw']['variation']) { 1727 $GPS_this_GPRMC['variation'] = $GPS_this_GPRMC['raw']['variation']; 1728 $GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1); 1729 } 1730 1731 $atom_structure['gps_entries'][$key] = $GPS_this_GPRMC; 1732 1733 @$info['quicktime']['gps_track'][$GPS_this_GPRMC['timestamp']] = array( 1734 'latitude' => (float) $GPS_this_GPRMC['latitude'], 1735 'longitude' => (float) $GPS_this_GPRMC['longitude'], 1736 'speed_kmh' => (float) $GPS_this_GPRMC['speed_kmh'], 1737 'heading' => (float) $GPS_this_GPRMC['heading'], 1738 ); 1739 1740 } else { 1741 $this->warning('Unhandled GPS format in "free" atom at offset '.$gps_pointer['offset']); 1674 1742 } 1743 } 1744 $this->fseek($previous_offset); 1675 1745 1676 $atom_structure['gps_entries'][$key] = $GPS_this_GPRMC; 1746 } else { 1747 $this->warning('QuickTime atom "'.$atomname.'" is not mod-8 bytes long ('.$atomsize.' bytes) at offset '.$baseoffset); 1748 } 1749 } else { 1750 $this->warning('QuickTime atom "'.$atomname.'" is zero bytes long at offset '.$baseoffset); 1751 } 1752 break; 1677 1753 1678 @$info['quicktime']['gps_track'][$GPS_this_GPRMC['timestamp']] = array( 1679 'latitude' => $GPS_this_GPRMC['latitude'], 1680 'longitude' => $GPS_this_GPRMC['longitude'], 1681 'speed_kmh' => $GPS_this_GPRMC['speed_kmh'], 1682 'heading' => $GPS_this_GPRMC['heading'], 1683 ); 1754 case 'loci':// 3GP location (El Loco) 1755 $loffset = 0; 1756 $info['quicktime']['comments']['gps_flags'] = array( getid3_lib::BigEndian2Int(substr($atom_data, 0, 4))); 1757 $info['quicktime']['comments']['gps_lang'] = array( getid3_lib::BigEndian2Int(substr($atom_data, 4, 2))); 1758 $info['quicktime']['comments']['gps_location'] = array( $this->LociString(substr($atom_data, 6), $loffset)); 1759 $loci_data = substr($atom_data, 6 + $loffset); 1760 $info['quicktime']['comments']['gps_role'] = array( getid3_lib::BigEndian2Int(substr($loci_data, 0, 1))); 1761 $info['quicktime']['comments']['gps_longitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4))); 1762 $info['quicktime']['comments']['gps_latitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4))); 1763 $info['quicktime']['comments']['gps_altitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4))); 1764 $info['quicktime']['comments']['gps_body'] = array( $this->LociString(substr($loci_data, 13 ), $loffset)); 1765 $info['quicktime']['comments']['gps_notes'] = array( $this->LociString(substr($loci_data, 13 + $loffset), $loffset)); 1766 break; 1684 1767 1685 } else { 1686 $this->warning('Unhandled GPS format in "free" atom at offset '.$gps_pointer['offset']); 1768 case 'chpl': // CHaPter List 1769 // https://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf 1770 $chpl_version = getid3_lib::BigEndian2Int(substr($atom_data, 4, 1)); // Expected to be 0 1771 $chpl_flags = getid3_lib::BigEndian2Int(substr($atom_data, 5, 3)); // Reserved, set to 0 1772 $chpl_count = getid3_lib::BigEndian2Int(substr($atom_data, 8, 1)); 1773 $chpl_offset = 9; 1774 for ($i = 0; $i < $chpl_count; $i++) { 1775 if (($chpl_offset + 9) >= strlen($atom_data)) { 1776 $this->warning('QuickTime chapter '.$i.' extends beyond end of "chpl" atom'); 1777 break; 1778 } 1779 $info['quicktime']['chapters'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 8)) / 10000000; // timestamps are stored as 100-nanosecond units 1780 $chpl_offset += 8; 1781 $chpl_title_size = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 1)); 1782 $chpl_offset += 1; 1783 $info['quicktime']['chapters'][$i]['title'] = substr($atom_data, $chpl_offset, $chpl_title_size); 1784 $chpl_offset += $chpl_title_size; 1785 } 1786 break; 1787 1788 case 'FIRM': // FIRMware version(?), seen on GoPro Hero4 1789 $info['quicktime']['camera']['firmware'] = $atom_data; 1790 break; 1791 1792 case 'CAME': // FIRMware version(?), seen on GoPro Hero4 1793 $info['quicktime']['camera']['serial_hash'] = unpack('H*', $atom_data); 1794 break; 1795 1796 case 'dscp': 1797 case 'rcif': 1798 // https://www.getid3.org/phpBB3/viewtopic.php?t=1908 1799 if (substr($atom_data, 0, 7) == "\x00\x00\x00\x00\x55\xC4".'{') { 1800 if ($json_decoded = @json_decode(rtrim(substr($atom_data, 6), "\x00"), true)) { 1801 $info['quicktime']['camera'][$atomname] = $json_decoded; 1802 if (($atomname == 'rcif') && isset($info['quicktime']['camera']['rcif']['wxcamera']['rotate'])) { 1803 $info['video']['rotate'] = $info['quicktime']['video']['rotate'] = $info['quicktime']['camera']['rcif']['wxcamera']['rotate']; 1687 1804 } 1805 } else { 1806 $this->warning('Failed to JSON decode atom "'.$atomname.'"'); 1807 $atom_structure['data'] = $atom_data; 1688 1808 } 1689 $this->fseek($previous_offset); 1690 1809 unset($json_decoded); 1691 1810 } else { 1692 $this->warning('QuickTime atom "'.$atomname.'" is not mod-8 bytes long ('.$atomsize.' bytes) at offset '.$baseoffset); 1811 $this->warning('Expecting 55 C4 7B at start of atom "'.$atomname.'", found '.getid3_lib::PrintHexBytes(substr($atom_data, 4, 3)).' instead'); 1812 $atom_structure['data'] = $atom_data; 1693 1813 } 1694 } else { 1695 $this->warning('QuickTime atom "'.$atomname.'" is zero bytes long at offset '.$baseoffset); 1696 } 1697 break; 1814 break; 1698 1815 1699 case 'loci':// 3GP location (El Loco) 1700 $info['quicktime']['comments']['gps_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1701 $info['quicktime']['comments']['gps_lang'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 1702 $loffset = 0; 1703 $info['quicktime']['comments']['gps_location'] = $this->LociString(substr($atom_data, 6), $loffset); 1704 $loci_data=substr($atom_data, 6 + $loffset); 1705 $info['quicktime']['comments']['gps_role'] = getid3_lib::BigEndian2Int(substr($loci_data, 0, 1)); 1706 $info['quicktime']['comments']['gps_longitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4)); 1707 $info['quicktime']['comments']['gps_latitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4)); 1708 $info['quicktime']['comments']['gps_altitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4)); 1709 $info['quicktime']['comments']['gps_body'] = $this->LociString(substr($loci_data, 13), $loffset); 1710 $info['quicktime']['comments']['gps_notes'] = $this->LociString(substr($loci_data, 13 + $loffset), $loffset); 1711 break; 1816 case 'frea': 1817 // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea 1818 // may contain "scra" (PreviewImage) and/or "thma" (ThumbnailImage) 1819 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); 1820 break; 1821 case 'tima': // subatom to "frea" 1822 // no idea what this does, the one sample file I've seen has a value of 0x00000027 1823 $atom_structure['data'] = $atom_data; 1824 break; 1825 case 'ver ': // subatom to "frea" 1826 // some kind of version number, the one sample file I've seen has a value of "3.00.073" 1827 $atom_structure['data'] = $atom_data; 1828 break; 1829 case 'thma': // subatom to "frea" -- "ThumbnailImage" 1830 // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea 1831 if (strlen($atom_data) > 0) { 1832 $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg'); 1833 } 1834 break; 1835 case 'scra': // subatom to "frea" -- "PreviewImage" 1836 // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea 1837 // but the only sample file I've seen has no useful data here 1838 if (strlen($atom_data) > 0) { 1839 $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg'); 1840 } 1841 break; 1712 1842 1713 default: 1714 $this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset); 1715 $atom_structure['data'] = $atom_data; 1716 break; 1843 1844 default: 1845 $this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).'), '.$atomsize.' bytes at offset '.$baseoffset); 1846 $atom_structure['data'] = $atom_data; 1847 break; 1848 } 1717 1849 } 1718 1850 array_pop($atomHierarchy); 1719 1851 return $atom_structure; 1720 1852 } 1721 1853 1854 /** 1855 * @param string $atom_data 1856 * @param int $baseoffset 1857 * @param array $atomHierarchy 1858 * @param bool $ParseAllPossibleAtoms 1859 * 1860 * @return array|false 1861 */ 1722 1862 public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { 1723 //echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';1724 1863 $atom_structure = false; 1725 1864 $subatomoffset = 0; 1726 1865 $subatomcounter = 0; … … 1741 1880 } 1742 1881 return $atom_structure; 1743 1882 } 1744 1745 $atom_structure[$subatomcounter] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); 1746 1883 $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); 1747 1884 $subatomoffset += $subatomsize; 1748 $subatomcounter++;1749 1885 } 1750 1886 return $atom_structure; 1751 1887 } 1752 1888 1753 1889 /** 1890 * @param string $data 1891 * @param int $offset 1892 * 1893 * @return int 1894 */ 1754 1895 public function quicktime_read_mp4_descr_length($data, &$offset) { 1755 1896 // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html 1756 1897 $num_bytes = 0; … … 1762 1903 return $length; 1763 1904 } 1764 1905 1765 1906 /** 1907 * @param int $languageid 1908 * 1909 * @return string 1910 */ 1766 1911 public function QuicktimeLanguageLookup($languageid) { 1767 1912 // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353 1768 1913 static $QuicktimeLanguageLookup = array(); … … 1900 2045 return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid'); 1901 2046 } 1902 2047 2048 /** 2049 * @param string $codecid 2050 * 2051 * @return string 2052 */ 1903 2053 public function QuicktimeVideoCodecLookup($codecid) { 1904 2054 static $QuicktimeVideoCodecLookup = array(); 1905 2055 if (empty($QuicktimeVideoCodecLookup)) { … … 1959 2109 return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : ''); 1960 2110 } 1961 2111 2112 /** 2113 * @param string $codecid 2114 * 2115 * @return mixed|string 2116 */ 1962 2117 public function QuicktimeAudioCodecLookup($codecid) { 1963 2118 static $QuicktimeAudioCodecLookup = array(); 1964 2119 if (empty($QuicktimeAudioCodecLookup)) { … … 2004 2159 return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : ''); 2005 2160 } 2006 2161 2162 /** 2163 * @param string $compressionid 2164 * 2165 * @return string 2166 */ 2007 2167 public function QuicktimeDCOMLookup($compressionid) { 2008 2168 static $QuicktimeDCOMLookup = array(); 2009 2169 if (empty($QuicktimeDCOMLookup)) { … … 2013 2173 return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : ''); 2014 2174 } 2015 2175 2176 /** 2177 * @param int $colordepthid 2178 * 2179 * @return string 2180 */ 2016 2181 public function QuicktimeColorNameLookup($colordepthid) { 2017 2182 static $QuicktimeColorNameLookup = array(); 2018 2183 if (empty($QuicktimeColorNameLookup)) { … … 2031 2196 return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid'); 2032 2197 } 2033 2198 2199 /** 2200 * @param int $stik 2201 * 2202 * @return string 2203 */ 2034 2204 public function QuicktimeSTIKLookup($stik) { 2035 2205 static $QuicktimeSTIKLookup = array(); 2036 2206 if (empty($QuicktimeSTIKLookup)) { … … 2048 2218 return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid'); 2049 2219 } 2050 2220 2221 /** 2222 * @param int $audio_profile_id 2223 * 2224 * @return string 2225 */ 2051 2226 public function QuicktimeIODSaudioProfileName($audio_profile_id) { 2052 2227 static $QuicktimeIODSaudioProfileNameLookup = array(); 2053 2228 if (empty($QuicktimeIODSaudioProfileNameLookup)) { … … 2107 2282 return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private'); 2108 2283 } 2109 2284 2110 2285 /** 2286 * @param int $video_profile_id 2287 * 2288 * @return string 2289 */ 2111 2290 public function QuicktimeIODSvideoProfileName($video_profile_id) { 2112 2291 static $QuicktimeIODSvideoProfileNameLookup = array(); 2113 2292 if (empty($QuicktimeIODSvideoProfileNameLookup)) { … … 2179 2358 return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile'); 2180 2359 } 2181 2360 2182 2361 /** 2362 * @param int $rtng 2363 * 2364 * @return string 2365 */ 2183 2366 public function QuicktimeContentRatingLookup($rtng) { 2184 2367 static $QuicktimeContentRatingLookup = array(); 2185 2368 if (empty($QuicktimeContentRatingLookup)) { … … 2190 2373 return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid'); 2191 2374 } 2192 2375 2376 /** 2377 * @param int $akid 2378 * 2379 * @return string 2380 */ 2193 2381 public function QuicktimeStoreAccountTypeLookup($akid) { 2194 2382 static $QuicktimeStoreAccountTypeLookup = array(); 2195 2383 if (empty($QuicktimeStoreAccountTypeLookup)) { … … 2199 2387 return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid'); 2200 2388 } 2201 2389 2390 /** 2391 * @param int $sfid 2392 * 2393 * @return string 2394 */ 2202 2395 public function QuicktimeStoreFrontCodeLookup($sfid) { 2203 2396 static $QuicktimeStoreFrontCodeLookup = array(); 2204 2397 if (empty($QuicktimeStoreFrontCodeLookup)) { … … 2228 2421 return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid'); 2229 2422 } 2230 2423 2424 /** 2425 * @param string $atom_data 2426 * 2427 * @return array 2428 */ 2231 2429 public function QuicktimeParseNikonNCTG($atom_data) { 2232 2430 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG 2233 2431 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 … … 2270 2468 ); 2271 2469 2272 2470 $offset = 0; 2471 $data = null; 2273 2472 $datalength = strlen($atom_data); 2274 2473 $parsed = array(); 2275 2474 while ($offset < $datalength) { 2276 //echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';2277 2475 $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4; 2278 2476 $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; 2279 2477 $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; … … 2328 2526 $offset += ($data_size * 2); 2329 2527 break; 2330 2528 default: 2331 echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';2529 echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>'; 2332 2530 break 2; 2333 2531 } 2334 2532 … … 2406 2604 return $parsed; 2407 2605 } 2408 2606 2409 2607 /** 2608 * @param string $keyname 2609 * @param string|array $data 2610 * @param string $boxname 2611 * 2612 * @return bool 2613 */ 2410 2614 public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') { 2411 2615 static $handyatomtranslatorarray = array(); 2412 2616 if (empty($handyatomtranslatorarray)) { … … 2450 2654 $handyatomtranslatorarray["\xA9".'src'] = 'source_credit'; 2451 2655 $handyatomtranslatorarray["\xA9".'swr'] = 'software'; 2452 2656 $handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool'; // iTunes 4.0 2453 $handyatomtranslatorarray["\xA9".'trk'] = 'track ';2657 $handyatomtranslatorarray["\xA9".'trk'] = 'track_number'; 2454 2658 $handyatomtranslatorarray["\xA9".'url'] = 'url'; 2455 2659 $handyatomtranslatorarray["\xA9".'wrn'] = 'warning'; 2456 2660 $handyatomtranslatorarray["\xA9".'wrt'] = 'composer'; … … 2503 2707 $handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id'; 2504 2708 2505 2709 // http://age.hobba.nl/audio/tag_frame_reference.html 2506 $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - http ://www.getid3.org/phpBB3/viewtopic.php?t=13552507 $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - http ://www.getid3.org/phpBB3/viewtopic.php?t=13552710 $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355 2711 $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355 2508 2712 */ 2509 2713 } 2510 2714 $info = &$this->getid3->info; … … 2542 2746 return true; 2543 2747 } 2544 2748 2545 public function LociString($lstring, &$count) { 2546 // Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM 2547 // Also need to return the number of bytes the string occupied so additional fields can be extracted 2548 $len = strlen($lstring); 2549 if ($len == 0) { 2550 $count = 0; 2551 return ''; 2552 } 2553 if ($lstring[0] == "\x00") { 2554 $count = 1; 2555 return ''; 2556 } 2557 //check for BOM 2558 if ($len > 2 && (($lstring[0] == "\xFE" && $lstring[1] == "\xFF") || ($lstring[0] == "\xFF" && $lstring[1] == "\xFE"))) { 2559 //UTF-16 2560 if (preg_match('/(.*)\x00/', $lstring, $lmatches)){ 2561 $count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000 2562 return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]); 2563 } else { 2564 return ''; 2565 } 2566 } else { 2567 //UTF-8 2568 if (preg_match('/(.*)\x00/', $lstring, $lmatches)){ 2569 $count = strlen($lmatches[1]) + 1; //account for trailing \x00 2570 return $lmatches[1]; 2571 }else { 2572 return ''; 2573 } 2749 /** 2750 * @param string $lstring 2751 * @param int $count 2752 * 2753 * @return string 2754 */ 2755 public function LociString($lstring, &$count) { 2756 // Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM 2757 // Also need to return the number of bytes the string occupied so additional fields can be extracted 2758 $len = strlen($lstring); 2759 if ($len == 0) { 2760 $count = 0; 2761 return ''; 2762 } 2763 if ($lstring[0] == "\x00") { 2764 $count = 1; 2765 return ''; 2766 } 2767 // check for BOM 2768 if (($len > 2) && ((($lstring[0] == "\xFE") && ($lstring[1] == "\xFF")) || (($lstring[0] == "\xFF") && ($lstring[1] == "\xFE")))) { 2769 // UTF-16 2770 if (preg_match('/(.*)\x00/', $lstring, $lmatches)) { 2771 $count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000 2772 return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]); 2773 } else { 2774 return ''; 2775 } 2776 } 2777 // UTF-8 2778 if (preg_match('/(.*)\x00/', $lstring, $lmatches)) { 2779 $count = strlen($lmatches[1]) + 1; //account for trailing \x00 2780 return $lmatches[1]; 2781 } 2782 return ''; 2783 } 2574 2784 2575 } 2576 } 2577 2785 /** 2786 * @param string $nullterminatedstring 2787 * 2788 * @return string 2789 */ 2578 2790 public function NoNullString($nullterminatedstring) { 2579 2791 // remove the single null terminator on null terminated strings 2580 2792 if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") { … … 2583 2795 return $nullterminatedstring; 2584 2796 } 2585 2797 2798 /** 2799 * @param string $pascalstring 2800 * 2801 * @return string 2802 */ 2586 2803 public function Pascal2String($pascalstring) { 2587 2804 // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string 2588 2805 return substr($pascalstring, 1); … … 2589 2806 } 2590 2807 2591 2808 2592 /* 2593 // helper functions for m4b audiobook chapters 2594 // code by Steffen Hartmann 2015-Nov-08 2595 */ 2809 /** 2810 * Helper functions for m4b audiobook chapters 2811 * code by Steffen Hartmann 2015-Nov-08. 2812 * 2813 * @param array $info 2814 * @param string $tag 2815 * @param string $history 2816 * @param array $result 2817 */ 2596 2818 public function search_tag_by_key($info, $tag, $history, &$result) { 2597 2819 foreach ($info as $key => $value) { 2598 2820 $key_history = $history.'/'.$key; … … 2606 2828 } 2607 2829 } 2608 2830 2831 /** 2832 * @param array $info 2833 * @param string $k 2834 * @param string $v 2835 * @param string $history 2836 * @param array $result 2837 */ 2609 2838 public function search_tag_by_pair($info, $k, $v, $history, &$result) { 2610 2839 foreach ($info as $key => $value) { 2611 2840 $key_history = $history.'/'.$key; … … 2619 2848 } 2620 2849 } 2621 2850 2851 /** 2852 * @param array $info 2853 * 2854 * @return array 2855 */ 2622 2856 public function quicktime_time_to_sample_table($info) { 2623 2857 $res = array(); 2624 2858 $this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res); … … 2636 2870 return array(); 2637 2871 } 2638 2872 2639 function quicktime_bookmark_time_scale($info) { 2873 /** 2874 * @param array $info 2875 * 2876 * @return int 2877 */ 2878 public function quicktime_bookmark_time_scale($info) { 2640 2879 $time_scale = ''; 2641 2880 $ts_prefix_len = 0; 2642 2881 $res = array(); … … 2647 2886 if (count($stbl_res) > 0) { 2648 2887 $ts_res = array(); 2649 2888 $this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res); 2650 foreach ($ts_res as $ value) {2651 $prefix = substr($ value[0], 0, -12);2889 foreach ($ts_res as $sub_value) { 2890 $prefix = substr($sub_value[0], 0, -12); 2652 2891 if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) { 2653 $time_scale = $ value[1]['time_scale'];2892 $time_scale = $sub_value[1]['time_scale']; 2654 2893 $ts_prefix_len = strlen($prefix); 2655 2894 } 2656 2895 } -
src/wp-includes/ID3/module.audio-video.riff.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio-video.riff.php // 12 12 // module for analyzing RIFF files // … … 27 27 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true); 28 28 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true); 29 29 30 class getid3_riff extends getid3_handler {31 30 class getid3_riff extends getid3_handler 31 { 32 32 protected $container = 'riff'; // default 33 33 34 /** 35 * @return bool 36 * 37 * @throws getid3_exception 38 */ 34 39 public function Analyze() { 35 40 $info = &$this->getid3->info; 36 41 … … 46 51 $thisfile_audio_dataformat = &$thisfile_audio['dataformat']; 47 52 $thisfile_riff_audio = &$thisfile_riff['audio']; 48 53 $thisfile_riff_video = &$thisfile_riff['video']; 54 $thisfile_riff_WAVE = array(); 49 55 50 56 $Original['avdataoffset'] = $info['avdataoffset']; 51 57 $Original['avdataend'] = $info['avdataend']; … … 357 363 } 358 364 $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024)); 359 365 $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772))); 366 $thisfile_riff['comments']['tag_text'][] = substr($thisfile_riff_WAVE_cart_0['data'], 1772); 360 367 361 368 $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist']; 362 369 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title']; … … 405 412 'tracktitle'=>'title', 406 413 'category' =>'genre', 407 414 'cdtitle' =>'album', 408 'tracktitle'=>'title',409 415 ); 410 416 foreach ($tagmapping as $fromkey => $tokey) { 411 417 if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) { … … 613 619 $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably 614 620 $thisfile_video['dataformat'] = 'avi'; 615 621 622 $thisfile_riff_video_current = array(); 623 616 624 if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) { 617 625 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8; 618 626 if (isset($thisfile_riff['AVIX'])) { … … 695 703 'capturedfile' => 0x00010000, 696 704 'copyrighted' => 0x00020010, 697 705 ); 698 foreach ($flags as $flag => $value) {706 foreach ($flags as $flag => $value) { 699 707 $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value); 700 708 } 701 709 702 710 // shortcut 703 711 $thisfile_riff_video[$streamindex] = array(); 712 /** @var array $thisfile_riff_video_current */ 704 713 $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; 705 714 706 715 if ($thisfile_riff_raw_avih['dwWidth'] > 0) { … … 867 876 } 868 877 } 869 878 870 if (isset($thisfile_riff_raw_strf_strhfccType_streamindex ['fourcc'])) {879 if (isset($thisfile_riff_raw_strf_strhfccType_streamindex) && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) { 871 880 872 881 $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']; 873 882 if (self::fourccLookup($thisfile_video['fourcc'])) { … … 914 923 // http://en.wikipedia.org/wiki/CD-DA 915 924 case 'CDDA': 916 925 $info['fileformat'] = 'cda'; 917 unset($info['mime_type']);926 unset($info['mime_type']); 918 927 919 928 $thisfile_audio_dataformat = 'cda'; 920 929 … … 934 943 935 944 $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75; 936 945 $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75; 937 $info['comments']['track ']= $thisfile_riff_CDDA_fmt_0['track_num'];946 $info['comments']['track_number'] = $thisfile_riff_CDDA_fmt_0['track_num']; 938 947 $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds']; 939 948 940 949 // hardcoded data for CD-audio … … 947 956 } 948 957 break; 949 958 950 // http://en.wikipedia.org/wiki/AIFF959 // http://en.wikipedia.org/wiki/AIFF 951 960 case 'AIFF': 952 961 case 'AIFC': 953 962 $info['fileformat'] = 'aiff'; … … 1057 1066 if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) { 1058 1067 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 1059 1068 $getid3_temp = new getID3(); 1060 $getid3_temp->openfile($this->getid3->filename );1069 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1061 1070 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1062 1071 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8; 1063 1072 if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) { … … 1077 1086 $thisfile_audio_dataformat = '8svx'; 1078 1087 $thisfile_audio['bits_per_sample'] = 8; 1079 1088 $thisfile_audio['channels'] = 1; // overridden below, if need be 1089 $ActualBitsPerSample = 0; 1080 1090 1081 1091 if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) { 1082 1092 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8; … … 1114 1124 break; 1115 1125 1116 1126 default: 1117 $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'. sCompression.'"');1127 $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.$thisfile_riff_RIFFsubtype_VHDR_0['sCompression'].'"'); 1118 1128 break; 1119 1129 } 1120 1130 } … … 1159 1169 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true); 1160 1170 1161 1171 $getid3_temp = new getID3(); 1162 $getid3_temp->openfile($this->getid3->filename );1172 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1163 1173 $getid3_mpeg = new getid3_mpeg($getid3_temp); 1164 1174 $getid3_mpeg->Analyze(); 1165 1175 if (empty($getid3_temp->info['error'])) { … … 1245 1255 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 1246 1256 1247 1257 $getid3_temp = new getID3(); 1248 $getid3_temp->openfile($this->getid3->filename );1258 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1249 1259 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1250 1260 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8; 1251 1261 if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) { … … 1372 1382 return true; 1373 1383 } 1374 1384 1385 /** 1386 * @param int $startoffset 1387 * @param int $maxoffset 1388 * 1389 * @return array|false 1390 * 1391 * @throws Exception 1392 * @throws getid3_exception 1393 */ 1375 1394 public function ParseRIFFAMV($startoffset, $maxoffset) { 1376 1395 // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size 1377 1396 … … 1480 1499 return $RIFFchunk; 1481 1500 } 1482 1501 1483 1502 /** 1503 * @param int $startoffset 1504 * @param int $maxoffset 1505 * 1506 * @return array|false 1507 * @throws getid3_exception 1508 */ 1484 1509 public function ParseRIFF($startoffset, $maxoffset) { 1485 1510 $info = &$this->getid3->info; 1486 1511 … … 1529 1554 // MP3 1530 1555 if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) { 1531 1556 $getid3_temp = new getID3(); 1532 $getid3_temp->openfile($this->getid3->filename );1557 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1533 1558 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1534 1559 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; 1535 1560 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__); … … 1551 1576 1552 1577 // AC3 1553 1578 $getid3_temp = new getID3(); 1554 $getid3_temp->openfile($this->getid3->filename );1579 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1555 1580 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1556 1581 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; 1557 1582 $getid3_ac3 = new getid3_ac3($getid3_temp); … … 1612 1637 // Probably is MP3 data 1613 1638 if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) { 1614 1639 $getid3_temp = new getID3(); 1615 $getid3_temp->openfile($this->getid3->filename );1640 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1616 1641 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1617 1642 $getid3_temp->info['avdataend'] = $info['avdataend']; 1618 1643 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__); … … 1629 1654 // This is probably AC-3 data 1630 1655 $getid3_temp = new getID3(); 1631 1656 if ($isRegularAC3) { 1632 $getid3_temp->openfile($this->getid3->filename );1657 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1633 1658 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1634 1659 $getid3_temp->info['avdataend'] = $info['avdataend']; 1635 1660 } … … 1663 1688 1664 1689 // This is probably DTS data 1665 1690 $getid3_temp = new getID3(); 1666 $getid3_temp->openfile($this->getid3->filename );1691 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp); 1667 1692 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1668 1693 $getid3_dts = new getid3_dts($getid3_temp); 1669 1694 $getid3_dts->Analyze(); … … 1731 1756 // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize)); 1732 1757 // break; 1733 1758 1759 case 'scot': 1760 // https://cmsdk.com/node-js/adding-scot-chunk-to-wav-file.html 1761 $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); 1762 $RIFFchunk[$chunkname][$thisindex]['parsed']['alter'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 0, 1); 1763 $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 1, 1); 1764 $RIFFchunk[$chunkname][$thisindex]['parsed']['artnum'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 2, 2)); 1765 $RIFFchunk[$chunkname][$thisindex]['parsed']['title'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 4, 43); // "name" in other documentation 1766 $RIFFchunk[$chunkname][$thisindex]['parsed']['copy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 47, 4); 1767 $RIFFchunk[$chunkname][$thisindex]['parsed']['padd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 51, 1); 1768 $RIFFchunk[$chunkname][$thisindex]['parsed']['asclen'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 52, 5); 1769 $RIFFchunk[$chunkname][$thisindex]['parsed']['startseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 57, 2)); 1770 $RIFFchunk[$chunkname][$thisindex]['parsed']['starthundredths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 59, 2)); 1771 $RIFFchunk[$chunkname][$thisindex]['parsed']['endseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 61, 2)); 1772 $RIFFchunk[$chunkname][$thisindex]['parsed']['endhundreths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 63, 2)); 1773 $RIFFchunk[$chunkname][$thisindex]['parsed']['sdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 65, 6); 1774 $RIFFchunk[$chunkname][$thisindex]['parsed']['kdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 71, 6); 1775 $RIFFchunk[$chunkname][$thisindex]['parsed']['start_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 77, 1); 1776 $RIFFchunk[$chunkname][$thisindex]['parsed']['kill_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 78, 1); 1777 $RIFFchunk[$chunkname][$thisindex]['parsed']['digital'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 79, 1); 1778 $RIFFchunk[$chunkname][$thisindex]['parsed']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 80, 2)); 1779 $RIFFchunk[$chunkname][$thisindex]['parsed']['stereo'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 82, 1); 1780 $RIFFchunk[$chunkname][$thisindex]['parsed']['compress'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 83, 1); 1781 $RIFFchunk[$chunkname][$thisindex]['parsed']['eomstrt'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 84, 4)); 1782 $RIFFchunk[$chunkname][$thisindex]['parsed']['eomlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 88, 2)); 1783 $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib2'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 90, 4)); 1784 $RIFFchunk[$chunkname][$thisindex]['parsed']['future1'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 94, 12); 1785 $RIFFchunk[$chunkname][$thisindex]['parsed']['catfontcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 106, 4)); 1786 $RIFFchunk[$chunkname][$thisindex]['parsed']['catcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 110, 4)); 1787 $RIFFchunk[$chunkname][$thisindex]['parsed']['segeompos'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 114, 4)); 1788 $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_startsecs'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 118, 2)); 1789 $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_starthunds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 120, 2)); 1790 $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 122, 3); 1791 $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 125, 4); 1792 $RIFFchunk[$chunkname][$thisindex]['parsed']['priorpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 129, 1); 1793 $RIFFchunk[$chunkname][$thisindex]['parsed']['postcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 130, 3); 1794 $RIFFchunk[$chunkname][$thisindex]['parsed']['postcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 133, 4); 1795 $RIFFchunk[$chunkname][$thisindex]['parsed']['postpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 137, 1); 1796 $RIFFchunk[$chunkname][$thisindex]['parsed']['hrcanplay'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 138, 21); 1797 $RIFFchunk[$chunkname][$thisindex]['parsed']['future2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 159, 108); 1798 $RIFFchunk[$chunkname][$thisindex]['parsed']['artist'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 267, 34); 1799 $RIFFchunk[$chunkname][$thisindex]['parsed']['comment'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 301, 34); // "trivia" in other documentation 1800 $RIFFchunk[$chunkname][$thisindex]['parsed']['intro'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 335, 2); 1801 $RIFFchunk[$chunkname][$thisindex]['parsed']['end'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 337, 1); 1802 $RIFFchunk[$chunkname][$thisindex]['parsed']['year'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 338, 4); 1803 $RIFFchunk[$chunkname][$thisindex]['parsed']['obsolete2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 342, 1); 1804 $RIFFchunk[$chunkname][$thisindex]['parsed']['rec_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 343, 1); 1805 $RIFFchunk[$chunkname][$thisindex]['parsed']['rdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 344, 6); 1806 $RIFFchunk[$chunkname][$thisindex]['parsed']['mpeg_bitrate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 350, 2)); 1807 $RIFFchunk[$chunkname][$thisindex]['parsed']['pitch'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 352, 2)); 1808 $RIFFchunk[$chunkname][$thisindex]['parsed']['playlevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 354, 2)); 1809 $RIFFchunk[$chunkname][$thisindex]['parsed']['lenvalid'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 356, 1); 1810 $RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 357, 4)); 1811 $RIFFchunk[$chunkname][$thisindex]['parsed']['newplaylevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 361, 2)); 1812 $RIFFchunk[$chunkname][$thisindex]['parsed']['chopsize'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 363, 4)); 1813 $RIFFchunk[$chunkname][$thisindex]['parsed']['vteomovr'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 367, 4)); 1814 $RIFFchunk[$chunkname][$thisindex]['parsed']['desiredlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 371, 4)); 1815 $RIFFchunk[$chunkname][$thisindex]['parsed']['triggers'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 375, 4)); 1816 $RIFFchunk[$chunkname][$thisindex]['parsed']['fillout'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 379, 33); 1817 1818 foreach (array('title', 'artist', 'comment') as $key) { 1819 if (trim($RIFFchunk[$chunkname][$thisindex]['parsed'][$key])) { 1820 $info['riff']['comments'][$key] = array($RIFFchunk[$chunkname][$thisindex]['parsed'][$key]); 1821 } 1822 } 1823 if ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] && !empty($info['filesize']) && ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] != $info['filesize'])) { 1824 $this->warning('RIFF.WAVE.scot.filelength ('.$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'].') different from actual filesize ('.$info['filesize'].')'); 1825 } 1826 break; 1827 1734 1828 default: 1735 if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {1829 if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) { 1736 1830 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset']; 1737 1831 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size']; 1738 1832 unset($RIFFchunk[$chunkname][$thisindex]['offset']); … … 1767 1861 return $RIFFchunk; 1768 1862 } 1769 1863 1864 /** 1865 * @param string $RIFFdata 1866 * 1867 * @return bool 1868 */ 1770 1869 public function ParseRIFFdata(&$RIFFdata) { 1771 1870 $info = &$this->getid3->info; 1772 1871 if ($RIFFdata) { … … 1804 1903 return false; 1805 1904 } 1806 1905 1906 /** 1907 * @param array $RIFFinfoArray 1908 * @param array $CommentsTargetArray 1909 * 1910 * @return bool 1911 */ 1807 1912 public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) { 1808 1913 $RIFFinfoKeyLookup = array( 1809 1914 'IARL'=>'archivallocation', … … 1863 1968 return true; 1864 1969 } 1865 1970 1971 /** 1972 * @param string $WaveFormatExData 1973 * 1974 * @return array 1975 */ 1866 1976 public static function parseWAVEFORMATex($WaveFormatExData) { 1867 1977 // shortcut 1978 $WaveFormatEx = array(); 1868 1979 $WaveFormatEx['raw'] = array(); 1869 1980 $WaveFormatEx_raw = &$WaveFormatEx['raw']; 1870 1981 … … 1888 1999 return $WaveFormatEx; 1889 2000 } 1890 2001 2002 /** 2003 * @param string $WavPackChunkData 2004 * 2005 * @return bool 2006 */ 1891 2007 public function parseWavPackHeader($WavPackChunkData) { 1892 2008 // typedef struct { 1893 2009 // char ckID [4]; … … 1949 2065 return true; 1950 2066 } 1951 2067 2068 /** 2069 * @param string $BITMAPINFOHEADER 2070 * @param bool $littleEndian 2071 * 2072 * @return array 2073 */ 1952 2074 public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) { 1953 2075 1954 2076 $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure … … 1968 2090 return $parsed; 1969 2091 } 1970 2092 2093 /** 2094 * @param string $DIVXTAG 2095 * @param bool $raw 2096 * 2097 * @return array 2098 */ 1971 2099 public static function ParseDIVXTAG($DIVXTAG, $raw=false) { 1972 2100 // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/ 1973 2101 // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip … … 2014 2142 5 => 'NC-17', 2015 2143 ); 2016 2144 2145 $parsed = array(); 2017 2146 $parsed['title'] = trim(substr($DIVXTAG, 0, 32)); 2018 2147 $parsed['artist'] = trim(substr($DIVXTAG, 32, 28)); 2019 2148 $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4))); … … 2029 2158 if (!$raw) { 2030 2159 unset($parsed['genre_id'], $parsed['rating_id']); 2031 2160 foreach ($parsed as $key => $value) { 2032 if ( !$value === '') {2033 unset($parsed[ 'key']);2161 if (empty($value)) { 2162 unset($parsed[$key]); 2034 2163 } 2035 2164 } 2036 2165 } … … 2042 2171 return $parsed; 2043 2172 } 2044 2173 2174 /** 2175 * @param string $tagshortname 2176 * 2177 * @return string 2178 */ 2045 2179 public static function waveSNDMtagLookup($tagshortname) { 2046 2180 $begin = __LINE__; 2047 2181 … … 2065 2199 return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm'); 2066 2200 } 2067 2201 2202 /** 2203 * @param int $wFormatTag 2204 * 2205 * @return string 2206 */ 2068 2207 public static function wFormatTagLookup($wFormatTag) { 2069 2208 2070 2209 $begin = __LINE__; … … 2234 2373 return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag'); 2235 2374 } 2236 2375 2376 /** 2377 * @param string $fourcc 2378 * 2379 * @return string 2380 */ 2237 2381 public static function fourccLookup($fourcc) { 2238 2382 2239 2383 $begin = __LINE__; … … 2628 2772 return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc'); 2629 2773 } 2630 2774 2775 /** 2776 * @param string $byteword 2777 * @param bool $signed 2778 * 2779 * @return int|float|false 2780 */ 2631 2781 private function EitherEndian2Int($byteword, $signed=false) { 2632 2782 if ($this->container == 'riff') { 2633 2783 return getid3_lib::LittleEndian2Int($byteword, $signed); -
src/wp-includes/ID3/module.audio.ac3.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio.ac3.php // 12 12 // module for analyzing AC-3 (aka Dolby Digital) audio files // … … 17 17 18 18 class getid3_ac3 extends getid3_handler 19 19 { 20 private $AC3header = array(); 21 private $BSIoffset = 0; 20 /** 21 * @var array 22 */ 23 private $AC3header = array(); 22 24 23 const syncword = 0x0B77; 25 /** 26 * @var int 27 */ 28 private $BSIoffset = 0; 24 29 30 const syncword = 0x0B77; 31 32 /** 33 * @return bool 34 */ 25 35 public function Analyze() { 26 36 $info = &$this->getid3->info; 27 37 … … 187 197 } elseif ($thisfile_ac3_raw_bsi['bsid'] <= 16) { // E-AC3 188 198 189 199 190 $this->error('E-AC3 parsing is incomplete and experimental in this version of getID3 ('.$this->getid3->version().'). Notably the bitrate calculations are wrong -- value might (or not) be correct, but it is not calculated correctly. Email info@getid3.org if you know how to calculate EAC3 bitrate correctly.');200 $this->error('E-AC3 parsing is incomplete and experimental in this version of getID3 ('.$this->getid3->version().'). Notably the bitrate calculations are wrong -- value might (or not) be correct, but it is not calculated correctly. Email info@getid3.org if you know how to calculate EAC3 bitrate correctly.'); 191 201 $info['audio']['dataformat'] = 'eac3'; 192 202 193 203 $thisfile_ac3_raw_bsi['strmtyp'] = $this->readHeaderBSI(2); … … 412 422 } else { 413 423 414 424 $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 16. Please submit a support ticket with a sample file.'); 415 unset($info['ac3']);425 unset($info['ac3']); 416 426 return false; 417 427 418 428 } … … 431 441 $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw_bsi['frmsizecod'], $thisfile_ac3_raw_bsi['fscod']); 432 442 $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw_bsi['frmsizecod']); 433 443 } elseif (!empty($thisfile_ac3_raw_bsi['frmsiz'])) { 434 // this isn't right, but it's (usually) close, roughly 5% less than it should be.435 // but WHERE is the actual bitrate value stored in EAC3?? email info@getid3.org if you know!444 // this isn't right, but it's (usually) close, roughly 5% less than it should be. 445 // but WHERE is the actual bitrate value stored in EAC3?? email info@getid3.org if you know! 436 446 $thisfile_ac3['bitrate'] = ($thisfile_ac3_raw_bsi['frmsiz'] + 1) * 16 * 30; // The frmsiz field shall contain a value one less than the overall size of the coded syncframe in 16-bit words. That is, this field may assume a value ranging from 0 to 2047, and these values correspond to syncframe sizes ranging from 1 to 2048. 437 // kludge-fix to make it approximately the expected value, still not "right":438 $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16000;447 // kludge-fix to make it approximately the expected value, still not "right": 448 $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16000; 439 449 } 440 450 $info['audio']['bitrate'] = $thisfile_ac3['bitrate']; 441 451 442 $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']); 452 if (isset($thisfile_ac3_raw_bsi['bsmod']) && isset($thisfile_ac3_raw_bsi['acmod'])) { 453 $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']); 454 } 443 455 $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']); 444 456 foreach($ac3_coding_mode as $key => $value) { 445 457 $thisfile_ac3[$key] = $value; … … 470 482 return true; 471 483 } 472 484 485 /** 486 * @param int $length 487 * 488 * @return float|int 489 */ 473 490 private function readHeaderBSI($length) { 474 491 $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length); 475 492 $this->BSIoffset += $length; … … 477 494 return bindec($data); 478 495 } 479 496 497 /** 498 * @param int $fscod 499 * 500 * @return int|string|false 501 */ 480 502 public static function sampleRateCodeLookup($fscod) { 481 503 static $sampleRateCodeLookup = array( 482 504 0 => 48000, … … 487 509 return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false); 488 510 } 489 511 512 /** 513 * @param int $fscod2 514 * 515 * @return int|string|false 516 */ 490 517 public static function sampleRateCodeLookup2($fscod2) { 491 518 static $sampleRateCodeLookup2 = array( 492 519 0 => 24000, … … 497 524 return (isset($sampleRateCodeLookup2[$fscod2]) ? $sampleRateCodeLookup2[$fscod2] : false); 498 525 } 499 526 527 /** 528 * @param int $bsmod 529 * @param int $acmod 530 * 531 * @return string|false 532 */ 500 533 public static function serviceTypeLookup($bsmod, $acmod) { 501 534 static $serviceTypeLookup = array(); 502 535 if (empty($serviceTypeLookup)) { … … 518 551 return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false); 519 552 } 520 553 554 /** 555 * @param int $acmod 556 * 557 * @return array|false 558 */ 521 559 public static function audioCodingModeLookup($acmod) { 522 560 // array(channel configuration, # channels (not incl LFE), channel order) 523 561 static $audioCodingModeLookup = array ( … … 533 571 return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false); 534 572 } 535 573 574 /** 575 * @param int $cmixlev 576 * 577 * @return int|float|string|false 578 */ 536 579 public static function centerMixLevelLookup($cmixlev) { 537 580 static $centerMixLevelLookup; 538 581 if (empty($centerMixLevelLookup)) { … … 546 589 return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false); 547 590 } 548 591 592 /** 593 * @param int $surmixlev 594 * 595 * @return int|float|string|false 596 */ 549 597 public static function surroundMixLevelLookup($surmixlev) { 550 598 static $surroundMixLevelLookup; 551 599 if (empty($surroundMixLevelLookup)) { … … 559 607 return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false); 560 608 } 561 609 610 /** 611 * @param int $dsurmod 612 * 613 * @return string|false 614 */ 562 615 public static function dolbySurroundModeLookup($dsurmod) { 563 616 static $dolbySurroundModeLookup = array( 564 617 0 => 'not indicated', … … 569 622 return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false); 570 623 } 571 624 625 /** 626 * @param int $acmod 627 * @param bool $lfeon 628 * 629 * @return array 630 */ 572 631 public static function channelsEnabledLookup($acmod, $lfeon) { 573 632 $lookup = array( 574 'ch1'=>( bool) ($acmod == 0),575 'ch2'=>( bool) ($acmod == 0),576 'left'=>( bool) ($acmod > 1),577 'right'=>( bool) ($acmod > 1),633 'ch1'=>($acmod == 0), 634 'ch2'=>($acmod == 0), 635 'left'=>($acmod > 1), 636 'right'=>($acmod > 1), 578 637 'center'=>(bool) ($acmod & 0x01), 579 638 'surround_mono'=>false, 580 639 'surround_left'=>false, … … 594 653 return $lookup; 595 654 } 596 655 656 /** 657 * @param int $compre 658 * 659 * @return float|int 660 */ 597 661 public static function heavyCompression($compre) { 598 662 // The first four bits indicate gain changes in 6.02dB increments which can be 599 663 // implemented with an arithmetic shift operation. The following four bits … … 623 687 // -8 -42.14 dB 624 688 625 689 $fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT); 626 if ($fourbit {0}== '1') {690 if ($fourbit[0] == '1') { 627 691 $log_gain = -8 + bindec(substr($fourbit, 1)); 628 692 } else { 629 693 $log_gain = bindec(substr($fourbit, 1)); … … 644 708 return $log_gain - $lin_gain; 645 709 } 646 710 711 /** 712 * @param int $roomtyp 713 * 714 * @return string|false 715 */ 647 716 public static function roomTypeLookup($roomtyp) { 648 717 static $roomTypeLookup = array( 649 718 0 => 'not indicated', … … 654 723 return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false); 655 724 } 656 725 726 /** 727 * @param int $frmsizecod 728 * @param int $fscod 729 * 730 * @return int|false 731 */ 657 732 public static function frameSizeLookup($frmsizecod, $fscod) { 658 733 // LSB is whether padding is used or not 659 734 $padding = (bool) ($frmsizecod & 0x01); … … 683 758 18 => array(2560, 2786, 3840) // 640 kbps 684 759 ); 685 760 } 761 $paddingBytes = 0; 686 762 if (($fscod == 1) && $padding) { 687 763 // frame lengths are padded by 1 word (16 bits) at 44100 688 $frameSizeLookup[$frmsizecod] += 2; 764 // (fscode==1) means 44100Hz (see sampleRateCodeLookup) 765 $paddingBytes = 2; 689 766 } 690 return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);767 return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] + $paddingBytes : false); 691 768 } 692 769 770 /** 771 * @param int $frmsizecod 772 * 773 * @return int|false 774 */ 693 775 public static function bitrateLookup($frmsizecod) { 694 776 // LSB is whether padding is used or not 695 777 $padding = (bool) ($frmsizecod & 0x01); … … 719 801 return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false); 720 802 } 721 803 804 /** 805 * @param int $numblkscod 806 * 807 * @return int|false 808 */ 722 809 public static function blocksPerSyncFrame($numblkscod) { 723 810 static $blocksPerSyncFrameLookup = array( 724 811 0 => 1, -
src/wp-includes/ID3/module.audio.dts.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio.dts.php // 12 12 // module for analyzing DTS Audio files // … … 21 21 class getid3_dts extends getid3_handler 22 22 { 23 23 /** 24 * Default DTS syncword used in native .cpt or .dts formats25 */26 const syncword = "\x7F\xFE\x80\x01";24 * Default DTS syncword used in native .cpt or .dts formats. 25 */ 26 const syncword = "\x7F\xFE\x80\x01"; 27 27 28 /** 29 * @var int 30 */ 28 31 private $readBinDataOffset = 0; 29 32 30 /**31 * Possible syncwords indicating bitstream encoding 32 */33 public static $syncwords = array(34 0 => "\x7F\xFE\x80\x01", // raw big-endian35 1 => "\xFE\x7F\x01\x80", // raw little-endian36 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian37 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian33 /** 34 * Possible syncwords indicating bitstream encoding. 35 */ 36 public static $syncwords = array( 37 0 => "\x7F\xFE\x80\x01", // raw big-endian 38 1 => "\xFE\x7F\x01\x80", // raw little-endian 39 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian 40 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian 38 41 42 /** 43 * @return bool 44 */ 39 45 public function Analyze() { 40 46 $info = &$this->getid3->info; 41 47 $info['fileformat'] = 'dts'; … … 45 51 46 52 // check syncword 47 53 $sync = substr($DTSheader, 0, 4); 48 if (($encoding = array_search($sync, self::$syncwords)) !== false) {54 if (($encoding = array_search($sync, self::$syncwords)) !== false) { 49 55 50 $info['dts']['raw']['magic'] = $sync;56 $info['dts']['raw']['magic'] = $sync; 51 57 $this->readBinDataOffset = 32; 52 58 53 } elseif ($this->isDependencyFor('matroska')) {59 } elseif ($this->isDependencyFor('matroska')) { 54 60 55 61 // Matroska contains DTS without syncword encoded as raw big-endian format 56 62 $encoding = 0; 57 63 $this->readBinDataOffset = 0; 58 64 59 } else {65 } else { 60 66 61 67 unset($info['fileformat']); 62 68 return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"'); … … 139 145 return true; 140 146 } 141 147 148 /** 149 * @param string $bin 150 * @param int $length 151 * 152 * @return float|int 153 */ 142 154 private function readBinData($bin, $length) { 143 155 $data = substr($bin, $this->readBinDataOffset, $length); 144 156 $this->readBinDataOffset += $length; … … 146 158 return bindec($data); 147 159 } 148 160 161 /** 162 * @param int $index 163 * 164 * @return int|string|false 165 */ 149 166 public static function bitrateLookup($index) { 150 167 static $lookup = array( 151 168 0 => 32000, … … 184 201 return (isset($lookup[$index]) ? $lookup[$index] : false); 185 202 } 186 203 204 /** 205 * @param int $index 206 * 207 * @return int|string|false 208 */ 187 209 public static function sampleRateLookup($index) { 188 210 static $lookup = array( 189 211 0 => 'invalid', … … 206 228 return (isset($lookup[$index]) ? $lookup[$index] : false); 207 229 } 208 230 231 /** 232 * @param int $index 233 * 234 * @return int|false 235 */ 209 236 public static function bitPerSampleLookup($index) { 210 237 static $lookup = array( 211 238 0 => 16, … … 216 243 return (isset($lookup[$index]) ? $lookup[$index] : false); 217 244 } 218 245 246 /** 247 * @param int $index 248 * 249 * @return int|false 250 */ 219 251 public static function numChannelsLookup($index) { 220 252 switch ($index) { 221 253 case 0: … … 254 286 return false; 255 287 } 256 288 289 /** 290 * @param int $index 291 * 292 * @return string 293 */ 257 294 public static function channelArrangementLookup($index) { 258 295 static $lookup = array( 259 296 0 => 'A', … … 276 313 return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined'); 277 314 } 278 315 316 /** 317 * @param int $index 318 * @param int $version 319 * 320 * @return int|false 321 */ 279 322 public static function dialogNormalization($index, $version) { 280 323 switch ($version) { 281 324 case 7: -
src/wp-includes/ID3/module.audio.flac.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio.flac.php // 12 12 // module for analyzing FLAC and OggFLAC audio files // … … 24 24 { 25 25 const syncword = 'fLaC'; 26 26 27 /** 28 * @return bool 29 */ 27 30 public function Analyze() { 28 31 $info = &$this->getid3->info; 29 32 … … 41 44 return $this->parseMETAdata(); 42 45 } 43 46 47 /** 48 * @return bool 49 */ 44 50 public function parseMETAdata() { 45 51 $info = &$this->getid3->info; 46 52 do { 47 53 $BlockOffset = $this->ftell(); 48 54 $BlockHeader = $this->fread(4); 49 $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1)); 55 $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1)); // LBFBT = LastBlockFlag + BlockType 50 56 $LastBlockFlag = (bool) ($LBFBT & 0x80); 51 57 $BlockType = ($LBFBT & 0x7F); 52 58 $BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3)); … … 53 59 $BlockTypeText = self::metaBlockTypeLookup($BlockType); 54 60 55 61 if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) { 56 $this-> error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');62 $this->warning('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file'); 57 63 break; 58 64 } 59 65 if ($BlockLength < 1) { 66 if ($BlockTypeText != 'reserved') { 67 // probably supposed to be zero-length 68 $this->warning('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockTypeText.') at offset '.$BlockOffset.' is zero bytes'); 69 continue; 70 } 60 71 $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid'); 61 72 break; 62 73 } … … 167 178 if (isset($info['flac']['STREAMINFO']['audio_signature'])) { 168 179 169 180 if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) { 170 $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');181 $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)'); 171 182 } 172 183 else { 173 184 $info['md5_data_source'] = ''; … … 194 205 return true; 195 206 } 196 207 197 private function parseSTREAMINFO($BlockData) {198 $info = &$this->getid3->info;199 208 200 $info['flac']['STREAMINFO'] = array(); 201 $streaminfo = &$info['flac']['STREAMINFO']; 202 209 /** 210 * @param string $BlockData 211 * 212 * @return array 213 */ 214 public static function parseSTREAMINFOdata($BlockData) { 215 $streaminfo = array(); 203 216 $streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2)); 204 217 $streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2)); 205 218 $streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3)); … … 211 224 $streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1; 212 225 $streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36)); 213 226 214 $streaminfo['audio_signature'] = substr($BlockData, 18, 16);227 $streaminfo['audio_signature'] = substr($BlockData, 18, 16); 215 228 216 if (!empty($streaminfo['sample_rate'])) { 229 return $streaminfo; 230 } 217 231 232 /** 233 * @param string $BlockData 234 * 235 * @return bool 236 */ 237 private function parseSTREAMINFO($BlockData) { 238 $info = &$this->getid3->info; 239 240 $info['flac']['STREAMINFO'] = self::parseSTREAMINFOdata($BlockData); 241 242 if (!empty($info['flac']['STREAMINFO']['sample_rate'])) { 243 218 244 $info['audio']['bitrate_mode'] = 'vbr'; 219 $info['audio']['sample_rate'] = $ streaminfo['sample_rate'];220 $info['audio']['channels'] = $ streaminfo['channels'];221 $info['audio']['bits_per_sample'] = $ streaminfo['bits_per_sample'];222 $info['playtime_seconds'] = $ streaminfo['samples_stream'] / $streaminfo['sample_rate'];245 $info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate']; 246 $info['audio']['channels'] = $info['flac']['STREAMINFO']['channels']; 247 $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample']; 248 $info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate']; 223 249 if ($info['playtime_seconds'] > 0) { 224 250 if (!$this->isDependencyFor('matroska')) { 225 251 $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; … … 236 262 return true; 237 263 } 238 264 265 /** 266 * @param string $BlockData 267 * 268 * @return bool 269 */ 239 270 private function parseAPPLICATION($BlockData) { 240 271 $info = &$this->getid3->info; 241 272 … … 246 277 return true; 247 278 } 248 279 280 /** 281 * @param string $BlockData 282 * 283 * @return bool 284 */ 249 285 private function parseSEEKTABLE($BlockData) { 250 286 $info = &$this->getid3->info; 251 287 … … 275 311 return true; 276 312 } 277 313 314 /** 315 * @param string $BlockData 316 * 317 * @return bool 318 */ 278 319 private function parseVORBIS_COMMENT($BlockData) { 279 320 $info = &$this->getid3->info; 280 321 … … 294 335 return true; 295 336 } 296 337 338 /** 339 * @param string $BlockData 340 * 341 * @return bool 342 */ 297 343 private function parseCUESHEET($BlockData) { 298 344 $info = &$this->getid3->info; 299 345 $offset = 0; … … 346 392 } 347 393 348 394 /** 349 * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment 350 * External usage: audio.ogg 351 */ 395 * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment 396 * External usage: audio.ogg 397 * 398 * @return bool 399 */ 352 400 public function parsePICTURE() { 353 401 $info = &$this->getid3->info; 354 402 … … 380 428 return true; 381 429 } 382 430 431 /** 432 * @param int $blocktype 433 * 434 * @return string 435 */ 383 436 public static function metaBlockTypeLookup($blocktype) { 384 437 static $lookup = array( 385 438 0 => 'STREAMINFO', … … 393 446 return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved'); 394 447 } 395 448 449 /** 450 * @param int $applicationid 451 * 452 * @return string 453 */ 396 454 public static function applicationIDLookup($applicationid) { 397 455 // http://flac.sourceforge.net/id.html 398 456 static $lookup = array( … … 423 481 return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved'); 424 482 } 425 483 484 /** 485 * @param int $type_id 486 * 487 * @return string 488 */ 426 489 public static function pictureTypeLookup($type_id) { 427 490 static $lookup = array ( 428 491 0 => 'Other', -
src/wp-includes/ID3/module.audio.mp3.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio.mp3.php // 12 12 // module for analyzing MP3 files // … … 24 24 25 25 class getid3_mp3 extends getid3_handler 26 26 { 27 /** 28 * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, 29 * unrecommended, but may provide data from otherwise-unusable files. 30 * 31 * @var bool 32 */ 33 public $allow_bruteforce = false; 27 34 28 public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files 29 35 /** 36 * @return bool 37 */ 30 38 public function Analyze() { 31 39 $info = &$this->getid3->info; 32 40 … … 35 43 if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) { 36 44 if ($this->allow_bruteforce) { 37 45 $this->error('Rescanning file in BruteForce mode'); 38 $this->getOnlyMPEGaudioInfoBruteForce( $this->getid3->fp, $info);46 $this->getOnlyMPEGaudioInfoBruteForce(); 39 47 } 40 48 } 41 49 … … 152 160 153 161 // Calculate playtime 154 162 if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) { 155 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate']; 163 // https://github.com/JamesHeinrich/getID3/issues/161 164 // VBR header frame contains ~0.026s of silent audio data, but is not actually part of the original encoding and should be ignored 165 $xingVBRheaderFrameLength = ((isset($info['mpeg']['audio']['VBR_frames']) && isset($info['mpeg']['audio']['framelength'])) ? $info['mpeg']['audio']['framelength'] : 0); 166 167 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset'] - $xingVBRheaderFrameLength) * 8 / $info['audio']['bitrate']; 156 168 } 157 169 158 170 $info['audio']['encoder_options'] = $this->GuessEncoderOptions(); … … 160 172 return true; 161 173 } 162 174 163 175 /** 176 * @return string 177 */ 164 178 public function GuessEncoderOptions() { 165 179 // shortcuts 166 180 $info = &$this->getid3->info; 181 $thisfile_mpeg_audio = array(); 182 $thisfile_mpeg_audio_lame = array(); 167 183 if (!empty($info['mpeg']['audio'])) { 168 184 $thisfile_mpeg_audio = &$info['mpeg']['audio']; 169 185 if (!empty($thisfile_mpeg_audio['LAME'])) { … … 178 194 179 195 $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality']; 180 196 181 } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {197 } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && isset($thisfile_mpeg_audio_lame['preset_used_id']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) { 182 198 183 199 $encoder_options = $thisfile_mpeg_audio_lame['preset_used']; 184 200 … … 404 420 return $encoder_options; 405 421 } 406 422 407 423 /** 424 * @param int $offset 425 * @param array $info 426 * @param bool $recursivesearch 427 * @param bool $ScanAsCBR 428 * @param bool $FastMPEGheaderScan 429 * 430 * @return bool 431 */ 408 432 public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) { 409 433 static $MPEGaudioVersionLookup; 410 434 static $MPEGaudioLayerLookup; … … 458 482 } 459 483 $thisfile_mpeg_audio = &$info['mpeg']['audio']; 460 484 461 462 485 if ($MPEGaudioHeaderValidCache[$head4_key]) { 463 486 $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray; 464 487 } else { … … 562 585 563 586 $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; 564 587 $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer'; 565 $info['audio']['codec'] = 'Fraunhofer';588 $info['audio']['codec'] = 'Fraunhofer'; 566 589 567 590 $SideInfoData = substr($headerstring, 4 + 2, 32); 568 591 … … 655 678 $used_filesize = $thisfile_mpeg_audio['VBR_bytes']; 656 679 } elseif (!empty($info['filesize'])) { 657 680 $used_filesize = $info['filesize']; 658 $used_filesize -= intval(@$info['id3v2']['headerlength']);681 $used_filesize -= (isset($info['id3v2']['headerlength']) ? intval($info['id3v2']['headerlength']) : 0); 659 682 $used_filesize -= (isset($info['id3v1']) ? 128 : 0); 660 683 $used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0); 661 684 $this->warning('MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes'); … … 678 701 if ($thisfile_mpeg_audio['xing_flags']['toc']) { 679 702 $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100); 680 703 for ($i = 0; $i < 100; $i++) { 681 $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData {$i});704 $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData[$i]); 682 705 } 683 706 } 684 707 if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) { … … 1083 1106 return true; 1084 1107 } 1085 1108 1109 /** 1110 * @param int $offset 1111 * @param int $nextframetestoffset 1112 * @param bool $ScanAsCBR 1113 * 1114 * @return bool 1115 */ 1086 1116 public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) { 1087 1117 $info = &$this->getid3->info; 1088 1118 $firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']); … … 1129 1159 return true; 1130 1160 } 1131 1161 1162 /** 1163 * @param int $offset 1164 * @param bool $deepscan 1165 * 1166 * @return int|false 1167 */ 1132 1168 public function FreeFormatFrameLength($offset, $deepscan=false) { 1133 1169 $info = &$this->getid3->info; 1134 1170 … … 1137 1173 1138 1174 $SyncPattern1 = substr($MPEGaudioData, 0, 4); 1139 1175 // may be different pattern due to padding 1140 $SyncPattern2 = $SyncPattern1 {0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};1176 $SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) | 0x02).$SyncPattern1[3]; 1141 1177 if ($SyncPattern2 === $SyncPattern1) { 1142 $SyncPattern2 = $SyncPattern1 {0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};1178 $SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) & 0xFD).$SyncPattern1[3]; 1143 1179 } 1144 1180 1145 1181 $framelength = false; … … 1206 1242 return $framelength; 1207 1243 } 1208 1244 1245 /** 1246 * @return bool 1247 */ 1209 1248 public function getOnlyMPEGaudioInfoBruteForce() { 1210 1249 $MPEGaudioHeaderDecodeCache = array(); 1211 1250 $MPEGaudioHeaderValidCache = array(); … … 1241 1280 if (strlen($head4) < 4) { 1242 1281 break; 1243 1282 } 1244 if ($head4 {0}!= "\xFF") {1283 if ($head4[0] != "\xFF") { 1245 1284 for ($i = 1; $i < 4; $i++) { 1246 if ($head4 {$i}== "\xFF") {1285 if ($head4[$i] == "\xFF") { 1247 1286 $this->fseek($i - 4, SEEK_CUR); 1248 1287 continue 2; 1249 1288 } … … 1275 1314 $WhereWeWere = $this->ftell(); 1276 1315 $this->fseek($MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR); 1277 1316 $next4 = $this->fread(4); 1278 if ($next4 {0}== "\xFF") {1317 if ($next4[0] == "\xFF") { 1279 1318 if (!isset($MPEGaudioHeaderDecodeCache[$next4])) { 1280 1319 $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4); 1281 1320 } … … 1353 1392 return true; 1354 1393 } 1355 1394 1356 1395 /** 1396 * @param int $avdataoffset 1397 * @param bool $BitrateHistogram 1398 * 1399 * @return bool 1400 */ 1357 1401 public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { 1358 1402 // looks for synch, decodes MPEG audio header 1359 1403 … … 1363 1407 static $MPEGaudioLayerLookup; 1364 1408 static $MPEGaudioBitrateLookup; 1365 1409 if (empty($MPEGaudioVersionLookup)) { 1366 $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); 1367 $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); 1368 $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); 1369 1410 $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); 1411 $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); 1412 $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); 1370 1413 } 1371 1414 1372 1415 $this->fseek($avdataoffset); … … 1416 1459 return false; 1417 1460 } 1418 1461 1419 if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected 1462 if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected 1463 $FirstFrameAVDataOffset = null; 1420 1464 if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) { 1421 1465 $FirstFrameThisfileInfo = $info; 1422 1466 $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset; … … 1440 1484 $info['audio']['dataformat'] = 'mp3'; 1441 1485 break; 1442 1486 } 1443 if (isset($FirstFrameThisfileInfo ['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {1487 if (isset($FirstFrameThisfileInfo) && isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) { 1444 1488 if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) { 1445 1489 // If there is garbage data between a valid VBR header frame and a sequence 1446 1490 // of valid MPEG-audio frames the VBR data is no longer discarded. … … 1510 1554 $this->fseek($scan_start_offset[$current_segment]); 1511 1555 $buffer_4k = $this->fread(4096); 1512 1556 for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) { 1513 if (($buffer_4k {$j} == "\xFF") && ($buffer_4k{($j + 1)}> "\xE0")) { // synch detected1557 if (($buffer_4k[$j] == "\xFF") && ($buffer_4k[($j + 1)] > "\xE0")) { // synch detected 1514 1558 if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) { 1515 1559 $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength']; 1516 1560 if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) { … … 1522 1566 } 1523 1567 } 1524 1568 $synchstartoffset = $scan_start_offset[$current_segment]; 1525 while ( $this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {1569 while (($synchstartoffset < $info['avdataend']) && $this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) { 1526 1570 $FastMode = true; 1527 1571 $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']]; 1528 1572 … … 1633 1677 return true; 1634 1678 } 1635 1679 1636 1680 /** 1681 * @return array 1682 */ 1637 1683 public static function MPEGaudioVersionArray() { 1638 1684 static $MPEGaudioVersion = array('2.5', false, '2', '1'); 1639 1685 return $MPEGaudioVersion; 1640 1686 } 1641 1687 1688 /** 1689 * @return array 1690 */ 1642 1691 public static function MPEGaudioLayerArray() { 1643 1692 static $MPEGaudioLayer = array(false, 3, 2, 1); 1644 1693 return $MPEGaudioLayer; 1645 1694 } 1646 1695 1696 /** 1697 * @return array 1698 */ 1647 1699 public static function MPEGaudioBitrateArray() { 1648 1700 static $MPEGaudioBitrate; 1649 1701 if (empty($MPEGaudioBitrate)) { … … 1663 1715 return $MPEGaudioBitrate; 1664 1716 } 1665 1717 1718 /** 1719 * @return array 1720 */ 1666 1721 public static function MPEGaudioFrequencyArray() { 1667 1722 static $MPEGaudioFrequency; 1668 1723 if (empty($MPEGaudioFrequency)) { … … 1675 1730 return $MPEGaudioFrequency; 1676 1731 } 1677 1732 1733 /** 1734 * @return array 1735 */ 1678 1736 public static function MPEGaudioChannelModeArray() { 1679 1737 static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono'); 1680 1738 return $MPEGaudioChannelMode; 1681 1739 } 1682 1740 1741 /** 1742 * @return array 1743 */ 1683 1744 public static function MPEGaudioModeExtensionArray() { 1684 1745 static $MPEGaudioModeExtension; 1685 1746 if (empty($MPEGaudioModeExtension)) { … … 1692 1753 return $MPEGaudioModeExtension; 1693 1754 } 1694 1755 1756 /** 1757 * @return array 1758 */ 1695 1759 public static function MPEGaudioEmphasisArray() { 1696 1760 static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17'); 1697 1761 return $MPEGaudioEmphasis; 1698 1762 } 1699 1763 1764 /** 1765 * @param string $head4 1766 * @param bool $allowBitrate15 1767 * 1768 * @return bool 1769 */ 1700 1770 public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) { 1701 1771 return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15); 1702 1772 } 1703 1773 1774 /** 1775 * @param array $rawarray 1776 * @param bool $echoerrors 1777 * @param bool $allowBitrate15 1778 * 1779 * @return bool 1780 */ 1704 1781 public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) { 1705 1782 if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) { 1706 1783 return false; … … 1773 1850 return true; 1774 1851 } 1775 1852 1853 /** 1854 * @param string $Header4Bytes 1855 * 1856 * @return array|false 1857 */ 1776 1858 public static function MPEGaudioHeaderDecode($Header4Bytes) { 1777 1859 // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM 1778 1860 // A - Frame sync (all bits set) … … 1794 1876 } 1795 1877 1796 1878 $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4; 1797 $MPEGrawHeader['version'] = (ord($Header4Bytes {1}) & 0x18) >> 3; // BB1798 $MPEGrawHeader['layer'] = (ord($Header4Bytes {1}) & 0x06) >> 1; // CC1799 $MPEGrawHeader['protection'] = (ord($Header4Bytes {1}) & 0x01); // D1800 $MPEGrawHeader['bitrate'] = (ord($Header4Bytes {2}) & 0xF0) >> 4; // EEEE1801 $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes {2}) & 0x0C) >> 2; // FF1802 $MPEGrawHeader['padding'] = (ord($Header4Bytes {2}) & 0x02) >> 1; // G1803 $MPEGrawHeader['private'] = (ord($Header4Bytes {2}) & 0x01); // H1804 $MPEGrawHeader['channelmode'] = (ord($Header4Bytes {3}) & 0xC0) >> 6; // II1805 $MPEGrawHeader['modeextension'] = (ord($Header4Bytes {3}) & 0x30) >> 4; // JJ1806 $MPEGrawHeader['copyright'] = (ord($Header4Bytes {3}) & 0x08) >> 3; // K1807 $MPEGrawHeader['original'] = (ord($Header4Bytes {3}) & 0x04) >> 2; // L1808 $MPEGrawHeader['emphasis'] = (ord($Header4Bytes {3}) & 0x03); // MM1879 $MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB 1880 $MPEGrawHeader['layer'] = (ord($Header4Bytes[1]) & 0x06) >> 1; // CC 1881 $MPEGrawHeader['protection'] = (ord($Header4Bytes[1]) & 0x01); // D 1882 $MPEGrawHeader['bitrate'] = (ord($Header4Bytes[2]) & 0xF0) >> 4; // EEEE 1883 $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes[2]) & 0x0C) >> 2; // FF 1884 $MPEGrawHeader['padding'] = (ord($Header4Bytes[2]) & 0x02) >> 1; // G 1885 $MPEGrawHeader['private'] = (ord($Header4Bytes[2]) & 0x01); // H 1886 $MPEGrawHeader['channelmode'] = (ord($Header4Bytes[3]) & 0xC0) >> 6; // II 1887 $MPEGrawHeader['modeextension'] = (ord($Header4Bytes[3]) & 0x30) >> 4; // JJ 1888 $MPEGrawHeader['copyright'] = (ord($Header4Bytes[3]) & 0x08) >> 3; // K 1889 $MPEGrawHeader['original'] = (ord($Header4Bytes[3]) & 0x04) >> 2; // L 1890 $MPEGrawHeader['emphasis'] = (ord($Header4Bytes[3]) & 0x03); // MM 1809 1891 1810 1892 return $MPEGrawHeader; 1811 1893 } 1812 1894 1895 /** 1896 * @param int|string $bitrate 1897 * @param string $version 1898 * @param string $layer 1899 * @param bool $padding 1900 * @param int $samplerate 1901 * 1902 * @return int|false 1903 */ 1813 1904 public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) { 1814 1905 static $AudioFrameLengthCache = array(); 1815 1906 … … 1871 1962 return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate]; 1872 1963 } 1873 1964 1965 /** 1966 * @param float|int $bit_rate 1967 * 1968 * @return int|float|string 1969 */ 1874 1970 public static function ClosestStandardMP3Bitrate($bit_rate) { 1875 1971 static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000); 1876 1972 static $bit_rate_table = array (0=>'-'); … … 1891 1987 return $bit_rate_table[$round_bit_rate]; 1892 1988 } 1893 1989 1990 /** 1991 * @param string $version 1992 * @param string $channelmode 1993 * 1994 * @return int 1995 */ 1894 1996 public static function XingVBRidOffset($version, $channelmode) { 1895 1997 static $XingVBRidOffsetCache = array(); 1896 if (empty($XingVBRidOffset )) {1897 $XingVBRidOffset = array (1998 if (empty($XingVBRidOffsetCache)) { 1999 $XingVBRidOffsetCache = array ( 1898 2000 '1' => array ('mono' => 0x15, // 4 + 17 = 21 1899 2001 'stereo' => 0x24, // 4 + 32 = 36 1900 2002 'joint stereo' => 0x24, … … 1914 2016 ) 1915 2017 ); 1916 2018 } 1917 return $XingVBRidOffset [$version][$channelmode];2019 return $XingVBRidOffsetCache[$version][$channelmode]; 1918 2020 } 1919 2021 2022 /** 2023 * @param int $VBRmethodID 2024 * 2025 * @return string 2026 */ 1920 2027 public static function LAMEvbrMethodLookup($VBRmethodID) { 1921 2028 static $LAMEvbrMethodLookup = array( 1922 2029 0x00 => 'unknown', … … 1933 2040 return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : ''); 1934 2041 } 1935 2042 2043 /** 2044 * @param int $StereoModeID 2045 * 2046 * @return string 2047 */ 1936 2048 public static function LAMEmiscStereoModeLookup($StereoModeID) { 1937 2049 static $LAMEmiscStereoModeLookup = array( 1938 2050 0 => 'mono', … … 1947 2059 return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : ''); 1948 2060 } 1949 2061 2062 /** 2063 * @param int $SourceSampleFrequencyID 2064 * 2065 * @return string 2066 */ 1950 2067 public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) { 1951 2068 static $LAMEmiscSourceSampleFrequencyLookup = array( 1952 2069 0 => '<= 32 kHz', … … 1957 2074 return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : ''); 1958 2075 } 1959 2076 2077 /** 2078 * @param int $SurroundInfoID 2079 * 2080 * @return string 2081 */ 1960 2082 public static function LAMEsurroundInfoLookup($SurroundInfoID) { 1961 2083 static $LAMEsurroundInfoLookup = array( 1962 2084 0 => 'no surround info', … … 1967 2089 return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved'); 1968 2090 } 1969 2091 2092 /** 2093 * @param array $LAMEtag 2094 * 2095 * @return string 2096 */ 1970 2097 public static function LAMEpresetUsedLookup($LAMEtag) { 1971 2098 1972 2099 if ($LAMEtag['preset_used_id'] == 0) { -
src/wp-includes/ID3/module.audio.ogg.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.audio.ogg.php // 12 12 // module for analyzing Ogg Vorbis, OggFLAC and Speex files // … … 18 18 19 19 class getid3_ogg extends getid3_handler 20 20 { 21 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html 21 /** 22 * @link http://xiph.org/vorbis/doc/Vorbis_I_spec.html 23 * 24 * @return bool 25 */ 22 26 public function Analyze() { 23 27 $info = &$this->getid3->info; 24 28 … … 65 69 66 70 } elseif (substr($filedata, 0, 8) == 'OpusHead') { 67 71 68 if ( $this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) == false) {72 if ($this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) === false) { 69 73 return false; 70 74 } 71 75 … … 179 183 if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) { 180 184 $info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator']; 181 185 } 182 $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable');186 $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable'); 183 187 184 188 185 189 } elseif (substr($filedata, 0, 8) == "fishead\x00") { … … 259 263 $this->error('Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']'); 260 264 //return false; 261 265 266 } elseif (substr($filedata, 0, 5) == "\x7F".'FLAC') { 267 // https://xiph.org/flac/ogg_mapping.html 268 269 $info['audio']['dataformat'] = 'flac'; 270 $info['audio']['bitrate_mode'] = 'vbr'; 271 $info['audio']['lossless'] = true; 272 273 $info['ogg']['flac']['header']['version_major'] = ord(substr($filedata, 5, 1)); 274 $info['ogg']['flac']['header']['version_minor'] = ord(substr($filedata, 6, 1)); 275 $info['ogg']['flac']['header']['header_packets'] = getid3_lib::BigEndian2Int(substr($filedata, 7, 2)) + 1; // "A two-byte, big-endian binary number signifying the number of header (non-audio) packets, not including this one. This number may be zero (0x0000) to signify 'unknown' but be aware that some decoders may not be able to handle such streams." 276 $info['ogg']['flac']['header']['magic'] = substr($filedata, 9, 4); 277 if ($info['ogg']['flac']['header']['magic'] != 'fLaC') { 278 $this->error('Ogg-FLAC expecting "fLaC", found "'.$info['ogg']['flac']['header']['magic'].'" ('.trim(getid3_lib::PrintHexBytes($info['ogg']['flac']['header']['magic'])).')'); 279 return false; 280 } 281 $info['ogg']['flac']['header']['STREAMINFO_bytes'] = getid3_lib::BigEndian2Int(substr($filedata, 13, 4)); 282 $info['flac']['STREAMINFO'] = getid3_flac::parseSTREAMINFOdata(substr($filedata, 17, 34)); 283 if (!empty($info['flac']['STREAMINFO']['sample_rate'])) { 284 $info['audio']['bitrate_mode'] = 'vbr'; 285 $info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate']; 286 $info['audio']['channels'] = $info['flac']['STREAMINFO']['channels']; 287 $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample']; 288 $info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate']; 289 } 290 262 291 } else { 263 292 264 $this->error('Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"');293 $this->error('Expecting one of "vorbis", "Speex", "OpusHead", "vorbis", "fishhead", "theora", "fLaC" identifier strings, found "'.substr($filedata, 0, 8).'"'); 265 294 unset($info['ogg']); 266 295 unset($info['mime_type']); 267 296 return false; … … 378 407 return true; 379 408 } 380 409 410 /** 411 * @param string $filedata 412 * @param int $filedataoffset 413 * @param array $oggpageinfo 414 * 415 * @return bool 416 */ 381 417 public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) { 382 418 $info = &$this->getid3->info; 383 419 $info['audio']['dataformat'] = 'vorbis'; … … 426 462 return true; 427 463 } 428 464 429 // http://tools.ietf.org/html/draft-ietf-codec-oggopus-03 465 /** 466 * @link http://tools.ietf.org/html/draft-ietf-codec-oggopus-03 467 * 468 * @param string $filedata 469 * @param int $filedataoffset 470 * @param array $oggpageinfo 471 * 472 * @return bool 473 */ 430 474 public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) { 431 475 $info = &$this->getid3->info; 432 476 $info['audio']['dataformat'] = 'opus'; … … 458 502 $info['ogg']['pageheader']['opus']['pre_skip'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2)); 459 503 $filedataoffset += 2; 460 504 461 $info['ogg']['pageheader']['opus'][' sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));505 $info['ogg']['pageheader']['opus']['input_sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); 462 506 $filedataoffset += 4; 463 507 464 508 //$info['ogg']['pageheader']['opus']['output_gain'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2)); … … 467 511 //$info['ogg']['pageheader']['opus']['channel_mapping_family'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); 468 512 //$filedataoffset += 1; 469 513 470 $info['opus']['opus_version'] = $info['ogg']['pageheader']['opus']['version'];471 $info['opus']['sample_rate '] = $info['ogg']['pageheader']['opus']['sample_rate'];472 $info['opus']['out_channel_count'] = $info['ogg']['pageheader']['opus']['out_channel_count'];514 $info['opus']['opus_version'] = $info['ogg']['pageheader']['opus']['version']; 515 $info['opus']['sample_rate_input'] = $info['ogg']['pageheader']['opus']['input_sample_rate']; 516 $info['opus']['out_channel_count'] = $info['ogg']['pageheader']['opus']['out_channel_count']; 473 517 474 $info['audio']['channels'] = $info['opus']['out_channel_count']; 475 $info['audio']['sample_rate'] = $info['opus']['sample_rate']; 518 $info['audio']['channels'] = $info['opus']['out_channel_count']; 519 $info['audio']['sample_rate_input'] = $info['opus']['sample_rate_input']; 520 $info['audio']['sample_rate'] = 48000; // "All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz for playback (unless the target hardware does not support this sampling rate). However, this field may be used to resample the audio back to the original sampling rate, for example, when saving the output to a file." -- https://mf4.xiph.org/jenkins/view/opus/job/opusfile-unix/ws/doc/html/structOpusHead.html 476 521 return true; 477 522 } 478 523 479 524 /** 525 * @return array|false 526 */ 480 527 public function ParseOggPageHeader() { 481 528 // http://xiph.org/ogg/vorbis/doc/framing.html 482 529 $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file … … 489 536 return false; 490 537 } 491 538 if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) { 492 if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) {539 if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === '')) { 493 540 // get some more data, unless eof, in which case fail 494 541 return false; 495 542 } … … 528 575 return $oggheader; 529 576 } 530 577 531 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005 578 /** 579 * @link http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005 580 * 581 * @return bool 582 */ 532 583 public function ParseVorbisComments() { 533 584 $info = &$this->getid3->info; 534 585 535 586 $OriginalOffset = $this->ftell(); 587 $commentdata = null; 536 588 $commentdataoffset = 0; 537 589 $VorbisCommentPage = 1; 590 $CommentStartOffset = 0; 538 591 539 592 switch ($info['audio']['dataformat']) { 540 593 case 'vorbis': … … 765 818 return true; 766 819 } 767 820 821 /** 822 * @param int $mode 823 * 824 * @return string|null 825 */ 768 826 public static function SpeexBandModeLookup($mode) { 769 827 static $SpeexBandModeLookup = array(); 770 828 if (empty($SpeexBandModeLookup)) { … … 775 833 return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null); 776 834 } 777 835 778 836 /** 837 * @param array $OggInfoArray 838 * @param int $SegmentNumber 839 * 840 * @return int 841 */ 779 842 public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) { 843 $segmentlength = 0; 780 844 for ($i = 0; $i < $SegmentNumber; $i++) { 781 845 $segmentlength = 0; 782 846 foreach ($OggInfoArray['segment_table'] as $key => $value) { … … 789 853 return $segmentlength; 790 854 } 791 855 792 856 /** 857 * @param int $nominal_bitrate 858 * 859 * @return float 860 */ 793 861 public static function get_quality_from_nominal_bitrate($nominal_bitrate) { 794 862 795 863 // decrease precision … … 813 881 return round($qval, 1); // 5 or 4.9 814 882 } 815 883 884 /** 885 * @param int $colorspace_id 886 * 887 * @return string|null 888 */ 816 889 public static function TheoraColorSpace($colorspace_id) { 817 890 // http://www.theora.org/doc/Theora.pdf (table 6.3) 818 891 static $TheoraColorSpaceLookup = array(); … … 825 898 return (isset($TheoraColorSpaceLookup[$colorspace_id]) ? $TheoraColorSpaceLookup[$colorspace_id] : null); 826 899 } 827 900 901 /** 902 * @param int $pixelformat_id 903 * 904 * @return string|null 905 */ 828 906 public static function TheoraPixelFormat($pixelformat_id) { 829 907 // http://www.theora.org/doc/Theora.pdf (table 6.4) 830 908 static $TheoraPixelFormatLookup = array(); -
src/wp-includes/ID3/module.tag.apetag.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.tag.apetag.php // 12 12 // module for analyzing APE tags // … … 16 16 17 17 class getid3_apetag extends getid3_handler 18 18 { 19 public $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory 19 /** 20 * true: return full data for all attachments; 21 * false: return no data for all attachments; 22 * integer: return data for attachments <= than this; 23 * string: save as file to this directory. 24 * 25 * @var int|bool|string 26 */ 27 public $inline_attachments = true; 28 20 29 public $overrideendoffset = 0; 21 30 31 /** 32 * @return bool 33 */ 22 34 public function Analyze() { 23 35 $info = &$this->getid3->info; 24 36 … … 150 162 switch (strtolower($item_key)) { 151 163 // http://wiki.hydrogenaud.io/index.php?title=ReplayGain#MP3Gain 152 164 case 'replaygain_track_gain': 153 if (preg_match('#^ [\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {154 $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $ thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!165 if (preg_match('#^([\\-\\+][0-9\\.,]{8})( dB)?$#', $thisfile_ape_items_current['data'][0], $matches)) { 166 $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero! 155 167 $thisfile_replaygain['track']['originator'] = 'unspecified'; 156 168 } else { 157 169 $this->warning('MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); … … 159 171 break; 160 172 161 173 case 'replaygain_track_peak': 162 if (preg_match('#^ [0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {163 $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $ thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!174 if (preg_match('#^([0-9\\.,]{8})$#', $thisfile_ape_items_current['data'][0], $matches)) { 175 $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero! 164 176 $thisfile_replaygain['track']['originator'] = 'unspecified'; 165 177 if ($thisfile_replaygain['track']['peak'] <= 0) { 166 178 $this->warning('ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'); … … 171 183 break; 172 184 173 185 case 'replaygain_album_gain': 174 if (preg_match('#^ [\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {175 $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $ thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!186 if (preg_match('#^([\\-\\+][0-9\\.,]{8})( dB)?$#', $thisfile_ape_items_current['data'][0], $matches)) { 187 $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero! 176 188 $thisfile_replaygain['album']['originator'] = 'unspecified'; 177 189 } else { 178 190 $this->warning('MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); … … 180 192 break; 181 193 182 194 case 'replaygain_album_peak': 183 if (preg_match('#^ [0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {184 $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $ thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!195 if (preg_match('#^([0-9\\.,]{8})$#', $thisfile_ape_items_current['data'][0], $matches)) { 196 $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero! 185 197 $thisfile_replaygain['album']['originator'] = 'unspecified'; 186 198 if ($thisfile_replaygain['album']['peak'] <= 0) { 187 199 $this->warning('ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'); … … 225 237 case 'tracknumber': 226 238 if (is_array($thisfile_ape_items_current['data'])) { 227 239 foreach ($thisfile_ape_items_current['data'] as $comment) { 228 $thisfile_ape['comments']['track '][] = $comment;240 $thisfile_ape['comments']['track_number'][] = $comment; 229 241 } 230 242 } 231 243 break; … … 335 347 return true; 336 348 } 337 349 350 /** 351 * @param string $APEheaderFooterData 352 * 353 * @return array|false 354 */ 338 355 public function parseAPEheaderFooter($APEheaderFooterData) { 339 356 // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html 340 357 … … 359 376 return $headerfooterinfo; 360 377 } 361 378 379 /** 380 * @param int $rawflagint 381 * 382 * @return array 383 */ 362 384 public function parseAPEtagFlags($rawflagint) { 363 385 // "Note: APE Tags 1.0 do not use any of the APE Tag flags. 364 386 // All are set to zero on creation and ignored on reading." … … 374 396 return $flags; 375 397 } 376 398 399 /** 400 * @param int $contenttypeid 401 * 402 * @return string 403 */ 377 404 public function APEcontentTypeFlagLookup($contenttypeid) { 378 405 static $APEcontentTypeFlagLookup = array( 379 406 0 => 'utf-8', … … 384 411 return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid'); 385 412 } 386 413 414 /** 415 * @param string $itemkey 416 * 417 * @return bool 418 */ 387 419 public function APEtagItemIsUTF8Lookup($itemkey) { 388 420 static $APEtagItemIsUTF8Lookup = array( 389 421 'title', -
src/wp-includes/ID3/module.tag.id3v1.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 // // 11 11 // module.tag.id3v1.php // 12 12 // module for analyzing ID3v1 tags // … … 17 17 18 18 class getid3_id3v1 extends getid3_handler 19 19 { 20 20 /** 21 * @return bool 22 */ 21 23 public function Analyze() { 22 24 $info = &$this->getid3->info; 23 25 … … 43 45 44 46 // If second-last byte of comment field is null and last byte of comment field is non-null 45 47 // then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number 46 if (($id3v1tag {125} === "\x00") && ($id3v1tag{126}!== "\x00")) {47 $ParsedID3v1['track ']= ord(substr($ParsedID3v1['comment'], 29, 1));48 $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);48 if (($id3v1tag[125] === "\x00") && ($id3v1tag[126] !== "\x00")) { 49 $ParsedID3v1['track_number'] = ord(substr($ParsedID3v1['comment'], 29, 1)); 50 $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28); 49 51 } 50 52 $ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']); 51 53 … … 66 68 $ID3v1encoding = 'ISO-8859-1'; 67 69 foreach ($ParsedID3v1['comments'] as $tag_key => $valuearray) { 68 70 foreach ($valuearray as $key => $value) { 69 if (preg_match('#^[\\x00-\\x40\\xA8\\ B8\\x80-\\xFF]+$#', $value)) {71 if (preg_match('#^[\\x00-\\x40\\xA8\\xB8\\x80-\\xFF]+$#', $value)) { 70 72 foreach (array('Windows-1251', 'KOI8-R') as $id3v1_bad_encoding) { 71 73 if (function_exists('mb_convert_encoding') && @mb_convert_encoding($value, $id3v1_bad_encoding, $id3v1_bad_encoding) === $value) { 72 74 $ID3v1encoding = $id3v1_bad_encoding; … … 89 91 $ParsedID3v1['year'], 90 92 (isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false), 91 93 $ParsedID3v1['comment'], 92 (!empty($ParsedID3v1['track ']) ? $ParsedID3v1['track'] : ''));94 (!empty($ParsedID3v1['track_number']) ? $ParsedID3v1['track_number'] : '')); 93 95 $ParsedID3v1['padding_valid'] = true; 94 96 if ($id3v1tag !== $GoodFormatID3v1tag) { 95 97 $ParsedID3v1['padding_valid'] = false; … … 124 126 return true; 125 127 } 126 128 129 /** 130 * @param string $str 131 * 132 * @return string 133 */ 127 134 public static function cutfield($str) { 128 135 return trim(substr($str, 0, strcspn($str, "\x00"))); 129 136 } 130 137 138 /** 139 * @param bool $allowSCMPXextended 140 * 141 * @return string[] 142 */ 131 143 public static function ArrayOfGenres($allowSCMPXextended=false) { 132 144 static $GenreLookup = array( 133 145 0 => 'Blues', … … 312 324 return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup); 313 325 } 314 326 327 /** 328 * @param string $genreid 329 * @param bool $allowSCMPXextended 330 * 331 * @return string|false 332 */ 315 333 public static function LookupGenreName($genreid, $allowSCMPXextended=true) { 316 334 switch ($genreid) { 317 335 case 'RX': … … 328 346 return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false); 329 347 } 330 348 349 /** 350 * @param string $genre 351 * @param bool $allowSCMPXextended 352 * 353 * @return string|false 354 */ 331 355 public static function LookupGenreID($genre, $allowSCMPXextended=false) { 332 356 $GenreLookup = self::ArrayOfGenres($allowSCMPXextended); 333 357 $LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre)); … … 339 363 return false; 340 364 } 341 365 366 /** 367 * @param string $OriginalGenre 368 * 369 * @return string|false 370 */ 342 371 public static function StandardiseID3v1GenreName($OriginalGenre) { 343 372 if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) { 344 373 return self::LookupGenreName($GenreID); … … 346 375 return $OriginalGenre; 347 376 } 348 377 378 /** 379 * @param string $title 380 * @param string $artist 381 * @param string $album 382 * @param string $year 383 * @param int $genreid 384 * @param string $comment 385 * @param int|string $track 386 * 387 * @return string 388 */ 349 389 public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') { 350 390 $ID3v1Tag = 'TAG'; 351 391 $ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT); -
src/wp-includes/ID3/module.tag.id3v2.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 /// // 11 11 // module.tag.id3v2.php // 12 12 // module for analyzing ID3v2 tags // … … 20 20 { 21 21 public $StartingOffset = 0; 22 22 23 /** 24 * @return bool 25 */ 23 26 public function Analyze() { 24 27 $info = &$this->getid3->info; 25 28 … … 56 59 $header = $this->fread(10); 57 60 if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) { 58 61 59 $thisfile_id3v2['majorversion'] = ord($header {3});60 $thisfile_id3v2['minorversion'] = ord($header {4});62 $thisfile_id3v2['majorversion'] = ord($header[3]); 63 $thisfile_id3v2['minorversion'] = ord($header[4]); 61 64 62 65 // shortcut 63 66 $id3v2_majorversion = &$thisfile_id3v2['majorversion']; … … 76 79 77 80 } 78 81 79 $id3_flags = ord($header {5});82 $id3_flags = ord($header[5]); 80 83 switch ($id3v2_majorversion) { 81 84 case 2: 82 85 // %ab000000 in v2.2 … … 257 260 $thisfile_id3v2['padding']['length'] = strlen($framedata); 258 261 $thisfile_id3v2['padding']['valid'] = true; 259 262 for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) { 260 if ($framedata {$i}!= "\x00") {263 if ($framedata[$i] != "\x00") { 261 264 $thisfile_id3v2['padding']['valid'] = false; 262 265 $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; 263 266 $this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'); … … 266 269 } 267 270 break; // skip rest of ID3v2 header 268 271 } 272 $frame_header = null; 273 $frame_name = null; 274 $frame_size = null; 275 $frame_flags = null; 269 276 if ($id3v2_majorversion == 2) { 270 277 // Frame ID $xx xx xx (three characters) 271 278 // Size $xx xx xx (24-bit integer) … … 319 326 320 327 $len = strlen($framedata); 321 328 for ($i = 0; $i < $len; $i++) { 322 if ($framedata {$i}!= "\x00") {329 if ($framedata[$i] != "\x00") { 323 330 $thisfile_id3v2['padding']['valid'] = false; 324 331 $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; 325 332 $this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'); … … 427 434 $footer = $this->fread(10); 428 435 if (substr($footer, 0, 3) == '3DI') { 429 436 $thisfile_id3v2['footer'] = true; 430 $thisfile_id3v2['majorversion_footer'] = ord($footer {3});431 $thisfile_id3v2['minorversion_footer'] = ord($footer {4});437 $thisfile_id3v2['majorversion_footer'] = ord($footer[3]); 438 $thisfile_id3v2['minorversion_footer'] = ord($footer[4]); 432 439 } 433 440 if ($thisfile_id3v2['majorversion_footer'] <= 4) { 434 $id3_flags = ord( substr($footer{5}));441 $id3_flags = ord($footer[5]); 435 442 $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80); 436 443 $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40); 437 444 $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20); … … 452 459 unset($key, $value, $genres, $genre); 453 460 } 454 461 455 if (isset($thisfile_id3v2['comments']['track '])) {456 foreach ($thisfile_id3v2['comments']['track '] as $key => $value) {462 if (isset($thisfile_id3v2['comments']['track_number'])) { 463 foreach ($thisfile_id3v2['comments']['track_number'] as $key => $value) { 457 464 if (strstr($value, '/')) { 458 list($thisfile_id3v2['comments']['track num'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);465 list($thisfile_id3v2['comments']['track_number'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track_number'][$key]); 459 466 } 460 467 } 461 468 } … … 498 505 return true; 499 506 } 500 507 501 508 /** 509 * @param string $genrestring 510 * 511 * @return array 512 */ 502 513 public function ParseID3v2GenreString($genrestring) { 503 514 // Parse genres into arrays of genreName and genreID 504 515 // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)' … … 530 541 foreach ($genre_elements as $element) { 531 542 $element = trim($element); 532 543 if ($element) { 533 if (preg_match('#^[0-9]{1,3} #', $element)) {544 if (preg_match('#^[0-9]{1,3}$#', $element)) { 534 545 $clean_genres[] = getid3_id3v1::LookupGenreName($element); 535 546 } else { 536 547 $clean_genres[] = str_replace('((', '(', $element); … … 540 551 return $clean_genres; 541 552 } 542 553 543 554 /** 555 * @param array $parsedFrame 556 * 557 * @return bool 558 */ 544 559 public function ParseID3v2Frame(&$parsedFrame) { 545 560 546 561 // shortcuts … … 657 672 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 658 673 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 659 674 } 660 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 661 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 662 // if description only contains a BOM or terminator then make it blank 663 $frame_description = ''; 664 } 675 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 676 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 665 677 $parsedFrame['encodingid'] = $frame_textencoding; 666 678 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 667 679 668 $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $ frame_description));680 $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['description'])); 669 681 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 682 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator); 670 683 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 671 684 $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0)); 672 685 if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) { … … 678 691 //unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain 679 692 680 693 681 } elseif ($parsedFrame['frame_name'] {0}== 'T') { // 4.2. T??[?] Text information frame694 } elseif ($parsedFrame['frame_name'][0] == 'T') { // 4.2. T??[?] Text information frame 682 695 // There may only be one text information frame of its kind in an tag. 683 696 // <Header for 'Text information frame', ID: 'T000' - 'TZZZ', 684 697 // excluding 'TXXX' described in 4.2.6.> … … 692 705 } 693 706 694 707 $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); 708 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding)); 695 709 696 710 $parsedFrame['encodingid'] = $frame_textencoding; 697 711 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 698 699 712 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 700 713 // ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with / 701 714 // This of course breaks when an artist name contains slash character, e.g. "AC/DC" … … 751 764 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 752 765 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 753 766 } 754 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);755 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {756 // if description only contains a BOM or terminator then make it blank757 $frame_description = '';758 }759 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));760 761 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);762 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {763 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00764 }765 if ($frame_terminatorpos) {766 // there are null bytes after the data - this is not according to spec767 // only use data up to first null byte768 $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);769 } else {770 // no null bytes following data, just use all data771 $frame_urldata = (string) $parsedFrame['data'];772 }773 774 767 $parsedFrame['encodingid'] = $frame_textencoding; 775 768 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 769 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); // according to the frame text encoding 770 $parsedFrame['url'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); // always ISO-8859-1 771 $parsedFrame['description'] = $this->RemoveStringTerminator($parsedFrame['description'], $frame_textencoding_terminator); 772 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 776 773 777 $parsedFrame['url'] = $frame_urldata;778 $parsedFrame['description'] = $frame_description;779 774 if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { 780 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback( $parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);775 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback('ISO-8859-1', $info['id3v2']['encoding'], $parsedFrame['url']); 781 776 } 782 777 unset($parsedFrame['data']); 783 778 784 779 785 } elseif ($parsedFrame['frame_name'] {0}== 'W') { // 4.3. W??? URL link frames780 } elseif ($parsedFrame['frame_name'][0] == 'W') { // 4.3. W??? URL link frames 786 781 // There may only be one URL link frame of its kind in a tag, 787 782 // except when stated otherwise in the frame description 788 783 // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX' … … 789 784 // described in 4.3.2.> 790 785 // URL <text string> 791 786 792 $parsedFrame['url'] = trim($parsedFrame['data']); 787 $parsedFrame['url'] = trim($parsedFrame['data']); // always ISO-8859-1 793 788 if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { 794 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];789 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback('ISO-8859-1', $info['id3v2']['encoding'], $parsedFrame['url']); 795 790 } 796 791 unset($parsedFrame['data']); 797 792 … … 813 808 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']); 814 809 $parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset); 815 810 816 // http ://www.getid3.org/phpBB3/viewtopic.php?t=1369811 // https://www.getid3.org/phpBB3/viewtopic.php?t=1369 817 812 // "this tag typically contains null terminated strings, which are associated in pairs" 818 813 // "there are users that use the tag incorrectly" 819 814 $IPLS_parts = array(); … … 933 928 $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1)); 934 929 $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1)); 935 930 $parsedFrame['data'] = substr($parsedFrame['data'], 10); 931 $deviationbitstream = ''; 936 932 while ($frame_offset < strlen($parsedFrame['data'])) { 937 933 $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1)); 938 934 } … … 994 990 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 995 991 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 996 992 } 997 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 998 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 999 // if description only contains a BOM or terminator then make it blank 1000 $frame_description = ''; 1001 } 993 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 994 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1002 995 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 996 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator); 1003 997 1004 998 $parsedFrame['encodingid'] = $frame_textencoding; 1005 999 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); … … 1006 1000 1007 1001 $parsedFrame['language'] = $frame_language; 1008 1002 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); 1009 $parsedFrame['description'] = $frame_description;1010 1003 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 1011 1004 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); 1012 1005 } … … 1061 1054 $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset); 1062 1055 1063 1056 $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1064 if (($timestampindex == 0) && (ord($frame_remainingdata {0}) != 0)) {1057 if (($timestampindex == 0) && (ord($frame_remainingdata[0]) != 0)) { 1065 1058 // timestamp probably omitted for first data item 1066 1059 } else { 1067 1060 $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4)); … … 1102 1095 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1103 1096 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1104 1097 } 1105 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1106 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1107 // if description only contains a BOM or terminator then make it blank 1108 $frame_description = ''; 1109 } 1098 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1099 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1110 1100 $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1101 $frame_text = $this->RemoveStringTerminator($frame_text, $frame_textencoding_terminator); 1111 1102 1112 1103 $parsedFrame['encodingid'] = $frame_textencoding; 1113 1104 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); … … 1114 1105 1115 1106 $parsedFrame['language'] = $frame_language; 1116 1107 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); 1117 $parsedFrame['description'] = $frame_description;1118 1108 $parsedFrame['data'] = $frame_text; 1119 1109 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 1120 1110 $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0)); … … 1407 1397 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1408 1398 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1409 1399 } 1410 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1411 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1412 // if description only contains a BOM or terminator then make it blank 1413 $frame_description = ''; 1414 } 1415 $parsedFrame['encodingid'] = $frame_textencoding; 1416 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 1400 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1401 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1402 $parsedFrame['encodingid'] = $frame_textencoding; 1403 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 1417 1404 1418 1405 if ($id3v2_majorversion == 2) { 1419 $parsedFrame['imagetype'] = $frame_imagetype;1406 $parsedFrame['imagetype'] = isset($frame_imagetype) ? $frame_imagetype : null; 1420 1407 } else { 1421 $parsedFrame['mime'] = $frame_mimetype;1408 $parsedFrame['mime'] = isset($frame_mimetype) ? $frame_mimetype : null; 1422 1409 } 1423 $parsedFrame['picturetypeid'] = $frame_picturetype; 1424 $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype); 1425 $parsedFrame['description'] = $frame_description; 1426 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1427 $parsedFrame['datalength'] = strlen($parsedFrame['data']); 1410 $parsedFrame['picturetypeid'] = $frame_picturetype; 1411 $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype); 1412 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1413 $parsedFrame['datalength'] = strlen($parsedFrame['data']); 1428 1414 1429 $parsedFrame['image_mime'] = '';1415 $parsedFrame['image_mime'] = ''; 1430 1416 $imageinfo = array(); 1431 1417 if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) { 1432 1418 if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) { 1433 $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);1419 $parsedFrame['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); 1434 1420 if ($imagechunkcheck[0]) { 1435 1421 $parsedFrame['image_width'] = $imagechunkcheck[0]; 1436 1422 } … … 1446 1432 unset($parsedFrame['data']); 1447 1433 break; 1448 1434 } 1435 $dir = ''; 1449 1436 if ($this->getid3->option_save_attachments === true) { 1450 1437 // great 1451 1438 /* … … 1533 1520 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1534 1521 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1535 1522 } 1536 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1537 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1538 // if description only contains a BOM or terminator then make it blank 1539 $frame_description = ''; 1540 } 1523 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1524 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1541 1525 $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator); 1542 1526 1543 1527 $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset); … … 1546 1530 1547 1531 $parsedFrame['mime'] = $frame_mimetype; 1548 1532 $parsedFrame['filename'] = $frame_filename; 1549 $parsedFrame['description'] = $frame_description;1550 1533 unset($parsedFrame['data']); 1551 1534 1552 1535 … … 1616 1599 $frame_offset = $frame_terminatorpos + strlen("\x00"); 1617 1600 1618 1601 $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); 1619 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1620 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1621 // if description only contains a BOM or terminator then make it blank 1622 $frame_description = ''; 1623 } 1602 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1603 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1624 1604 $frame_offset = $frame_terminatorpos + strlen("\x00"); 1625 1605 1626 1606 $parsedFrame['ownerid'] = $frame_ownerid; 1627 1607 $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); 1628 $parsedFrame['description'] = $frame_description;1629 1608 unset($parsedFrame['data']); 1630 1609 1631 1610 … … 1721 1700 $parsedFrame['encodingid'] = $frame_textencoding; 1722 1701 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 1723 1702 1724 $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); 1703 $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); 1704 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding)); 1725 1705 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 1726 1706 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); 1727 1707 } … … 1759 1739 $frame_offset += 8; 1760 1740 1761 1741 $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset); 1742 $parsedFrame['seller'] = $this->RemoveStringTerminator($parsedFrame['seller'], $this->TextEncodingTerminatorLookup($frame_textencoding)); 1762 1743 unset($parsedFrame['data']); 1763 1744 1764 1745 … … 1817 1798 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1818 1799 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1819 1800 } 1820 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1821 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1822 // if description only contains a BOM or terminator then make it blank 1823 $frame_description = ''; 1824 } 1801 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1802 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1825 1803 $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator); 1826 1804 1827 1805 $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); … … 1838 1816 $parsedFrame['receivedasid'] = $frame_receivedasid; 1839 1817 $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid); 1840 1818 $parsedFrame['sellername'] = $frame_sellername; 1841 $parsedFrame['description'] = $frame_description;1842 1819 $parsedFrame['mime'] = $frame_mimetype; 1843 1820 $parsedFrame['logo'] = $frame_sellerlogo; 1844 1821 unset($parsedFrame['data']); … … 2002 1979 // Element ID <text string> $00 2003 1980 // Start time $xx xx xx xx 2004 1981 // End time $xx xx xx xx 2005 // Start offset $xx xx xx xx2006 // End offset $xx xx xx xx2007 // <Optional embedded sub-frames>1982 // Start offset $xx xx xx xx 1983 // End offset $xx xx xx xx 1984 // <Optional embedded sub-frames> 2008 1985 2009 1986 $frame_offset = 0; 2010 1987 @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2); … … 2045 2022 $subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1)); 2046 2023 $subframe['text'] = substr($subframe_rawdata, 1); 2047 2024 $subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']); 2048 $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text'])); ;2025 $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text'])); 2049 2026 switch (substr($encoding_converted_text, 0, 2)) { 2050 2027 case "\xFF\xFE": 2051 2028 case "\xFE\xFF": … … 2065 2042 break; 2066 2043 } 2067 2044 2068 if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {2069 if ($subframe['name'] == 'TIT2') {2045 switch ($subframe['name']) { 2046 case 'TIT2': 2070 2047 $parsedFrame['chapter_name'] = $encoding_converted_text; 2071 } elseif ($subframe['name'] == 'TIT3') { 2048 $parsedFrame['subframes'][] = $subframe; 2049 break; 2050 case 'TIT3': 2072 2051 $parsedFrame['chapter_description'] = $encoding_converted_text; 2073 } 2074 $parsedFrame['subframes'][] = $subframe; 2075 } else { 2076 $this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)'); 2052 $parsedFrame['subframes'][] = $subframe; 2053 break; 2054 case 'WXXX': 2055 list($subframe['chapter_url_description'], $subframe['chapter_url']) = explode("\x00", $encoding_converted_text, 2); 2056 $parsedFrame['chapter_url'][$subframe['chapter_url_description']] = $subframe['chapter_url']; 2057 $parsedFrame['subframes'][] = $subframe; 2058 break; 2059 case 'APIC': 2060 if (preg_match('#^([^\\x00]+)*\\x00(.)([^\\x00]+)*\\x00(.+)$#s', $subframe['text'], $matches)) { 2061 list($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata) = $matches; 2062 $subframe['image_mime'] = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_mime)); 2063 $subframe['picture_type'] = $this->APICPictureTypeLookup($subframe_apic_picturetype); 2064 $subframe['description'] = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_description)); 2065 if (strlen($this->TextEncodingTerminatorLookup($subframe['encoding'])) == 2) { 2066 // the null terminator between "description" and "picture data" could be either 1 byte (ISO-8859-1, UTF-8) or two bytes (UTF-16) 2067 // the above regex assumes one byte, if it's actually two then strip the second one here 2068 $subframe_apic_picturedata = substr($subframe_apic_picturedata, 1); 2069 } 2070 $subframe['data'] = $subframe_apic_picturedata; 2071 unset($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata); 2072 unset($subframe['text'], $parsedFrame['text']); 2073 $parsedFrame['subframes'][] = $subframe; 2074 $parsedFrame['picture_present'] = true; 2075 } else { 2076 $this->warning('ID3v2.CHAP subframe #'.(count($parsedFrame['subframes']) + 1).' "'.$subframe['name'].'" not in expected format'); 2077 } 2078 break; 2079 default: 2080 $this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (supported: TIT2, TIT3, WXXX, APIC)'); 2081 break; 2077 2082 } 2078 2083 } 2079 2084 unset($subframe_rawdata, $subframe, $encoding_converted_text); 2085 unset($parsedFrame['data']); // debatable whether this this be here, without it the returned structure may contain a large amount of duplicate data if chapters contain APIC 2080 2086 } 2081 2087 2082 2088 $id3v2_chapter_entry = array(); 2083 foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description' ) as $id3v2_chapter_key) {2089 foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description', 'chapter_url', 'picture_present') as $id3v2_chapter_key) { 2084 2090 if (isset($parsedFrame[$id3v2_chapter_key])) { 2085 2091 $id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key]; 2086 2092 } … … 2099 2105 // CTOC flags %xx 2100 2106 // Entry count $xx 2101 2107 // Child Element ID <string>$00 /* zero or more child CHAP or CTOC entries */ 2102 // <Optional embedded sub-frames>2108 // <Optional embedded sub-frames> 2103 2109 2104 2110 $frame_offset = 0; 2105 2111 @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2); … … 2181 2187 return true; 2182 2188 } 2183 2189 2184 2190 /** 2191 * @param string $data 2192 * 2193 * @return string 2194 */ 2185 2195 public function DeUnsynchronise($data) { 2186 2196 return str_replace("\xFF\x00", "\xFF", $data); 2187 2197 } 2188 2198 2199 /** 2200 * @param int $index 2201 * 2202 * @return string 2203 */ 2189 2204 public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) { 2190 2205 static $LookupExtendedHeaderRestrictionsTagSizeLimits = array( 2191 2206 0x00 => 'No more than 128 frames and 1 MB total tag size', … … 2196 2211 return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : ''); 2197 2212 } 2198 2213 2214 /** 2215 * @param int $index 2216 * 2217 * @return string 2218 */ 2199 2219 public function LookupExtendedHeaderRestrictionsTextEncodings($index) { 2200 2220 static $LookupExtendedHeaderRestrictionsTextEncodings = array( 2201 2221 0x00 => 'No restrictions', … … 2204 2224 return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : ''); 2205 2225 } 2206 2226 2227 /** 2228 * @param int $index 2229 * 2230 * @return string 2231 */ 2207 2232 public function LookupExtendedHeaderRestrictionsTextFieldSize($index) { 2208 2233 static $LookupExtendedHeaderRestrictionsTextFieldSize = array( 2209 2234 0x00 => 'No restrictions', … … 2214 2239 return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : ''); 2215 2240 } 2216 2241 2242 /** 2243 * @param int $index 2244 * 2245 * @return string 2246 */ 2217 2247 public function LookupExtendedHeaderRestrictionsImageEncoding($index) { 2218 2248 static $LookupExtendedHeaderRestrictionsImageEncoding = array( 2219 2249 0x00 => 'No restrictions', … … 2222 2252 return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : ''); 2223 2253 } 2224 2254 2255 /** 2256 * @param int $index 2257 * 2258 * @return string 2259 */ 2225 2260 public function LookupExtendedHeaderRestrictionsImageSizeSize($index) { 2226 2261 static $LookupExtendedHeaderRestrictionsImageSizeSize = array( 2227 2262 0x00 => 'No restrictions', … … 2232 2267 return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : ''); 2233 2268 } 2234 2269 2270 /** 2271 * @param string $currencyid 2272 * 2273 * @return string 2274 */ 2235 2275 public function LookupCurrencyUnits($currencyid) { 2236 2276 2237 2277 $begin = __LINE__; … … 2428 2468 return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units'); 2429 2469 } 2430 2470 2431 2471 /** 2472 * @param string $currencyid 2473 * 2474 * @return string 2475 */ 2432 2476 public function LookupCurrencyCountry($currencyid) { 2433 2477 2434 2478 $begin = __LINE__; … … 2624 2668 return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country'); 2625 2669 } 2626 2670 2627 2628 2671 /** 2672 * @param string $languagecode 2673 * @param bool $casesensitive 2674 * 2675 * @return string 2676 */ 2629 2677 public static function LanguageLookup($languagecode, $casesensitive=false) { 2630 2678 2631 2679 if (!$casesensitive) { … … 3081 3129 return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode'); 3082 3130 } 3083 3131 3084 3132 /** 3133 * @param int $index 3134 * 3135 * @return string 3136 */ 3085 3137 public static function ETCOEventLookup($index) { 3086 3138 if (($index >= 0x17) && ($index <= 0xDF)) { 3087 3139 return 'reserved for future use'; … … 3125 3177 return (isset($EventLookup[$index]) ? $EventLookup[$index] : ''); 3126 3178 } 3127 3179 3180 /** 3181 * @param int $index 3182 * 3183 * @return string 3184 */ 3128 3185 public static function SYTLContentTypeLookup($index) { 3129 3186 static $SYTLContentTypeLookup = array( 3130 3187 0x00 => 'other', … … 3141 3198 return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : ''); 3142 3199 } 3143 3200 3201 /** 3202 * @param int $index 3203 * @param bool $returnarray 3204 * 3205 * @return array|string 3206 */ 3144 3207 public static function APICPictureTypeLookup($index, $returnarray=false) { 3145 3208 static $APICPictureTypeLookup = array( 3146 3209 0x00 => 'Other', … … 3171 3234 return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : ''); 3172 3235 } 3173 3236 3237 /** 3238 * @param int $index 3239 * 3240 * @return string 3241 */ 3174 3242 public static function COMRReceivedAsLookup($index) { 3175 3243 static $COMRReceivedAsLookup = array( 3176 3244 0x00 => 'Other', … … 3187 3255 return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : ''); 3188 3256 } 3189 3257 3258 /** 3259 * @param int $index 3260 * 3261 * @return string 3262 */ 3190 3263 public static function RVA2ChannelTypeLookup($index) { 3191 3264 static $RVA2ChannelTypeLookup = array( 3192 3265 0x00 => 'Other', … … 3203 3276 return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : ''); 3204 3277 } 3205 3278 3279 /** 3280 * @param string $framename 3281 * 3282 * @return string 3283 */ 3206 3284 public static function FrameNameLongLookup($framename) { 3207 3285 3208 3286 $begin = __LINE__; … … 3354 3432 TYER Year 3355 3433 UFI Unique file identifier 3356 3434 UFID Unique file identifier 3357 ULT Unsy chronised lyric/text transcription3435 ULT Unsynchronised lyric/text transcription 3358 3436 USER Terms of use 3359 3437 USLT Unsynchronised lyric/text transcription 3360 3438 WAF Official audio file webpage … … 3386 3464 // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html 3387 3465 } 3388 3466 3389 3467 /** 3468 * @param string $framename 3469 * 3470 * @return string 3471 */ 3390 3472 public static function FrameNameShortLookup($framename) { 3391 3473 3392 3474 $begin = __LINE__; … … 3538 3620 TYER year 3539 3621 UFI unique_file_identifier 3540 3622 UFID unique_file_identifier 3541 ULT unsy chronised_lyric3623 ULT unsynchronised_lyric 3542 3624 USER terms_of_use 3543 3625 USLT unsynchronised_lyric 3544 3626 WAF url_file … … 3566 3648 return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short'); 3567 3649 } 3568 3650 3651 /** 3652 * @param string $encoding 3653 * 3654 * @return string 3655 */ 3569 3656 public static function TextEncodingTerminatorLookup($encoding) { 3570 3657 // http://www.id3.org/id3v2.4.0-structure.txt 3571 3658 // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: … … 3579 3666 return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00"); 3580 3667 } 3581 3668 3669 /** 3670 * @param int $encoding 3671 * 3672 * @return string 3673 */ 3582 3674 public static function TextEncodingNameLookup($encoding) { 3583 3675 // http://www.id3.org/id3v2.4.0-structure.txt 3584 3676 // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: … … 3592 3684 return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1'); 3593 3685 } 3594 3686 3687 /** 3688 * @param string $string 3689 * @param string $terminator 3690 * 3691 * @return string 3692 */ 3693 public static function RemoveStringTerminator($string, $terminator) { 3694 // Null terminator at end of comment string is somewhat ambiguous in the specification, may or may not be implemented by various taggers. Remove terminator only if present. 3695 // https://github.com/JamesHeinrich/getID3/issues/121 3696 // https://community.mp3tag.de/t/x-trailing-nulls-in-id3v2-comments/19227 3697 if (substr($string, -strlen($terminator), strlen($terminator)) === $terminator) { 3698 $string = substr($string, 0, -strlen($terminator)); 3699 } 3700 return $string; 3701 } 3702 3703 /** 3704 * @param string $string 3705 * 3706 * @return string 3707 */ 3708 public static function MakeUTF16emptyStringEmpty($string) { 3709 if (in_array($string, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 3710 // if string only contains a BOM or terminator then make it actually an empty string 3711 $string = ''; 3712 } 3713 return $string; 3714 } 3715 3716 /** 3717 * @param string $framename 3718 * @param int $id3v2majorversion 3719 * 3720 * @return bool|int 3721 */ 3595 3722 public static function IsValidID3v2FrameName($framename, $id3v2majorversion) { 3596 3723 switch ($id3v2majorversion) { 3597 3724 case 2: … … 3606 3733 return false; 3607 3734 } 3608 3735 3736 /** 3737 * @param string $numberstring 3738 * @param bool $allowdecimal 3739 * @param bool $allownegative 3740 * 3741 * @return bool 3742 */ 3609 3743 public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) { 3610 3744 for ($i = 0; $i < strlen($numberstring); $i++) { 3611 if ((chr($numberstring {$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {3612 if (($numberstring {$i}== '.') && $allowdecimal) {3745 if ((chr($numberstring[$i]) < chr('0')) || (chr($numberstring[$i]) > chr('9'))) { 3746 if (($numberstring[$i] == '.') && $allowdecimal) { 3613 3747 // allowed 3614 } elseif (($numberstring {$i}== '-') && $allownegative && ($i == 0)) {3748 } elseif (($numberstring[$i] == '-') && $allownegative && ($i == 0)) { 3615 3749 // allowed 3616 3750 } else { 3617 3751 return false; … … 3621 3755 return true; 3622 3756 } 3623 3757 3758 /** 3759 * @param string $datestamp 3760 * 3761 * @return bool 3762 */ 3624 3763 public static function IsValidDateStampString($datestamp) { 3625 3764 if (strlen($datestamp) != 8) { 3626 3765 return false; … … 3649 3788 return true; 3650 3789 } 3651 3790 3791 /** 3792 * @param int $majorversion 3793 * 3794 * @return int 3795 */ 3652 3796 public static function ID3v2HeaderLength($majorversion) { 3653 3797 return (($majorversion == 2) ? 6 : 10); 3654 3798 } 3655 3799 3800 /** 3801 * @param string $frame_name 3802 * 3803 * @return string|false 3804 */ 3656 3805 public static function ID3v22iTunesBrokenFrameName($frame_name) { 3657 3806 // iTunes (multiple versions) has been known to write ID3v2.3 style frames 3658 3807 // but use ID3v2.2 frame names, right-padded using either [space] or [null] … … 3739 3888 } 3740 3889 3741 3890 } 3891 -
src/wp-includes/ID3/module.tag.lyrics3.php
1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 7 9 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details //9 /////////////////////////////////////////////////////////////////10 10 /// // 11 11 // module.tag.lyrics3.php // 12 12 // module for analyzing Lyrics3 tags // … … 17 17 18 18 class getid3_lyrics3 extends getid3_handler 19 19 { 20 20 /** 21 * @return bool 22 */ 21 23 public function Analyze() { 22 24 $info = &$this->getid3->info; 23 25 … … 61 63 62 64 // Lyrics3v2, no ID3v1, no APE 63 65 64 $lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'66 $lyrics3size = (int) strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' 65 67 $lyrics3offset = $info['filesize'] - $lyrics3size; 66 68 $lyrics3version = 2; 67 69 … … 96 98 97 99 } 98 100 99 if (isset($lyrics3offset) ) {101 if (isset($lyrics3offset) && isset($lyrics3version) && isset($lyrics3size)) { 100 102 $info['avdataend'] = $lyrics3offset; 101 103 $this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size); 102 104 … … 126 128 return true; 127 129 } 128 130 131 /** 132 * @param int $endoffset 133 * @param int $version 134 * @param int $length 135 * 136 * @return bool 137 */ 129 138 public function getLyrics3Data($endoffset, $version, $length) { 130 139 // http://www.volweb.cz/str/tags.htm 131 140 … … 142 151 } 143 152 $rawdata = $this->fread($length); 144 153 154 $ParsedLyrics3 = array(); 155 145 156 $ParsedLyrics3['raw']['lyrics3version'] = $version; 146 157 $ParsedLyrics3['raw']['lyrics3tagsize'] = $length; 147 158 $ParsedLyrics3['tag_offset_start'] = $endoffset; … … 250 261 return true; 251 262 } 252 263 264 /** 265 * @param string $rawtimestamp 266 * 267 * @return int|false 268 */ 253 269 public function Lyrics3Timestamp2Seconds($rawtimestamp) { 254 270 if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) { 255 271 return (int) (($regs[1] * 60) + $regs[2]); … … 257 273 return false; 258 274 } 259 275 276 /** 277 * @param array $Lyrics3data 278 * 279 * @return bool 280 */ 260 281 public function Lyrics3LyricsTimestampParse(&$Lyrics3data) { 261 282 $lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']); 283 $notimestamplyricsarray = array(); 262 284 foreach ($lyricsarray as $key => $lyricline) { 263 285 $regs = array(); 264 286 unset($thislinetimestamps); … … 287 309 return true; 288 310 } 289 311 312 /** 313 * @param string $char 314 * 315 * @return bool|null 316 */ 290 317 public function IntString2Bool($char) { 291 318 if ($char == '1') { 292 319 return true; -
src/wp-includes/ID3/readme.txt
1 1 ///////////////////////////////////////////////////////////////// 2 2 /// getID3() by James Heinrich <info@getid3.org> // 3 3 // available at http://getid3.sourceforge.net // 4 // or http ://www.getid3.org//4 // or https://www.getid3.org // 5 5 // also https://github.com/JamesHeinrich/getID3 // 6 6 ///////////////////////////////////////////////////////////////// 7 7 … … 18 18 19 19 GNU LGPL: https://gnu.org/licenses/lgpl.html (v3) 20 20 21 Mozilla MPL: http ://www.mozilla.org/MPL/2.0/(v2)21 Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2) 22 22 23 getID3 Commercial License: http ://getid3.org/#gCL (payment required)23 getID3 Commercial License: https://www.getid3.org/#gCL (payment required) 24 24 25 25 ***************************************************************** 26 26 ***************************************************************** … … 28 28 directory of the getID3 distribution. 29 29 30 30 31 +--------------------------------------------- +32 | If you want to donate, there is a link on |33 | http ://www.getid3.org for PayPal donations. |34 +--------------------------------------------- +31 +----------------------------------------------+ 32 | If you want to donate, there is a link on | 33 | https://www.getid3.org for PayPal donations. | 34 +----------------------------------------------+ 35 35 36 36 37 37 Quick Start … … 77 77 ¤ audio-lossy: 78 78 * MP3/MP2/MP1 79 79 * MPC / Musepack 80 * Ogg (Vorbis, OggFLAC, Speex )80 * Ogg (Vorbis, OggFLAC, Speex, Opus) 81 81 * AAC / MP4 82 82 * AC3 83 83 * DTS … … 145 145 Requirements 146 146 =========================================================================== 147 147 148 * PHP 4.2.0 up to 5.2.x for getID3() 1.7.x (and earlier) 149 * PHP 5.0.5 (or higher) for getID3() 1.8.x (and up) 150 * PHP 5.0.5 (or higher) for getID3() 2.0.x (and up) 148 * PHP 4.2.0 up to 5.2.x for getID3() 1.7.x (and earlier) 149 * PHP 5.0.5 (or higher) for getID3() 1.8.x (and up) 150 * PHP 5.3.0 (or higher) for getID3() 1.9.17 (and up) 151 * PHP 5.3.0 (or higher) for getID3() 2.0.x (and up) 151 152 * at least 4MB memory for PHP. 8MB or more is highly recommended. 152 153 12MB is required with all modules loaded. 153 154 … … 177 178 // Copy remote file locally to scan with getID3() 178 179 $remotefilename = 'http://www.example.com/filename.mp3'; 179 180 if ($fp_remote = fopen($remotefilename, 'rb')) { 180 $localtempfilename = tempnam('/tmp', 'getID3');181 if ($fp_local = fopen($localtempfilename, 'wb')) {182 while ($buffer = fread($fp_remote, 8192)) {183 fwrite($fp_local, $buffer);184 }185 fclose($fp_local);181 $localtempfilename = tempnam('/tmp', 'getID3'); 182 if ($fp_local = fopen($localtempfilename, 'wb')) { 183 while ($buffer = fread($fp_remote, 32768)) { 184 fwrite($fp_local, $buffer); 185 } 186 fclose($fp_local); 186 187 188 $remote_headers = array_change_key_case(get_headers($remotefilename, 1), CASE_LOWER); 189 $remote_filesize = (isset($remote_headers['content-length']) ? (is_array($remote_headers['content-length']) ? $remote_headers['content-length'][count($remote_headers['content-length']) - 1] : $remote_headers['content-length']) : null); 190 187 191 // Initialize getID3 engine 188 192 $getID3 = new getID3; 189 193 190 $ThisFileInfo = $getID3->analyze($ filename);194 $ThisFileInfo = $getID3->analyze($localtempfilename, $remote_filesize, basename($remotefilename)); 191 195 192 // Delete temporary file193 unlink($localtempfilename);194 }195 fclose($fp_remote);196 // Delete temporary file 197 unlink($localtempfilename); 198 } 199 fclose($fp_remote); 196 200 } 197 201 202 Note: since v1.9.9-20150212 it is possible a second and third parameter 203 to $getID3->analyze(), for original filesize and original filename 204 respectively. This permits you to download only a portion of a large remote 205 file but get accurate playtime estimates, assuming the format only requires 206 the beginning of the file for correct format analysis. 198 207 199 208 See /demos/demo.write.php for how to write tags. 200 209 … … 292 301 293 302 Future Plans 294 303 =========================================================================== 295 http ://www.getid3.org/phpBB3/viewforum.php?f=7304 https://www.getid3.org/phpBB3/viewforum.php?f=7 296 305 297 306 * Better support for MP4 container format 298 307 * Scan for appended ID3v2 tag at end of file per ID3v2.4 specs (Section 5.0) … … 334 343 * Optional scan-through-frames for AVI verification 335 344 (thanks rockcohenØmassive-interactive*nl) 336 345 * Support for TTF (thanks infoØbutterflyx*com) 337 * Support for DSS (http ://www.getid3.org/phpBB3/viewtopic.php?t=171)346 * Support for DSS (https://www.getid3.org/phpBB3/viewtopic.php?t=171) 338 347 * Support for SMAF (http://smaf-yamaha.com/what/demo.html) 339 http ://www.getid3.org/phpBB3/viewtopic.php?t=182340 * Support for AMR (http ://www.getid3.org/phpBB3/viewtopic.php?t=195)341 * Support for 3gpp (http ://www.getid3.org/phpBB3/viewtopic.php?t=195)348 https://www.getid3.org/phpBB3/viewtopic.php?t=182 349 * Support for AMR (https://www.getid3.org/phpBB3/viewtopic.php?t=195) 350 * Support for 3gpp (https://www.getid3.org/phpBB3/viewtopic.php?t=195) 342 351 * Support for ID4 (http://www.wackysoft.cjb.net grizlyY2KØhotmail*com) 343 352 * Parse XML data returned in Ogg comments 344 353 * Parse XML data from Quicktime SMIL metafiles (klausrathØmac*com) … … 374 383 375 384 Known Bugs/Issues in getID3() that may be fixed eventually 376 385 =========================================================================== 377 http ://www.getid3.org/phpBB3/viewtopic.php?t=25386 https://www.getid3.org/phpBB3/viewtopic.php?t=25 378 387 379 388 * Cannot determine bitrate for MPEG video with VBR video data 380 389 (need documentation) … … 400 409 401 410 Known Bugs/Issues in getID3() that cannot be fixed 402 411 -------------------------------------------------- 403 http ://www.getid3.org/phpBB3/viewtopic.php?t=25412 https://www.getid3.org/phpBB3/viewtopic.php?t=25 404 413 405 414 * 32-bit PHP installations only: 406 415 Files larger than 2GB cannot always be parsed fully by getID3() … … 430 439 431 440 Known Bugs/Issues in other programs 432 441 ----------------------------------- 433 http ://www.getid3.org/phpBB3/viewtopic.php?t=25442 https://www.getid3.org/phpBB3/viewtopic.php?t=25 434 443 444 * MusicBrainz Picard (at least up to v1.3.2) writes multiple 445 ID3v2.3 genres in non-standard forward-slash separated text 446 rather than parenthesis-numeric+refinement style per the ID3v2.3 447 specs. Tags written in ID3v2.4 mode are written correctly. 448 (detected and worked around by getID3()) 449 * PZ TagEditor v4.53.408 has been known to insert ID3v2.3 frames 450 into an existing ID3v2.2 tag which, of course, breaks things 435 451 * Windows Media Player (up to v11) and iTunes (up to v10+) do 436 452 not correctly handle ID3v2.3 tags with UTF-16BE+BOM 437 453 encoding (they assume the data is UTF-16LE+BOM and either … … 451 467 written just "value" (detected by getID3()) 452 468 * Oggenc 0.9-rc3 flags the encoded file as ABR whether it's 453 469 actually ABR or VBR. 470 * iTunes (versions "v7.0.0.70" is known-guilty, probably 471 other versions are too) writes ID3v2.3 comment tags using an 472 ID3v2.2 frame name (3-bytes) null-padded to 4 bytes which is 473 not valid for ID3v2.3+ 474 (detected by getID3() since 1.9.12-201603221746) 454 475 * iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably 455 476 other versions are too) writes ID3v2.3 comment tags using a 456 477 frame name 'COM ' which is not valid for ID3v2.3+ (it's an … … 601 622 * http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm 602 623 * http://trac.musepack.net/trac/wiki/SV8Specification 603 624 * http://wyday.com/cuesharp/specification.php 604 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 605 No newline at end of file 625 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 626 * http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header 627 * http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)