1<?php 2///////////////////////////////////////////////////////////////// 3/// getID3() by James Heinrich <info@getid3.org> // 4// available at http://getid3.sourceforge.net // 5// or http://www.getid3.org // 6///////////////////////////////////////////////////////////////// 7// // 8// Please see readme.txt for more information // 9// /// 10///////////////////////////////////////////////////////////////// 11 12// Defines 13define('GETID3_VERSION', '1.7.8b2'); 14define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes 15 16 17 18class getID3 19{ 20 // public: Settings 21 var $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv()) 22 // Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE 23 24 var $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' 25 26 var $tempdir = '*'; // default '*' should use system temp dir 27 28 // public: Optional tag checks - disable for speed. 29 var $option_tag_id3v1 = true; // Read and process ID3v1 tags 30 var $option_tag_id3v2 = true; // Read and process ID3v2 tags 31 var $option_tag_lyrics3 = true; // Read and process Lyrics3 tags 32 var $option_tag_apetag = true; // Read and process APE tags 33 var $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding 34 var $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities 35 36 // public: Optional tag/comment calucations 37 var $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc 38 39 // public: Optional calculations 40 var $option_md5_data = false; // Get MD5 sum of data part - slow 41 var $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG 42 var $option_sha1_data = false; // Get SHA1 sum of data part - slow 43 var $option_max_2gb_check = true; // Check whether file is larger than 2 Gb and thus not supported by PHP 44 45 // private 46 var $filename; 47 48 49 // public: constructor 50 function getID3() 51 { 52 53 $this->startup_error = ''; 54 $this->startup_warning = ''; 55 56 // Check for PHP version >= 4.2.0 57 if (phpversion() < '4.2.0') { 58 $this->startup_error .= 'getID3() requires PHP v4.2.0 or higher - you are running v'.phpversion(); 59 } 60 61 // Check memory 62 $memory_limit = ini_get('memory_limit'); 63 if (eregi('([0-9]+)M', $memory_limit, $matches)) { 64 // could be stored as "16M" rather than 16777216 for example 65 $memory_limit = $matches[1] * 1048576; 66 } 67 if ($memory_limit <= 0) { 68 // memory limits probably disabled 69 } elseif ($memory_limit <= 3145728) { 70 $this->startup_error .= 'PHP has less than 3MB available memory and will very likely run out. Increase memory_limit in php.ini'; 71 } elseif ($memory_limit <= 12582912) { 72 $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini'; 73 } 74 75 // Check safe_mode off 76 if ((bool) ini_get('safe_mode')) { 77 $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.'); 78 } 79 80 81 // define a constant rather than looking up every time it is needed 82 if (!defined('GETID3_OS_ISWINDOWS')) { 83 if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { 84 define('GETID3_OS_ISWINDOWS', true); 85 } else { 86 define('GETID3_OS_ISWINDOWS', false); 87 } 88 } 89 90 // Get base path of getID3() - ONCE 91 if (!defined('GETID3_INCLUDEPATH')) { 92 foreach (get_included_files() as $key => $val) { 93 if (basename($val) == 'getid3.php') { 94 define('GETID3_INCLUDEPATH', dirname($val).DIRECTORY_SEPARATOR); 95 break; 96 } 97 } 98 } 99 100 // Load support library 101 if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { 102 $this->startup_error .= 'getid3.lib.php is missing or corrupt'; 103 } 104 105 106 // Needed for Windows only: 107 // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC 108 // as well as other helper functions such as head, tail, md5sum, etc 109 // IMPORTANT: This path cannot have spaces in it. If neccesary, use the 8dot3 equivalent 110 // ie for "C:/Program Files/Apache/" put "C:/PROGRA~1/APACHE/" 111 // IMPORTANT: This path must include the trailing slash 112 if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) { 113 114 $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path 115 116 if (!is_dir($helperappsdir)) { 117 $this->startup_error .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'; 118 } elseif (strpos(realpath($helperappsdir), ' ') !== false) { 119 $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir)); 120 foreach ($DirPieces as $key => $value) { 121 if ((strpos($value, '.') !== false) && (strpos($value, ' ') === false)) { 122 if (strpos($value, '.') > 8) { 123 $value = substr($value, 0, 6).'~1'; 124 } 125 } elseif ((strpos($value, ' ') !== false) || strlen($value) > 8) { 126 $value = substr($value, 0, 6).'~1'; 127 } 128 $DirPieces[$key] = strtoupper($value); 129 } 130 $this->startup_error .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary (on this server that would be something like "'.implode(DIRECTORY_SEPARATOR, $DirPieces).'" - NOTE: this may or may not be the actual 8.3 equivalent of "'.$helperappsdir.'", please double-check). You can run "dir /x" from the commandline to see the correct 8.3-style names.'; 131 } 132 define('GETID3_HELPERAPPSDIR', realpath($helperappsdir).DIRECTORY_SEPARATOR); 133 } 134 135 } 136 137 138 // public: setOption 139 function setOption($optArray) { 140 if (!is_array($optArray) || empty($optArray)) { 141 return false; 142 } 143 foreach ($optArray as $opt => $val) { 144 if (isset($this, $opt) === false) { 145 continue; 146 } 147 $this->$opt = $val; 148 } 149 return true; 150 } 151 152 153 // public: analyze file - replaces GetAllFileInfo() and GetTagOnly() 154 function analyze($filename) { 155 156 if (!empty($this->startup_error)) { 157 return $this->error($this->startup_error); 158 } 159 if (!empty($this->startup_warning)) { 160 $this->warning($this->startup_warning); 161 } 162 163 // init result array and set parameters 164 $this->info = array(); 165 $this->info['GETID3_VERSION'] = GETID3_VERSION; 166 167 // Check encoding/iconv support 168 if (!function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) { 169 $errormessage = 'iconv() support is needed for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. '; 170 if (GETID3_OS_ISWINDOWS) { 171 $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32'; 172 } else { 173 $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch'; 174 } 175 return $this->error($errormessage); 176 } 177 178 // Disable magic_quotes_runtime, if neccesary 179 $old_magic_quotes_runtime = get_magic_quotes_runtime(); // store current setting of magic_quotes_runtime 180 if ($old_magic_quotes_runtime) { 181 set_magic_quotes_runtime(0); // turn off magic_quotes_runtime 182 if (get_magic_quotes_runtime()) { 183 return $this->error('Could not disable magic_quotes_runtime - getID3() cannot work properly with this setting enabled'); 184 } 185 } 186 187 // remote files not supported 188 if (preg_match('/^(ht|f)tp:\/\//', $filename)) { 189 return $this->error('Remote files are not supported in this version of getID3() - please copy the file locally first'); 190 } 191 192 // open local file 193 if (!$fp = @fopen($filename, 'rb')) { 194 return $this->error('Could not open file "'.$filename.'"'); 195 } 196 197 // set parameters 198 $this->info['filesize'] = filesize($filename); 199 200 // option_max_2gb_check 201 if ($this->option_max_2gb_check) { 202 // PHP doesn't support integers larger than 31-bit (~2GB) 203 // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize 204 // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer 205 fseek($fp, 0, SEEK_END); 206 if ((($this->info['filesize'] != 0) && (ftell($fp) == 0)) || 207 ($this->info['filesize'] < 0) || 208 (ftell($fp) < 0)) { 209 unset($this->info['filesize']); 210 fclose($fp); 211 return $this->error('File is most likely larger than 2GB and is not supported by PHP'); 212 } 213 } 214 215 // set more parameters 216 $this->info['avdataoffset'] = 0; 217 $this->info['avdataend'] = $this->info['filesize']; 218 $this->info['fileformat'] = ''; // filled in later 219 $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used 220 $this->info['video']['dataformat'] = ''; // filled in later, unset if not used 221 $this->info['tags'] = array(); // filled in later, unset if not used 222 $this->info['error'] = array(); // filled in later, unset if not used 223 $this->info['warning'] = array(); // filled in later, unset if not used 224 $this->info['comments'] = array(); // filled in later, unset if not used 225 $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired 226 227 // set redundant parameters - might be needed in some include file 228 $this->info['filename'] = basename($filename); 229 $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); 230 $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; 231 232 233 // handle ID3v2 tag - done first - already at beginning of file 234 // ID3v2 detection (even if not parsing) is always done otherwise fileformat is much harder to detect 235 if ($this->option_tag_id3v2) { 236 237 $GETID3_ERRORARRAY = &$this->info['warning']; 238 if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, false)) { 239 $tag = new getid3_id3v2($fp, $this->info); 240 unset($tag); 241 } 242 243 } else { 244 245 fseek($fp, 0, SEEK_SET); 246 $header = fread($fp, 10); 247 if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) { 248 $this->info['id3v2']['header'] = true; 249 $this->info['id3v2']['majorversion'] = ord($header{3}); 250 $this->info['id3v2']['minorversion'] = ord($header{4}); 251 $this->info['id3v2']['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length 252 253 $this->info['id3v2']['tag_offset_start'] = 0; 254 $this->info['id3v2']['tag_offset_end'] = $this->info['id3v2']['tag_offset_start'] + $this->info['id3v2']['headerlength']; 255 $this->info['avdataoffset'] = $this->info['id3v2']['tag_offset_end']; 256 } 257 258 } 259 260 261 // handle ID3v1 tag 262 if ($this->option_tag_id3v1) { 263 if (!@include_once(GETID3_INCLUDEPATH.'module.tag.id3v1.php')) { 264 return $this->error('module.tag.id3v1.php is missing - you may disable option_tag_id3v1.'); 265 } 266 $tag = new getid3_id3v1($fp, $this->info); 267 unset($tag); 268 } 269 270 // handle APE tag 271 if ($this->option_tag_apetag) { 272 if (!@include_once(GETID3_INCLUDEPATH.'module.tag.apetag.php')) { 273 return $this->error('module.tag.apetag.php is missing - you may disable option_tag_apetag.'); 274 } 275 $tag = new getid3_apetag($fp, $this->info); 276 unset($tag); 277 } 278 279 // handle lyrics3 tag 280 if ($this->option_tag_lyrics3) { 281 if (!@include_once(GETID3_INCLUDEPATH.'module.tag.lyrics3.php')) { 282 return $this->error('module.tag.lyrics3.php is missing - you may disable option_tag_lyrics3.'); 283 } 284 $tag = new getid3_lyrics3($fp, $this->info); 285 unset($tag); 286 } 287 288 // read 32 kb file data 289 fseek($fp, $this->info['avdataoffset'], SEEK_SET); 290 $formattest = fread($fp, 32774); 291 292 // determine format 293 $determined_format = $this->GetFileFormat($formattest, $filename); 294 295 // unable to determine file format 296 if (!$determined_format) { 297 fclose($fp); 298 return $this->error('unable to determine file format'); 299 } 300 301 // check for illegal ID3 tags 302 if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) { 303 if ($determined_format['fail_id3'] === 'ERROR') { 304 fclose($fp); 305 return $this->error('ID3 tags not allowed on this file type.'); 306 } elseif ($determined_format['fail_id3'] === 'WARNING') { 307 $this->info['warning'][] = 'ID3 tags not allowed on this file type.'; 308 } 309 } 310 311 // check for illegal APE tags 312 if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) { 313 if ($determined_format['fail_ape'] === 'ERROR') { 314 fclose($fp); 315 return $this->error('APE tags not allowed on this file type.'); 316 } elseif ($determined_format['fail_ape'] === 'WARNING') { 317 $this->info['warning'][] = 'APE tags not allowed on this file type.'; 318 } 319 } 320 321 // set mime type 322 $this->info['mime_type'] = $determined_format['mime_type']; 323 324 // supported format signature pattern detected, but module deleted 325 if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) { 326 fclose($fp); 327 return $this->error('Format not supported, module, '.$determined_format['include'].', was removed.'); 328 } 329 330 // module requires iconv support 331 if (!function_exists('iconv') && @$determined_format['iconv_req']) { 332 return $this->error('iconv support is required for this module ('.$determined_format['include'].').'); 333 } 334 335 // include module 336 include_once(GETID3_INCLUDEPATH.$determined_format['include']); 337 338 // instantiate module class 339 $class_name = 'getid3_'.$determined_format['module']; 340 if (!class_exists($class_name)) { 341 return $this->error('Format not supported, module, '.$determined_format['include'].', is corrupt.'); 342 } 343 if (isset($determined_format['option'])) { 344 $class = new $class_name($fp, $this->info, $determined_format['option']); 345 } else { 346 $class = new $class_name($fp, $this->info); 347 } 348 unset($class); 349 350 // close file 351 fclose($fp); 352 353 // process all tags - copy to 'tags' and convert charsets 354 if ($this->option_tags_process) { 355 $this->HandleAllTags(); 356 } 357 358 // perform more calculations 359 if ($this->option_extra_info) { 360 $this->ChannelsBitratePlaytimeCalculations(); 361 $this->CalculateCompressionRatioVideo(); 362 $this->CalculateCompressionRatioAudio(); 363 $this->CalculateReplayGain(); 364 $this->ProcessAudioStreams(); 365 } 366 367 // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags 368 if ($this->option_md5_data) { 369 // do not cald md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too 370 if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) { 371 $this->getHashdata('md5'); 372 } 373 } 374 375 // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags 376 if ($this->option_sha1_data) { 377 $this->getHashdata('sha1'); 378 } 379 380 // remove undesired keys 381 $this->CleanUp(); 382 383 // restore magic_quotes_runtime setting 384 set_magic_quotes_runtime($old_magic_quotes_runtime); 385 386 // return info array 387 return $this->info; 388 } 389 390 391 // private: error handling 392 function error($message) { 393 394 $this->CleanUp(); 395 396 $this->info['error'][] = $message; 397 return $this->info; 398 } 399 400 401 // private: warning handling 402 function warning($message) { 403 $this->info['warning'][] = $message; 404 return true; 405 } 406 407 408 // private: CleanUp 409 function CleanUp() { 410 411 // remove possible empty keys 412 $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate'); 413 foreach ($AVpossibleEmptyKeys as $dummy => $key) { 414 if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) { 415 unset($this->info['audio'][$key]); 416 } 417 if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) { 418 unset($this->info['video'][$key]); 419 } 420 } 421 422 // remove empty root keys 423 if (!empty($this->info)) { 424 foreach ($this->info as $key => $value) { 425 if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) { 426 unset($this->info[$key]); 427 } 428 } 429 } 430 431 // remove meaningless entries from unknown-format files 432 if (empty($this->info['fileformat'])) { 433 if (isset($this->info['avdataoffset'])) { 434 unset($this->info['avdataoffset']); 435 } 436 if (isset($this->info['avdataend'])) { 437 unset($this->info['avdataend']); 438 } 439 } 440 } 441 442 443 // return array containing information about all supported formats 444 function GetFileFormatArray() { 445 static $format_info = array(); 446 if (empty($format_info)) { 447 $format_info = array( 448 449 // Audio formats 450 451 // AC-3 - audio - Dolby AC-3 / Dolby Digital 452 'ac3' => array( 453 'pattern' => '^\x0B\x77', 454 'group' => 'audio', 455 'module' => 'ac3', 456 'mime_type' => 'audio/ac3', 457 ), 458 459 // AAC - audio - Advanced Audio Coding (AAC) - ADIF format 460 'adif' => array( 461 'pattern' => '^ADIF', 462 'group' => 'audio', 463 'module' => 'aac', 464 'option' => 'adif', 465 'mime_type' => 'application/octet-stream', 466 'fail_ape' => 'WARNING', 467 ), 468 469 470 // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) 471 'adts' => array( 472 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]', 473 'group' => 'audio', 474 'module' => 'aac', 475 'option' => 'adts', 476 'mime_type' => 'application/octet-stream', 477 'fail_ape' => 'WARNING', 478 ), 479 480 481 // AU - audio - NeXT/Sun AUdio (AU) 482 'au' => array( 483 'pattern' => '^\.snd', 484 'group' => 'audio', 485 'module' => 'au', 486 'mime_type' => 'audio/basic', 487 ), 488 489 // AVR - audio - Audio Visual Research 490 'avr' => array( 491 'pattern' => '^2BIT', 492 'group' => 'audio', 493 'module' => 'avr', 494 'mime_type' => 'application/octet-stream', 495 ), 496 497 // BONK - audio - Bonk v0.9+ 498 'bonk' => array( 499 'pattern' => '^\x00(BONK|INFO|META| ID3)', 500 'group' => 'audio', 501 'module' => 'bonk', 502 'mime_type' => 'audio/xmms-bonk', 503 ), 504 505 // DTS - audio - Dolby Theatre System 506 'dts' => array( 507 'pattern' => '^\x7F\xFE\x80\x01', 508 'group' => 'audio', 509 'module' => 'dts', 510 'mime_type' => 'audio/dts', 511 ), 512 513 // FLAC - audio - Free Lossless Audio Codec 514 'flac' => array( 515 'pattern' => '^fLaC', 516 'group' => 'audio', 517 'module' => 'flac', 518 'mime_type' => 'audio/x-flac', 519 ), 520 521 // LA - audio - Lossless Audio (LA) 522 'la' => array( 523 'pattern' => '^LA0[2-4]', 524 'group' => 'audio', 525 'module' => 'la', 526 'mime_type' => 'application/octet-stream', 527 ), 528 529 // LPAC - audio - Lossless Predictive Audio Compression (LPAC) 530 'lpac' => array( 531 'pattern' => '^LPAC', 532 'group' => 'audio', 533 'module' => 'lpac', 534 'mime_type' => 'application/octet-stream', 535 ), 536 537 // MIDI - audio - MIDI (Musical Instrument Digital Interface) 538 'midi' => array( 539 'pattern' => '^MThd', 540 'group' => 'audio', 541 'module' => 'midi', 542 'mime_type' => 'audio/midi', 543 ), 544 545 // MAC - audio - Monkey's Audio Compressor 546 'mac' => array( 547 'pattern' => '^MAC ', 548 'group' => 'audio', 549 'module' => 'monkey', 550 'mime_type' => 'application/octet-stream', 551 ), 552 553 // MOD - audio - MODule (assorted sub-formats) 554 'mod' => array( 555 'pattern' => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)', 556 'group' => 'audio', 557 'module' => 'mod', 558 'option' => 'mod', 559 'mime_type' => 'audio/mod', 560 ), 561 562 // MOD - audio - MODule (Impulse Tracker) 563 'it' => array( 564 'pattern' => '^IMPM', 565 'group' => 'audio', 566 'module' => 'mod', 567 'option' => 'it', 568 'mime_type' => 'audio/it', 569 ), 570 571 // MOD - audio - MODule (eXtended Module, various sub-formats) 572 'xm' => array( 573 'pattern' => '^Extended Module', 574 'group' => 'audio', 575 'module' => 'mod', 576 'option' => 'xm', 577 'mime_type' => 'audio/xm', 578 ), 579 580 // MOD - audio - MODule (ScreamTracker) 581 's3m' => array( 582 'pattern' => '^.{44}SCRM', 583 'group' => 'audio', 584 'module' => 'mod', 585 'option' => 's3m', 586 'mime_type' => 'audio/s3m', 587 ), 588 589 // MPC - audio - Musepack / MPEGplus 590 'mpc' => array( 591 'pattern' => '^(MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])', 592 'group' => 'audio', 593 'module' => 'mpc', 594 'mime_type' => 'audio/x-musepack', 595 ), 596 597 // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) 598 'mp3' => array( 599 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]', 600 'group' => 'audio', 601 'module' => 'mp3', 602 'mime_type' => 'audio/mpeg', 603 ), 604 605 // OFR - audio - OptimFROG 606 'ofr' => array( 607 'pattern' => '^(\*RIFF|OFR)', 608 'group' => 'audio', 609 'module' => 'optimfrog', 610 'mime_type' => 'application/octet-stream', 611 ), 612 613 // RKAU - audio - RKive AUdio compressor 614 'rkau' => array( 615 'pattern' => '^RKA', 616 'group' => 'audio', 617 'module' => 'rkau', 618 'mime_type' => 'application/octet-stream', 619 ), 620 621 // SHN - audio - Shorten 622 'shn' => array( 623 'pattern' => '^ajkg', 624 'group' => 'audio', 625 'module' => 'shorten', 626 'mime_type' => 'audio/xmms-shn', 627 'fail_id3' => 'ERROR', 628 'fail_ape' => 'ERROR', 629 ), 630 631 // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) 632 'tta' => array( 633 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)' 634 'group' => 'audio', 635 'module' => 'tta', 636 'mime_type' => 'application/octet-stream', 637 ), 638 639 // VOC - audio - Creative Voice (VOC) 640 'voc' => array( 641 'pattern' => '^Creative Voice File', 642 'group' => 'audio', 643 'module' => 'voc', 644 'mime_type' => 'audio/voc', 645 ), 646 647 // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) 648 'vqf' => array( 649 'pattern' => '^TWIN', 650 'group' => 'audio', 651 'module' => 'vqf', 652 'mime_type' => 'application/octet-stream', 653 ), 654 655 // WV - audio - WavPack (v4.0+) 656 'wv' => array( 657 'pattern' => '^wvpk', 658 'group' => 'audio', 659 'module' => 'wavpack', 660 'mime_type' => 'application/octet-stream', 661 ), 662 663 664 // Audio-Video formats 665 666 // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio 667 'asf' => array( 668 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', 669 'group' => 'audio-video', 670 'module' => 'asf', 671 'mime_type' => 'video/x-ms-asf', 672 'iconv_req' => false, 673 ), 674 675 // BINK - audio/video - Bink / Smacker 676 'bink' => array( 677 'pattern' => '^(BIK|SMK)', 678 'group' => 'audio-video', 679 'module' => 'bink', 680 'mime_type' => 'application/octet-stream', 681 ), 682 683 // FLV - audio/video - FLash Video 684 'flv' => array( 685 'pattern' => '^FLV\x01', 686 'group' => 'audio-video', 687 'module' => 'flv', 688 'mime_type' => 'video/x-flv', 689 ), 690 691 // MKAV - audio/video - Mastroka 692 'matroska' => array( 693 'pattern' => '^\x1A\x45\xDF\xA3', 694 'group' => 'audio-video', 695 'module' => 'matroska', 696 'mime_type' => 'application/octet-stream', 697 ), 698 699 // MPEG - audio/video - MPEG (Moving Pictures Experts Group) 700 'mpeg' => array( 701 'pattern' => '^\x00\x00\x01(\xBA|\xB3)', 702 'group' => 'audio-video', 703 'module' => 'mpeg', 704 'mime_type' => 'video/mpeg', 705 ), 706 707 // NSV - audio/video - Nullsoft Streaming Video (NSV) 708 'nsv' => array( 709 'pattern' => '^NSV[sf]', 710 'group' => 'audio-video', 711 'module' => 'nsv', 712 'mime_type' => 'application/octet-stream', 713 ), 714 715 // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*)) 716 'ogg' => array( 717 'pattern' => '^OggS', 718 'group' => 'audio', 719 'module' => 'ogg', 720 'mime_type' => 'application/ogg', 721 'fail_id3' => 'WARNING', 722 'fail_ape' => 'WARNING', 723 ), 724 725 // QT - audio/video - Quicktime 726 'quicktime' => array( 727 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', 728 'group' => 'audio-video', 729 'module' => 'quicktime', 730 'mime_type' => 'video/quicktime', 731 ), 732 733 // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF) 734 'riff' => array( 735 'pattern' => '^(RIFF|SDSS|FORM)', 736 'group' => 'audio-video', 737 'module' => 'riff', 738 'mime_type' => 'audio/x-wave', 739 'fail_ape' => 'WARNING', 740 ), 741 742 // Real - audio/video - RealAudio, RealVideo 743 'real' => array( 744 'pattern' => '^(\.RMF|.ra)', 745 'group' => 'audio-video', 746 'module' => 'real', 747 'mime_type' => 'audio/x-realaudio', 748 ), 749 750 // SWF - audio/video - ShockWave Flash 751 'swf' => array( 752 'pattern' => '^(F|C)WS', 753 'group' => 'audio-video', 754 'module' => 'swf', 755 'mime_type' => 'application/x-shockwave-flash', 756 ), 757 758 759 // Still-Image formats 760 761 // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) 762 'bmp' => array( 763 'pattern' => '^BM', 764 'group' => 'graphic', 765 'module' => 'bmp', 766 'mime_type' => 'image/bmp', 767 'fail_id3' => 'ERROR', 768 'fail_ape' => 'ERROR', 769 ), 770 771 // GIF - still image - Graphics Interchange Format 772 'gif' => array( 773 'pattern' => '^GIF', 774 'group' => 'graphic', 775 'module' => 'gif', 776 'mime_type' => 'image/gif', 777 'fail_id3' => 'ERROR', 778 'fail_ape' => 'ERROR', 779 ), 780 781 // JPEG - still image - Joint Photographic Experts Group (JPEG) 782 'jpg' => array( 783 'pattern' => '^\xFF\xD8\xFF', 784 'group' => 'graphic', 785 'module' => 'jpg', 786 'mime_type' => 'image/jpeg', 787 'fail_id3' => 'ERROR', 788 'fail_ape' => 'ERROR', 789 ), 790 791 // PCD - still image - Kodak Photo CD 792 'pcd' => array( 793 'pattern' => '^.{2048}PCD_IPI\x00', 794 'group' => 'graphic', 795 'module' => 'pcd', 796 'mime_type' => 'image/x-photo-cd', 797 'fail_id3' => 'ERROR', 798 'fail_ape' => 'ERROR', 799 ), 800 801 802 // PNG - still image - Portable Network Graphics (PNG) 803 'png' => array( 804 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', 805 'group' => 'graphic', 806 'module' => 'png', 807 'mime_type' => 'image/png', 808 'fail_id3' => 'ERROR', 809 'fail_ape' => 'ERROR', 810 ), 811 812 813 // SVG - still image - Scalable Vector Graphics (SVG) 814 'svg' => array( 815 'pattern' => '<!DOCTYPE svg PUBLIC ', 816 'group' => 'graphic', 817 'module' => 'svg', 818 'mime_type' => 'image/svg+xml', 819 'fail_id3' => 'ERROR', 820 'fail_ape' => 'ERROR', 821 ), 822 823 824 // TIFF - still image - Tagged Information File Format (TIFF) 825 'tiff' => array( 826 'pattern' => '^(II\x2A\x00|MM\x00\x2A)', 827 'group' => 'graphic', 828 'module' => 'tiff', 829 'mime_type' => 'image/tiff', 830 'fail_id3' => 'ERROR', 831 'fail_ape' => 'ERROR', 832 ), 833 834 835 // Data formats 836 837 // ISO - data - International Standards Organization (ISO) CD-ROM Image 838 'iso' => array( 839 'pattern' => '^.{32769}CD001', 840 'group' => 'misc', 841 'module' => 'iso', 842 'mime_type' => 'application/octet-stream', 843 'fail_id3' => 'ERROR', 844 'fail_ape' => 'ERROR', 845 'iconv_req' => false, 846 ), 847 848 // RAR - data - RAR compressed data 849 'rar' => array( 850 'pattern' => '^Rar\!', 851 'group' => 'archive', 852 'module' => 'rar', 853 'mime_type' => 'application/octet-stream', 854 'fail_id3' => 'ERROR', 855 'fail_ape' => 'ERROR', 856 ), 857 858 // SZIP - audio/data - SZIP compressed data 859 'szip' => array( 860 'pattern' => '^SZ\x0A\x04', 861 'group' => 'archive', 862 'module' => 'szip', 863 'mime_type' => 'application/octet-stream', 864 'fail_id3' => 'ERROR', 865 'fail_ape' => 'ERROR', 866 ), 867 868 // TAR - data - TAR compressed data 869 'tar' => array( 870 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}', 871 'group' => 'archive', 872 'module' => 'tar', 873 'mime_type' => 'application/x-tar', 874 'fail_id3' => 'ERROR', 875 'fail_ape' => 'ERROR', 876 ), 877 878 // GZIP - data - GZIP compressed data 879 'gz' => array( 880 'pattern' => '^\x1F\x8B\x08', 881 'group' => 'archive', 882 'module' => 'gzip', 883 'mime_type' => 'application/x-gzip', 884 'fail_id3' => 'ERROR', 885 'fail_ape' => 'ERROR', 886 ), 887 888 // ZIP - data - ZIP compressed data 889 'zip' => array( 890 'pattern' => '^PK\x03\x04', 891 'group' => 'archive', 892 'module' => 'zip', 893 'mime_type' => 'application/zip', 894 'fail_id3' => 'ERROR', 895 'fail_ape' => 'ERROR', 896 ), 897 898 899 // Misc other formats 900 901 // PAR2 - data - Parity Volume Set Specification 2.0 902 'par2' => array ( 903 'pattern' => '^PAR2\x00PKT', 904 'group' => 'misc', 905 'module' => 'par2', 906 'mime_type' => 'application/octet-stream', 907 'fail_id3' => 'ERROR', 908 'fail_ape' => 'ERROR', 909 ), 910 911 // PDF - data - Portable Document Format 912 'pdf' => array( 913 'pattern' => '^\x25PDF', 914 'group' => 'misc', 915 'module' => 'pdf', 916 'mime_type' => 'application/pdf', 917 'fail_id3' => 'ERROR', 918 'fail_ape' => 'ERROR', 919 ), 920 921 // MSOFFICE - data - ZIP compressed data 922 'msoffice' => array( 923 'pattern' => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document 924 'group' => 'misc', 925 'module' => 'msoffice', 926 'mime_type' => 'application/octet-stream', 927 'fail_id3' => 'ERROR', 928 'fail_ape' => 'ERROR', 929 ), 930 ); 931 } 932 933 return $format_info; 934 } 935 936 937 938 function GetFileFormat(&$filedata, $filename='') { 939 // this function will determine the format of a file based on usually 940 // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG, 941 // and in the case of ISO CD image, 6 bytes offset 32kb from the start 942 // of the file). 943 944 // Identify file format - loop through $format_info and detect with reg expr 945 foreach ($this->GetFileFormatArray() as $format_name => $info) { 946 // Using preg_match() instead of ereg() - much faster 947 // The /s switch on preg_match() forces preg_match() NOT to treat 948 // newline (0x0A) characters as special chars but do a binary match 949 if (preg_match('/'.$info['pattern'].'/s', $filedata)) { 950 $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; 951 return $info; 952 } 953 } 954 955 956 if (preg_match('/\.mp[123a]$/i', $filename)) { 957 // Too many mp3 encoders on the market put gabage in front of mpeg files 958 // use assume format on these if format detection failed 959 $GetFileFormatArray = $this->GetFileFormatArray(); 960 $info = $GetFileFormatArray['mp3']; 961 $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; 962 return $info; 963 } 964 965 return false; 966 } 967 968 969 // converts array to $encoding charset from $this->encoding 970 function CharConvert(&$array, $encoding) { 971 972 // identical encoding - end here 973 if ($encoding == $this->encoding) { 974 return; 975 } 976 977 // loop thru array 978 foreach ($array as $key => $value) { 979 980 // go recursive 981 if (is_array($value)) { 982 $this->CharConvert($array[$key], $encoding); 983 } 984 985 // convert string 986 elseif (is_string($value)) { 987 $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value)); 988 } 989 } 990 } 991 992 993 function HandleAllTags() { 994 995 // key name => array (tag name, character encoding) 996 static $tags; 997 if (empty($tags)) { 998 $tags = array( 999 'asf' => array('asf' , 'UTF-16LE'), 1000 'midi' => array('midi' , 'ISO-8859-1'), 1001 'nsv' => array('nsv' , 'ISO-8859-1'), 1002 'ogg' => array('vorbiscomment' , 'UTF-8'), 1003 'png' => array('png' , 'UTF-8'), 1004 'tiff' => array('tiff' , 'ISO-8859-1'), 1005 'quicktime' => array('quicktime' , 'ISO-8859-1'), 1006 'real' => array('real' , 'ISO-8859-1'), 1007 'vqf' => array('vqf' , 'ISO-8859-1'), 1008 'zip' => array('zip' , 'ISO-8859-1'), 1009 'riff' => array('riff' , 'ISO-8859-1'), 1010 'lyrics3' => array('lyrics3' , 'ISO-8859-1'), 1011 'id3v1' => array('id3v1' , $this->encoding_id3v1), 1012 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8 1013 'ape' => array('ape' , 'UTF-8') 1014 ); 1015 } 1016 1017 // loop thru comments array 1018 foreach ($tags as $comment_name => $tagname_encoding_array) { 1019 list($tag_name, $encoding) = $tagname_encoding_array; 1020 1021 // fill in default encoding type if not already present 1022 if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) { 1023 $this->info[$comment_name]['encoding'] = $encoding; 1024 } 1025 1026 // copy comments if key name set 1027 if (!empty($this->info[$comment_name]['comments'])) { 1028 1029 foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) { 1030 foreach ($valuearray as $key => $value) { 1031 if (strlen(trim($value)) > 0) { 1032 $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed! 1033 } 1034 } 1035 } 1036 1037 if (!isset($this->info['tags'][$tag_name])) { 1038 // comments are set but contain nothing but empty strings, so skip 1039 continue; 1040 } 1041 1042 if ($this->option_tags_html) { 1043 foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { 1044 foreach ($valuearray as $key => $value) { 1045 if (is_string($value)) { 1046 //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding); 1047 $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', getid3_lib::MultiByteCharString2HTML($value, $encoding)); 1048 } else { 1049 $this->info['tags_html'][$tag_name][$tag_key][$key] = $value; 1050 } 1051 } 1052 } 1053 } 1054 1055 $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! 1056 } 1057 1058 } 1059 return true; 1060 } 1061 1062 1063 function getHashdata($algorithm) { 1064 switch ($algorithm) { 1065 case 'md5': 1066 case 'sha1': 1067 break; 1068 1069 default: 1070 return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()'); 1071 break; 1072 } 1073 1074 if ((@$this->info['fileformat'] == 'ogg') && (@$this->info['audio']['dataformat'] == 'vorbis')) { 1075 1076 // We cannot get an identical md5_data value for Ogg files where the comments 1077 // span more than 1 Ogg page (compared to the same audio data with smaller 1078 // comments) using the normal getID3() method of MD5'ing the data between the 1079 // end of the comments and the end of the file (minus any trailing tags), 1080 // because the page sequence numbers of the pages that the audio data is on 1081 // do not match. Under normal circumstances, where comments are smaller than 1082 // the nominal 4-8kB page size, then this is not a problem, but if there are 1083 // very large comments, the only way around it is to strip off the comment 1084 // tags with vorbiscomment and MD5 that file. 1085 // This procedure must be applied to ALL Ogg files, not just the ones with 1086 // comments larger than 1 page, because the below method simply MD5's the 1087 // whole file with the comments stripped, not just the portion after the 1088 // comments block (which is the standard getID3() method. 1089 1090 // The above-mentioned problem of comments spanning multiple pages and changing 1091 // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but 1092 // currently vorbiscomment only works on OggVorbis files. 1093 1094 if ((bool) ini_get('safe_mode')) { 1095 1096 $this->info['warning'][] = 'Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)'; 1097 $this->info[$algorithm.'_data'] = false; 1098 1099 } else { 1100 1101 // Prevent user from aborting script 1102 $old_abort = ignore_user_abort(true); 1103 1104 // Create empty file 1105 $empty = tempnam('*', 'getID3'); 1106 touch($empty); 1107 1108 1109 // Use vorbiscomment to make temp file without comments 1110 $temp = tempnam('*', 'getID3'); 1111 $file = $this->info['filenamepath']; 1112 1113 if (GETID3_OS_ISWINDOWS) { 1114 1115 if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { 1116 1117 $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"'; 1118 $VorbisCommentError = `$commandline`; 1119 1120 } else { 1121 1122 $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; 1123 1124 } 1125 1126 } else { 1127 1128 $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1'; 1129 $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; 1130 $VorbisCommentError = `$commandline`; 1131 1132 } 1133 1134 if (!empty($VorbisCommentError)) { 1135 1136 $this->info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError; 1137 $this->info[$algorithm.'_data'] = false; 1138 1139 } else { 1140 1141 // Get hash of newly created file 1142 switch ($algorithm) { 1143 case 'md5': 1144 $this->info[$algorithm.'_data'] = getid3_lib::md5_file($temp); 1145 break; 1146 1147 case 'sha1': 1148 $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($temp); 1149 break; 1150 } 1151 } 1152 1153 // Clean up 1154 unlink($empty); 1155 unlink($temp); 1156 1157 // Reset abort setting 1158 ignore_user_abort($old_abort); 1159 1160 } 1161 1162 } else { 1163 1164 if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) { 1165 1166 // get hash from part of file 1167 $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm); 1168 1169 } else { 1170 1171 // get hash from whole file 1172 switch ($algorithm) { 1173 case 'md5': 1174 $this->info[$algorithm.'_data'] = getid3_lib::md5_file($this->info['filenamepath']); 1175 break; 1176 1177 case 'sha1': 1178 $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($this->info['filenamepath']); 1179 break; 1180 } 1181 } 1182 1183 } 1184 return true; 1185 } 1186 1187 1188 function ChannelsBitratePlaytimeCalculations() { 1189 1190 // set channelmode on audio 1191 if (@$this->info['audio']['channels'] == '1') { 1192 $this->info['audio']['channelmode'] = 'mono'; 1193 } elseif (@$this->info['audio']['channels'] == '2') { 1194 $this->info['audio']['channelmode'] = 'stereo'; 1195 } 1196 1197 // Calculate combined bitrate - audio + video 1198 $CombinedBitrate = 0; 1199 $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); 1200 $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); 1201 if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) { 1202 $this->info['bitrate'] = $CombinedBitrate; 1203 } 1204 //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) { 1205 // // for example, VBR MPEG video files cannot determine video bitrate: 1206 // // should not set overall bitrate and playtime from audio bitrate only 1207 // unset($this->info['bitrate']); 1208 //} 1209 1210 // video bitrate undetermined, but calculable 1211 if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) { 1212 // if video bitrate not set 1213 if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) { 1214 // AND if audio bitrate is set to same as overall bitrate 1215 if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) { 1216 // AND if playtime is set 1217 if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) { 1218 // AND if AV data offset start/end is known 1219 // THEN we can calculate the video bitrate 1220 $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']); 1221 $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate']; 1222 } 1223 } 1224 } 1225 } 1226 1227 if (!isset($this->info['playtime_seconds']) && !empty($this->info['bitrate'])) { 1228 $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate']; 1229 } 1230 1231 // Set playtime string 1232 if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { 1233 $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']); 1234 } 1235 } 1236 1237 1238 function CalculateCompressionRatioVideo() { 1239 if (empty($this->info['video'])) { 1240 return false; 1241 } 1242 if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) { 1243 return false; 1244 } 1245 if (empty($this->info['video']['bits_per_sample'])) { 1246 return false; 1247 } 1248 1249 switch ($this->info['video']['dataformat']) { 1250 case 'bmp': 1251 case 'gif': 1252 case 'jpeg': 1253 case 'jpg': 1254 case 'png': 1255 case 'tiff': 1256 $FrameRate = 1; 1257 $PlaytimeSeconds = 1; 1258 $BitrateCompressed = $this->info['filesize'] * 8; 1259 break; 1260 1261 default: 1262 if (!empty($this->info['video']['frame_rate'])) { 1263 $FrameRate = $this->info['video']['frame_rate']; 1264 } else { 1265 return false; 1266 } 1267 if (!empty($this->info['playtime_seconds'])) { 1268 $PlaytimeSeconds = $this->info['playtime_seconds']; 1269 } else { 1270 return false; 1271 } 1272 if (!empty($this->info['video']['bitrate'])) { 1273 $BitrateCompressed = $this->info['video']['bitrate']; 1274 } else { 1275 return false; 1276 } 1277 break; 1278 } 1279 $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; 1280 1281 $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; 1282 return true; 1283 } 1284 1285 1286 function CalculateCompressionRatioAudio() { 1287 if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate'])) { 1288 return false; 1289 } 1290 $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16)); 1291 1292 if (!empty($this->info['audio']['streams'])) { 1293 foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) { 1294 if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) { 1295 $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16)); 1296 } 1297 } 1298 } 1299 return true; 1300 } 1301 1302 1303 function CalculateReplayGain() { 1304 if (isset($this->info['replay_gain'])) { 1305 $this->info['replay_gain']['reference_volume'] = 89; 1306 if (isset($this->info['replay_gain']['track']['adjustment'])) { 1307 $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; 1308 } 1309 if (isset($this->info['replay_gain']['album']['adjustment'])) { 1310 $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; 1311 } 1312 1313 if (isset($this->info['replay_gain']['track']['peak'])) { 1314 $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']); 1315 } 1316 if (isset($this->info['replay_gain']['album']['peak'])) { 1317 $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']); 1318 } 1319 } 1320 return true; 1321 } 1322 1323 function ProcessAudioStreams() { 1324 if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) { 1325 if (!isset($this->info['audio']['streams'])) { 1326 foreach ($this->info['audio'] as $key => $value) { 1327 if ($key != 'streams') { 1328 $this->info['audio']['streams'][0][$key] = $value; 1329 } 1330 } 1331 } 1332 } 1333 return true; 1334 } 1335 1336 function getid3_tempnam() { 1337 return tempnam($this->tempdir, 'gI3'); 1338 } 1339 1340} 1341 1342?>