コード例 #1
0
ファイル: Exe.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $EXEheader = fread($this->getid3->fp, 28);
     $magic = 'MZ';
     if (substr($EXEheader, 0, 2) != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($EXEheader, 0, 2)) . '"';
         return false;
     }
     $info['fileformat'] = 'exe';
     $info['exe']['mz']['magic'] = 'MZ';
     $info['exe']['mz']['raw']['last_page_size'] = Helper::LittleEndian2Int(substr($EXEheader, 2, 2));
     $info['exe']['mz']['raw']['page_count'] = Helper::LittleEndian2Int(substr($EXEheader, 4, 2));
     $info['exe']['mz']['raw']['relocation_count'] = Helper::LittleEndian2Int(substr($EXEheader, 6, 2));
     $info['exe']['mz']['raw']['header_paragraphs'] = Helper::LittleEndian2Int(substr($EXEheader, 8, 2));
     $info['exe']['mz']['raw']['min_memory_paragraphs'] = Helper::LittleEndian2Int(substr($EXEheader, 10, 2));
     $info['exe']['mz']['raw']['max_memory_paragraphs'] = Helper::LittleEndian2Int(substr($EXEheader, 12, 2));
     $info['exe']['mz']['raw']['initial_ss'] = Helper::LittleEndian2Int(substr($EXEheader, 14, 2));
     $info['exe']['mz']['raw']['initial_sp'] = Helper::LittleEndian2Int(substr($EXEheader, 16, 2));
     $info['exe']['mz']['raw']['checksum'] = Helper::LittleEndian2Int(substr($EXEheader, 18, 2));
     $info['exe']['mz']['raw']['cs_ip'] = Helper::LittleEndian2Int(substr($EXEheader, 20, 4));
     $info['exe']['mz']['raw']['relocation_table_offset'] = Helper::LittleEndian2Int(substr($EXEheader, 24, 2));
     $info['exe']['mz']['raw']['overlay_number'] = Helper::LittleEndian2Int(substr($EXEheader, 26, 2));
     $info['exe']['mz']['byte_size'] = ($info['exe']['mz']['raw']['page_count'] - 1) * 512 + $info['exe']['mz']['raw']['last_page_size'];
     $info['exe']['mz']['header_size'] = $info['exe']['mz']['raw']['header_paragraphs'] * 16;
     $info['exe']['mz']['memory_minimum'] = $info['exe']['mz']['raw']['min_memory_paragraphs'] * 16;
     $info['exe']['mz']['memory_recommended'] = $info['exe']['mz']['raw']['max_memory_paragraphs'] * 16;
     $info['error'][] = 'EXE parsing not enabled in this version of GetId3Core() [' . $this->getid3->version() . ']';
     return false;
 }
コード例 #2
0
ファイル: Nsv.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $NSVheader = fread($this->getid3->fp, 4);
     switch ($NSVheader) {
         case 'NSVs':
             if ($this->getNSVsHeaderFilepointer(0)) {
                 $info['fileformat'] = 'nsv';
                 $info['audio']['dataformat'] = 'nsv';
                 $info['video']['dataformat'] = 'nsv';
                 $info['audio']['lossless'] = false;
                 $info['video']['lossless'] = false;
             }
             break;
         case 'NSVf':
             if ($this->getNSVfHeaderFilepointer(0)) {
                 $info['fileformat'] = 'nsv';
                 $info['audio']['dataformat'] = 'nsv';
                 $info['video']['dataformat'] = 'nsv';
                 $info['audio']['lossless'] = false;
                 $info['video']['lossless'] = false;
                 $this->getNSVsHeaderFilepointer($info['nsv']['NSVf']['header_length']);
             }
             break;
         default:
             $info['error'][] = 'Expecting "NSVs" or "NSVf" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($NSVheader) . '"';
             return false;
             break;
     }
     if (!isset($info['nsv']['NSVf'])) {
         $info['warning'][] = 'NSVf header not present - cannot calculate playtime or bitrate';
     }
     return true;
 }
コード例 #3
0
ファイル: Mpc.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     $info['mpc']['header'] = array();
     $thisfile_mpc_header =& $info['mpc']['header'];
     $info['fileformat'] = 'mpc';
     $info['audio']['dataformat'] = 'mpc';
     $info['audio']['bitrate_mode'] = 'vbr';
     $info['audio']['channels'] = 2;
     // up to SV7 the format appears to have been hardcoded for stereo only
     $info['audio']['lossless'] = false;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $MPCheaderData = fread($this->getid3->fp, 4);
     $info['mpc']['header']['preamble'] = substr($MPCheaderData, 0, 4);
     // should be 'MPCK' (SV8) or 'MP+' (SV7), otherwise possible stream data (SV4-SV6)
     if (preg_match('#^MPCK#', $info['mpc']['header']['preamble'])) {
         // this is SV8
         return $this->ParseMPCsv8();
     } elseif (preg_match('#^MP\\+#', $info['mpc']['header']['preamble'])) {
         // this is SV7
         return $this->ParseMPCsv7();
     } elseif (preg_match('/^[\\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]/s', $MPCheaderData)) {
         // this is SV4 - SV6, handle seperately
         return $this->ParseMPCsv6();
     } else {
         $info['error'][] = 'Expecting "MP+" or "MPCK" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($MPCheaderData, 0, 4)) . '"';
         unset($info['fileformat']);
         unset($info['mpc']);
         return false;
     }
     return false;
 }
コード例 #4
0
ファイル: Aa.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $AAheader = fread($this->getid3->fp, 8);
     $magic = "W�u6";
     if (substr($AAheader, 4, 4) != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($AAheader, 4, 4)) . '"';
         return false;
     }
     // shortcut
     $info['aa'] = array();
     $thisfile_au =& $info['aa'];
     $info['fileformat'] = 'aa';
     $info['audio']['dataformat'] = 'aa';
     $info['error'][] = 'Audible Audiobook (.aa) parsing not enabled in this version of GetId3Core() [' . $this->getid3->version() . ']';
     return false;
     $info['audio']['bitrate_mode'] = 'cbr';
     // is it?
     $thisfile_au['encoding'] = 'ISO-8859-1';
     $thisfile_au['filesize'] = Helper::BigEndian2Int(substr($AUheader, 0, 4));
     if ($thisfile_au['filesize'] > $info['avdataend'] - $info['avdataoffset']) {
         $info['warning'][] = 'Possible truncated file - expecting "' . $thisfile_au['filesize'] . '" bytes of data, only found ' . ($info['avdataend'] - $info['avdataoffset']) . ' bytes"';
     }
     $info['audio']['bits_per_sample'] = 16;
     // is it?
     $info['audio']['sample_rate'] = $thisfile_au['sample_rate'];
     $info['audio']['channels'] = $thisfile_au['channels'];
     //$info['playtime_seconds'] = 0;
     //$info['audio']['bitrate'] = 0;
     return true;
 }
コード例 #5
0
ファイル: Dss.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $DSSheader = fread($this->getid3->fp, 1256);
     if (!preg_match('#^(\\x02|\\x03)dss#', $DSSheader)) {
         $info['error'][] = 'Expecting "[02-03] 64 73 73" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($DSSheader, 0, 4)) . '"';
         return false;
     }
     // some structure information taken from http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
     // shortcut
     $info['dss'] = array();
     $thisfile_dss =& $info['dss'];
     $info['fileformat'] = 'dss';
     $info['audio']['dataformat'] = 'dss';
     $info['audio']['bitrate_mode'] = 'cbr';
     //$thisfile_dss['encoding']              = 'ISO-8859-1';
     $thisfile_dss['version'] = ord(substr($DSSheader, 0, 1));
     $thisfile_dss['date_create'] = self::DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
     $thisfile_dss['date_complete'] = self::DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
     //$thisfile_dss['length']         =                         intval(substr($DSSheader,  62,   6)); // I thought time was in seconds, it's actually HHMMSS
     $thisfile_dss['length'] = intval(substr($DSSheader, 62, 2) * 3600 + substr($DSSheader, 64, 2) * 60 + substr($DSSheader, 66, 2));
     $thisfile_dss['priority'] = ord(substr($DSSheader, 793, 1));
     $thisfile_dss['comments'] = trim(substr($DSSheader, 798, 100));
     //$info['audio']['bits_per_sample']  = ?;
     //$info['audio']['sample_rate']      = ?;
     $info['audio']['channels'] = 1;
     $info['playtime_seconds'] = $thisfile_dss['length'];
     $info['audio']['bitrate'] = $info['filesize'] * 8 / $info['playtime_seconds'];
     return true;
 }
コード例 #6
0
ファイル: Szip.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $SZIPHeader = fread($this->getid3->fp, 6);
     if (substr($SZIPHeader, 0, 4) != "SZ\n") {
         $info['error'][] = 'Expecting "53 5A 0A 04" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($SZIPHeader, 0, 4)) . '"';
         return false;
     }
     $info['fileformat'] = 'szip';
     $info['szip']['major_version'] = Helper::BigEndian2Int(substr($SZIPHeader, 4, 1));
     $info['szip']['minor_version'] = Helper::BigEndian2Int(substr($SZIPHeader, 5, 1));
     while (!feof($this->getid3->fp)) {
         $NextBlockID = fread($this->getid3->fp, 2);
         switch ($NextBlockID) {
             case 'SZ':
                 // Note that szip files can be concatenated, this has the same effect as
                 // concatenating the files. this also means that global header blocks
                 // might be present between directory/data blocks.
                 fseek($this->getid3->fp, 4, SEEK_CUR);
                 break;
             case 'BH':
                 $BHheaderbytes = Helper::BigEndian2Int(fread($this->getid3->fp, 3));
                 $BHheaderdata = fread($this->getid3->fp, $BHheaderbytes);
                 $BHheaderoffset = 0;
                 while (strpos($BHheaderdata, "", $BHheaderoffset) > 0) {
                     //filename as \0 terminated string  (empty string indicates end)
                     //owner as \0 terminated string (empty is same as last file)
                     //group as \0 terminated string (empty is same as last file)
                     //3 byte filelength in this block
                     //2 byte access flags
                     //4 byte creation time (like in unix)
                     //4 byte modification time (like in unix)
                     //4 byte access time (like in unix)
                     $BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, ""));
                     $BHheaderoffset += strlen($BHdataArray['filename']) + 1;
                     $BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, ""));
                     $BHheaderoffset += strlen($BHdataArray['owner']) + 1;
                     $BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, ""));
                     $BHheaderoffset += strlen($BHdataArray['group']) + 1;
                     $BHdataArray['filelength'] = Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3));
                     $BHheaderoffset += 3;
                     $BHdataArray['access_flags'] = Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2));
                     $BHheaderoffset += 2;
                     $BHdataArray['creation_time'] = Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
                     $BHheaderoffset += 4;
                     $BHdataArray['modification_time'] = Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
                     $BHheaderoffset += 4;
                     $BHdataArray['access_time'] = Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
                     $BHheaderoffset += 4;
                     $info['szip']['BH'][] = $BHdataArray;
                 }
                 break;
             default:
                 break 2;
         }
     }
     return true;
 }
コード例 #7
0
ファイル: Msoffice.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $DOCFILEheader = fread($this->getid3->fp, 8);
     $magic = "поЮ║╠А";
     if (substr($DOCFILEheader, 0, 8) != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at ' . $info['avdataoffset'] . ', found ' . Helper::PrintHexBytes(substr($DOCFILEheader, 0, 8)) . ' instead.';
         return false;
     }
     $info['fileformat'] = 'msoffice';
     $info['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of GetId3Core() [' . $this->getid3->version() . ']';
     return false;
 }
コード例 #8
0
ファイル: Flac.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return type
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // http://flac.sourceforge.net/format.html
     $this->fseek($info['avdataoffset']);
     $StreamMarker = $this->fread(4);
     $magic = 'fLaC';
     if ($StreamMarker != $magic) {
         return $this->error('Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($StreamMarker) . '"');
     }
     $info['fileformat'] = 'flac';
     $info['audio']['dataformat'] = 'flac';
     $info['audio']['bitrate_mode'] = 'vbr';
     $info['audio']['lossless'] = true;
     return $this->parseMETAdata();
 }
コード例 #9
0
ファイル: Rkau.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $RKAUHeader = fread($this->getid3->fp, 20);
     $magic = 'RKA';
     if (substr($RKAUHeader, 0, 3) != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($RKAUHeader, 0, 3)) . '"';
         return false;
     }
     $info['fileformat'] = 'rkau';
     $info['audio']['dataformat'] = 'rkau';
     $info['audio']['bitrate_mode'] = 'vbr';
     $info['rkau']['raw']['version'] = Helper::LittleEndian2Int(substr($RKAUHeader, 3, 1));
     $info['rkau']['version'] = '1.' . str_pad($info['rkau']['raw']['version'] & 0xf, 2, '0', STR_PAD_LEFT);
     if ($info['rkau']['version'] > 1.07 || $info['rkau']['version'] < 1.06) {
         $info['error'][] = 'This version of GetId3Core() [' . $this->getid3->version() . '] can only parse RKAU files v1.06 and 1.07 (this file is v' . $info['rkau']['version'] . ')';
         unset($info['rkau']);
         return false;
     }
     $info['rkau']['source_bytes'] = Helper::LittleEndian2Int(substr($RKAUHeader, 4, 4));
     $info['rkau']['sample_rate'] = Helper::LittleEndian2Int(substr($RKAUHeader, 8, 4));
     $info['rkau']['channels'] = Helper::LittleEndian2Int(substr($RKAUHeader, 12, 1));
     $info['rkau']['bits_per_sample'] = Helper::LittleEndian2Int(substr($RKAUHeader, 13, 1));
     $info['rkau']['raw']['quality'] = Helper::LittleEndian2Int(substr($RKAUHeader, 14, 1));
     $this->RKAUqualityLookup($info['rkau']);
     $info['rkau']['raw']['flags'] = Helper::LittleEndian2Int(substr($RKAUHeader, 15, 1));
     $info['rkau']['flags']['joint_stereo'] = (bool) (!($info['rkau']['raw']['flags'] & 0x1));
     $info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x2);
     $info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x4);
     if ($info['rkau']['flags']['streaming']) {
         $info['avdataoffset'] += 20;
         $info['rkau']['compressed_bytes'] = Helper::LittleEndian2Int(substr($RKAUHeader, 16, 4));
     } else {
         $info['avdataoffset'] += 16;
         $info['rkau']['compressed_bytes'] = $info['avdataend'] - $info['avdataoffset'] - 1;
     }
     // Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes,
     // sometimes it's more, sometimes less. No idea why(?)
     $info['audio']['lossless'] = $info['rkau']['lossless'];
     $info['audio']['channels'] = $info['rkau']['channels'];
     $info['audio']['bits_per_sample'] = $info['rkau']['bits_per_sample'];
     $info['audio']['sample_rate'] = $info['rkau']['sample_rate'];
     $info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8));
     $info['audio']['bitrate'] = $info['rkau']['compressed_bytes'] * 8 / $info['playtime_seconds'];
     return true;
 }
コード例 #10
0
ファイル: Bink.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     $info['error'][] = 'Bink / Smacker files not properly processed by this version of GetId3Core() [' . $this->getid3->version() . ']';
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $fileTypeID = fread($this->getid3->fp, 3);
     switch ($fileTypeID) {
         case 'BIK':
             return $this->ParseBink();
             break;
         case 'SMK':
             return $this->ParseSmacker();
             break;
         default:
             $info['error'][] = 'Expecting "BIK" or "SMK" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($fileTypeID) . '"';
             return false;
             break;
     }
     return true;
 }
コード例 #11
0
ファイル: Au.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $AUheader = fread($this->getid3->fp, 8);
     $magic = '.snd';
     if (substr($AUheader, 0, 4) != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" (".snd") at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($AUheader, 0, 4)) . '"';
         return false;
     }
     // shortcut
     $info['au'] = array();
     $thisfile_au =& $info['au'];
     $info['fileformat'] = 'au';
     $info['audio']['dataformat'] = 'au';
     $info['audio']['bitrate_mode'] = 'cbr';
     $thisfile_au['encoding'] = 'ISO-8859-1';
     $thisfile_au['header_length'] = Helper::BigEndian2Int(substr($AUheader, 4, 4));
     $AUheader .= fread($this->getid3->fp, $thisfile_au['header_length'] - 8);
     $info['avdataoffset'] += $thisfile_au['header_length'];
     $thisfile_au['data_size'] = Helper::BigEndian2Int(substr($AUheader, 8, 4));
     $thisfile_au['data_format_id'] = Helper::BigEndian2Int(substr($AUheader, 12, 4));
     $thisfile_au['sample_rate'] = Helper::BigEndian2Int(substr($AUheader, 16, 4));
     $thisfile_au['channels'] = Helper::BigEndian2Int(substr($AUheader, 20, 4));
     $thisfile_au['comments']['comment'][] = trim(substr($AUheader, 24));
     $thisfile_au['data_format'] = $this->AUdataFormatNameLookup($thisfile_au['data_format_id']);
     $thisfile_au['used_bits_per_sample'] = $this->AUdataFormatUsedBitsPerSampleLookup($thisfile_au['data_format_id']);
     if ($thisfile_au['bits_per_sample'] = $this->AUdataFormatBitsPerSampleLookup($thisfile_au['data_format_id'])) {
         $info['audio']['bits_per_sample'] = $thisfile_au['bits_per_sample'];
     } else {
         unset($thisfile_au['bits_per_sample']);
     }
     $info['audio']['sample_rate'] = $thisfile_au['sample_rate'];
     $info['audio']['channels'] = $thisfile_au['channels'];
     if ($info['avdataoffset'] + $thisfile_au['data_size'] > $info['avdataend']) {
         $info['warning'][] = 'Possible truncated file - expecting "' . $thisfile_au['data_size'] . '" bytes of audio data, only found ' . ($info['avdataend'] - $info['avdataoffset']) . ' bytes"';
     }
     $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8));
     $info['audio']['bitrate'] = $thisfile_au['data_size'] * 8 / $info['playtime_seconds'];
     return true;
 }
コード例 #12
0
ファイル: Efax.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $efaxheader = fread($this->getid3->fp, 1024);
     $info['efax']['header']['magic'] = substr($efaxheader, 0, 2);
     if ($info['efax']['header']['magic'] != "Üþ") {
         $info['error'][] = 'Invalid eFax byte order identifier (expecting DC FE, found ' . Helper::PrintHexBytes($info['efax']['header']['magic']) . ') at offset ' . $info['avdataoffset'];
         return false;
     }
     $info['fileformat'] = 'efax';
     $info['efax']['header']['filesize'] = Helper::LittleEndian2Int(substr($efaxheader, 2, 4));
     if ($info['efax']['header']['filesize'] != $info['filesize']) {
         $info['error'][] = 'Probable ' . ($info['efax']['header']['filesize'] > $info['filesize'] ? 'truncated' : 'corrupt') . ' file, expecting ' . $info['efax']['header']['filesize'] . ' bytes, found ' . $info['filesize'] . ' bytes';
     }
     $info['efax']['header']['software1'] = rtrim(substr($efaxheader, 26, 32), "");
     $info['efax']['header']['software2'] = rtrim(substr($efaxheader, 58, 32), "");
     $info['efax']['header']['software3'] = rtrim(substr($efaxheader, 90, 32), "");
     $info['efax']['header']['pages'] = Helper::LittleEndian2Int(substr($efaxheader, 198, 2));
     $info['efax']['header']['data_bytes'] = Helper::LittleEndian2Int(substr($efaxheader, 202, 4));
     $info['error'][] = 'eFax parsing not enabled in this version of GetId3Core() [' . $this->getid3->version() . ']';
     return false;
     return true;
 }
コード例 #13
0
ファイル: Mp3.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @param  type    $offset
  * @param  type    $deepscan
  *
  * @return bool
  */
 public function FreeFormatFrameLength($offset, $deepscan = false)
 {
     $info =& $this->getGetId3()->info;
     fseek($this->getGetId3()->fp, $offset, SEEK_SET);
     $MPEGaudioData = fread($this->getGetId3()->fp, 32768);
     $SyncPattern1 = substr($MPEGaudioData, 0, 4);
     // may be different pattern due to padding
     $SyncPattern2 = $SyncPattern1[0] . $SyncPattern1[1] . chr(ord($SyncPattern1[2]) | 0x2) . $SyncPattern1[3];
     if ($SyncPattern2 === $SyncPattern1) {
         $SyncPattern2 = $SyncPattern1[0] . $SyncPattern1[1] . chr(ord($SyncPattern1[2]) & 0xfd) . $SyncPattern1[3];
     }
     $framelength = false;
     $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4);
     $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4);
     if ($framelength1 > 4) {
         $framelength = $framelength1;
     }
     if ($framelength2 > 4 && $framelength2 < $framelength1) {
         $framelength = $framelength2;
     }
     if (!$framelength) {
         // LAME 3.88 has a different value for modeextension on the first frame vs the rest
         $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4);
         $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4);
         if ($framelength1 > 4) {
             $framelength = $framelength1;
         }
         if ($framelength2 > 4 && $framelength2 < $framelength1) {
             $framelength = $framelength2;
         }
         if (!$framelength) {
             $info['error'][] = 'Cannot find next free-format synch pattern (' . Helper::PrintHexBytes($SyncPattern1) . ' or ' . Helper::PrintHexBytes($SyncPattern2) . ') after offset ' . $offset;
             return false;
         } else {
             $info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)';
             $info['audio']['codec'] = 'LAME';
             $info['audio']['encoder'] = 'LAME3.88';
             $SyncPattern1 = substr($SyncPattern1, 0, 3);
             $SyncPattern2 = substr($SyncPattern2, 0, 3);
         }
     }
     if ($deepscan) {
         $ActualFrameLengthValues = array();
         $nextoffset = $offset + $framelength;
         while ($nextoffset < $info['avdataend'] - 6) {
             fseek($this->getGetId3()->fp, $nextoffset - 1, SEEK_SET);
             $NextSyncPattern = fread($this->getGetId3()->fp, 6);
             if (substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1 || substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2) {
                 // good - found where expected
                 $ActualFrameLengthValues[] = $framelength;
             } elseif (substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1 || substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2) {
                 // ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
                 $ActualFrameLengthValues[] = $framelength - 1;
                 --$nextoffset;
             } elseif (substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1 || substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2) {
                 // ok - found one byte later than expected (last frame was padded, first frame wasn't)
                 $ActualFrameLengthValues[] = $framelength + 1;
                 ++$nextoffset;
             } else {
                 $info['error'][] = 'Did not find expected free-format sync pattern at offset ' . $nextoffset;
                 return false;
             }
             $nextoffset += $framelength;
         }
         if (count($ActualFrameLengthValues) > 0) {
             $framelength = intval(round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues)));
         }
     }
     return $framelength;
 }
コード例 #14
0
ファイル: Flv.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $FLVdataLength = $info['avdataend'] - $info['avdataoffset'];
     $FLVheader = fread($this->getid3->fp, 5);
     $info['fileformat'] = 'flv';
     $info['flv']['header']['signature'] = substr($FLVheader, 0, 3);
     $info['flv']['header']['version'] = Helper::BigEndian2Int(substr($FLVheader, 3, 1));
     $TypeFlags = Helper::BigEndian2Int(substr($FLVheader, 4, 1));
     $magic = 'FLV';
     if ($info['flv']['header']['signature'] != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($info['flv']['header']['signature']) . '"';
         unset($info['flv']);
         unset($info['fileformat']);
         return false;
     }
     $info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x4);
     $info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x1);
     $FrameSizeDataLength = Helper::BigEndian2Int(fread($this->getid3->fp, 4));
     $FLVheaderFrameLength = 9;
     if ($FrameSizeDataLength > $FLVheaderFrameLength) {
         fseek($this->getid3->fp, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
     }
     $Duration = 0;
     $found_video = false;
     $found_audio = false;
     $found_meta = false;
     $found_valid_meta_playtime = false;
     $tagParseCount = 0;
     $info['flv']['framecount'] = array('total' => 0, 'audio' => 0, 'video' => 0);
     $flv_framecount =& $info['flv']['framecount'];
     while (ftell($this->getid3->fp) + 16 < $info['avdataend'] && ($tagParseCount++ <= $this->max_frames || !$found_valid_meta_playtime)) {
         $ThisTagHeader = fread($this->getid3->fp, 16);
         $PreviousTagLength = Helper::BigEndian2Int(substr($ThisTagHeader, 0, 4));
         $TagType = Helper::BigEndian2Int(substr($ThisTagHeader, 4, 1));
         $DataLength = Helper::BigEndian2Int(substr($ThisTagHeader, 5, 3));
         $Timestamp = Helper::BigEndian2Int(substr($ThisTagHeader, 8, 3));
         $LastHeaderByte = Helper::BigEndian2Int(substr($ThisTagHeader, 15, 1));
         $NextOffset = ftell($this->getid3->fp) - 1 + $DataLength;
         if ($Timestamp > $Duration) {
             $Duration = $Timestamp;
         }
         ++$flv_framecount['total'];
         switch ($TagType) {
             case self::GETID3_FLV_TAG_AUDIO:
                 $flv_framecount['audio']++;
                 if (!$found_audio) {
                     $found_audio = true;
                     $info['flv']['audio']['audioFormat'] = $LastHeaderByte >> 4 & 0xf;
                     $info['flv']['audio']['audioRate'] = $LastHeaderByte >> 2 & 0x3;
                     $info['flv']['audio']['audioSampleSize'] = $LastHeaderByte >> 1 & 0x1;
                     $info['flv']['audio']['audioType'] = $LastHeaderByte & 0x1;
                 }
                 break;
             case self::GETID3_FLV_TAG_VIDEO:
                 $flv_framecount['video']++;
                 if (!$found_video) {
                     $found_video = true;
                     $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x7;
                     $FLVvideoHeader = fread($this->getid3->fp, 11);
                     if ($info['flv']['video']['videoCodec'] == self::GETID3_FLV_VIDEO_H264) {
                         // this code block contributed by: moysevichØgmail*com
                         $AVCPacketType = Helper::BigEndian2Int(substr($FLVvideoHeader, 0, 1));
                         if ($AVCPacketType == AVCSequenceParameterSetReader::H264_AVC_SEQUENCE_HEADER) {
                             //	read AVCDecoderConfigurationRecord
                             $configurationVersion = Helper::BigEndian2Int(substr($FLVvideoHeader, 4, 1));
                             $AVCProfileIndication = Helper::BigEndian2Int(substr($FLVvideoHeader, 5, 1));
                             $profile_compatibility = Helper::BigEndian2Int(substr($FLVvideoHeader, 6, 1));
                             $lengthSizeMinusOne = Helper::BigEndian2Int(substr($FLVvideoHeader, 7, 1));
                             $numOfSequenceParameterSets = Helper::BigEndian2Int(substr($FLVvideoHeader, 8, 1));
                             if (($numOfSequenceParameterSets & 0x1f) != 0) {
                                 //	there is at least one SequenceParameterSet
                                 //	read size of the first SequenceParameterSet
                                 //$spsSize = GetId3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2));
                                 $spsSize = Helper::LittleEndian2Int(substr($FLVvideoHeader, 9, 2));
                                 //	read the first SequenceParameterSet
                                 $sps = fread($this->getid3->fp, $spsSize);
                                 if (strlen($sps) == $spsSize) {
                                     //	make sure that whole SequenceParameterSet was red
                                     $spsReader = new AVCSequenceParameterSetReader($sps);
                                     $spsReader->readData();
                                     $info['video']['resolution_x'] = $spsReader->getWidth();
                                     $info['video']['resolution_y'] = $spsReader->getHeight();
                                 }
                             }
                         }
                         // end: moysevichØgmail*com
                     } elseif ($info['flv']['video']['videoCodec'] == self::GETID3_FLV_VIDEO_H263) {
                         $PictureSizeType = Helper::BigEndian2Int(substr($FLVvideoHeader, 3, 2)) >> 7;
                         $PictureSizeType = $PictureSizeType & 0x7;
                         $info['flv']['header']['videoSizeType'] = $PictureSizeType;
                         switch ($PictureSizeType) {
                             case 0:
                                 //$PictureSizeEnc = GetId3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
                                 //$PictureSizeEnc <<= 1;
                                 //$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
                                 //$PictureSizeEnc = GetId3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
                                 //$PictureSizeEnc <<= 1;
                                 //$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
                                 $PictureSizeEnc['x'] = Helper::BigEndian2Int(substr($FLVvideoHeader, 4, 2));
                                 $PictureSizeEnc['y'] = Helper::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
                                 $PictureSizeEnc['x'] >>= 7;
                                 $PictureSizeEnc['y'] >>= 7;
                                 $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xff;
                                 $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xff;
                                 break;
                             case 1:
                                 $PictureSizeEnc['x'] = Helper::BigEndian2Int(substr($FLVvideoHeader, 4, 3));
                                 $PictureSizeEnc['y'] = Helper::BigEndian2Int(substr($FLVvideoHeader, 6, 3));
                                 $PictureSizeEnc['x'] >>= 7;
                                 $PictureSizeEnc['y'] >>= 7;
                                 $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xffff;
                                 $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xffff;
                                 break;
                             case 2:
                                 $info['video']['resolution_x'] = 352;
                                 $info['video']['resolution_y'] = 288;
                                 break;
                             case 3:
                                 $info['video']['resolution_x'] = 176;
                                 $info['video']['resolution_y'] = 144;
                                 break;
                             case 4:
                                 $info['video']['resolution_x'] = 128;
                                 $info['video']['resolution_y'] = 96;
                                 break;
                             case 5:
                                 $info['video']['resolution_x'] = 320;
                                 $info['video']['resolution_y'] = 240;
                                 break;
                             case 6:
                                 $info['video']['resolution_x'] = 160;
                                 $info['video']['resolution_y'] = 120;
                                 break;
                             default:
                                 $info['video']['resolution_x'] = 0;
                                 $info['video']['resolution_y'] = 0;
                                 break;
                         }
                     }
                     $info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
                 }
                 break;
                 // Meta tag
             // Meta tag
             case self::GETID3_FLV_TAG_META:
                 if (!$found_meta) {
                     $found_meta = true;
                     fseek($this->getid3->fp, -1, SEEK_CUR);
                     $datachunk = fread($this->getid3->fp, $DataLength);
                     $AMFstream = new AMFStream($datachunk);
                     $reader = new AMFReader($AMFstream);
                     $eventName = $reader->readData();
                     $info['flv']['meta'][$eventName] = $reader->readData();
                     unset($reader);
                     $copykeys = array('framerate' => 'frame_rate', 'width' => 'resolution_x', 'height' => 'resolution_y', 'audiodatarate' => 'bitrate', 'videodatarate' => 'bitrate');
                     foreach ($copykeys as $sourcekey => $destkey) {
                         if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) {
                             switch ($sourcekey) {
                                 case 'width':
                                 case 'height':
                                     $info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey]));
                                     break;
                                 case 'audiodatarate':
                                     $info['audio'][$destkey] = Helper::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000));
                                     break;
                                 case 'videodatarate':
                                 case 'frame_rate':
                                 default:
                                     $info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey];
                                     break;
                             }
                         }
                     }
                     if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
                         $found_valid_meta_playtime = true;
                     }
                 }
                 break;
             default:
                 // noop
                 break;
         }
         fseek($this->getid3->fp, $NextOffset, SEEK_SET);
     }
     $info['playtime_seconds'] = $Duration / 1000;
     if ($info['playtime_seconds'] > 0) {
         $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     }
     if ($info['flv']['header']['hasAudio']) {
         $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['audio']['audioFormat']);
         $info['audio']['sample_rate'] = $this->FLVaudioRate($info['flv']['audio']['audioRate']);
         $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info['flv']['audio']['audioSampleSize']);
         $info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1;
         // 0=mono,1=stereo
         $info['audio']['lossless'] = $info['flv']['audio']['audioFormat'] ? false : true;
         // 0=uncompressed
         $info['audio']['dataformat'] = 'flv';
     }
     if (!empty($info['flv']['header']['hasVideo'])) {
         $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['video']['videoCodec']);
         $info['video']['dataformat'] = 'flv';
         $info['video']['lossless'] = false;
     }
     // Set information from meta
     if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
         $info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration'];
         $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     }
     if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) {
         $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['meta']['onMetaData']['audiocodecid']);
     }
     if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) {
         $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['meta']['onMetaData']['videocodecid']);
     }
     return true;
 }
コード例 #15
0
ファイル: Voc.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     $OriginalAVdataOffset = $info['avdataoffset'];
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $VOCheader = fread($this->getid3->fp, 26);
     $magic = 'Creative Voice File';
     if (substr($VOCheader, 0, 19) != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($VOCheader, 0, 19)) . '"';
         return false;
     }
     // shortcuts
     $thisfile_audio =& $info['audio'];
     $info['voc'] = array();
     $thisfile_voc =& $info['voc'];
     $info['fileformat'] = 'voc';
     $thisfile_audio['dataformat'] = 'voc';
     $thisfile_audio['bitrate_mode'] = 'cbr';
     $thisfile_audio['lossless'] = true;
     $thisfile_audio['channels'] = 1;
     // might be overriden below
     $thisfile_audio['bits_per_sample'] = 8;
     // might be overriden below
     // byte #     Description
     // ------     ------------------------------------------
     // 00-12      'Creative Voice File'
     // 13         1A (eof to abort printing of file)
     // 14-15      Offset of first datablock in .voc file (std 1A 00 in Intel Notation)
     // 16-17      Version number (minor,major) (VOC-HDR puts 0A 01)
     // 18-19      2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11)
     $thisfile_voc['header']['datablock_offset'] = Helper::LittleEndian2Int(substr($VOCheader, 20, 2));
     $thisfile_voc['header']['minor_version'] = Helper::LittleEndian2Int(substr($VOCheader, 22, 1));
     $thisfile_voc['header']['major_version'] = Helper::LittleEndian2Int(substr($VOCheader, 23, 1));
     do {
         $BlockOffset = ftell($this->getid3->fp);
         $BlockData = fread($this->getid3->fp, 4);
         $BlockType = ord($BlockData[0]);
         $BlockSize = Helper::LittleEndian2Int(substr($BlockData, 1, 3));
         $ThisBlock = array();
         Helper::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1);
         switch ($BlockType) {
             case 0:
                 // Terminator
                 // do nothing, we'll break out of the loop down below
                 break;
             case 1:
                 // Sound data
                 $BlockData .= fread($this->getid3->fp, 2);
                 if ($info['avdataoffset'] <= $OriginalAVdataOffset) {
                     $info['avdataoffset'] = ftell($this->getid3->fp);
                 }
                 fseek($this->getid3->fp, $BlockSize - 2, SEEK_CUR);
                 $ThisBlock['sample_rate_id'] = Helper::LittleEndian2Int(substr($BlockData, 4, 1));
                 $ThisBlock['compression_type'] = Helper::LittleEndian2Int(substr($BlockData, 5, 1));
                 $ThisBlock['compression_name'] = $this->VOCcompressionTypeLookup($ThisBlock['compression_type']);
                 if ($ThisBlock['compression_type'] <= 3) {
                     $thisfile_voc['compressed_bits_per_sample'] = Helper::CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name']));
                 }
                 // Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available)
                 if (empty($thisfile_audio['sample_rate'])) {
                     // SR byte = 256 - (1000000 / sample_rate)
                     $thisfile_audio['sample_rate'] = Helper::trunc(1000000 / (256 - $ThisBlock['sample_rate_id']) / $thisfile_audio['channels']);
                 }
                 break;
             case 2:
                 // Sound continue
             // Sound continue
             case 3:
                 // Silence
             // Silence
             case 4:
                 // Marker
             // Marker
             case 6:
                 // Repeat
             // Repeat
             case 7:
                 // End repeat
                 // nothing useful, just skip
                 fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
                 break;
             case 8:
                 // Extended
                 $BlockData .= fread($this->getid3->fp, 4);
                 //00-01  Time Constant:
                 //   Mono: 65536 - (256000000 / sample_rate)
                 // Stereo: 65536 - (256000000 / (sample_rate * 2))
                 $ThisBlock['time_constant'] = Helper::LittleEndian2Int(substr($BlockData, 4, 2));
                 $ThisBlock['pack_method'] = Helper::LittleEndian2Int(substr($BlockData, 6, 1));
                 $ThisBlock['stereo'] = (bool) Helper::LittleEndian2Int(substr($BlockData, 7, 1));
                 $thisfile_audio['channels'] = $ThisBlock['stereo'] ? 2 : 1;
                 $thisfile_audio['sample_rate'] = Helper::trunc(256000000 / (65536 - $ThisBlock['time_constant']) / $thisfile_audio['channels']);
                 break;
             case 9:
                 // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit
                 $BlockData .= fread($this->getid3->fp, 12);
                 if ($info['avdataoffset'] <= $OriginalAVdataOffset) {
                     $info['avdataoffset'] = ftell($this->getid3->fp);
                 }
                 fseek($this->getid3->fp, $BlockSize - 12, SEEK_CUR);
                 $ThisBlock['sample_rate'] = Helper::LittleEndian2Int(substr($BlockData, 4, 4));
                 $ThisBlock['bits_per_sample'] = Helper::LittleEndian2Int(substr($BlockData, 8, 1));
                 $ThisBlock['channels'] = Helper::LittleEndian2Int(substr($BlockData, 9, 1));
                 $ThisBlock['wFormat'] = Helper::LittleEndian2Int(substr($BlockData, 10, 2));
                 $ThisBlock['compression_name'] = $this->VOCwFormatLookup($ThisBlock['wFormat']);
                 if ($this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) {
                     $thisfile_voc['compressed_bits_per_sample'] = $this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']);
                 }
                 $thisfile_audio['sample_rate'] = $ThisBlock['sample_rate'];
                 $thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample'];
                 $thisfile_audio['channels'] = $ThisBlock['channels'];
                 break;
             default:
                 $info['warning'][] = 'Unhandled block type "' . $BlockType . '" at offset ' . $BlockOffset;
                 fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
                 break;
         }
         if (!empty($ThisBlock)) {
             $ThisBlock['block_offset'] = $BlockOffset;
             $ThisBlock['block_size'] = $BlockSize;
             $ThisBlock['block_type_id'] = $BlockType;
             $thisfile_voc['blocks'][] = $ThisBlock;
         }
     } while (!feof($this->getid3->fp) && $BlockType != 0);
     // Terminator block doesn't have size field, so seek back 3 spaces
     fseek($this->getid3->fp, -3, SEEK_CUR);
     ksort($thisfile_voc['blocktypes']);
     if (!empty($thisfile_voc['compressed_bits_per_sample'])) {
         $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']);
         $thisfile_audio['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     }
     return true;
 }
コード例 #16
0
ファイル: Riff.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // initialize these values to an empty array, otherwise they default to NULL
     // and you can't append array values to a NULL value
     $info['riff'] = array('raw' => array());
     // Shortcuts
     $thisfile_riff =& $info['riff'];
     $thisfile_riff_raw =& $thisfile_riff['raw'];
     $thisfile_audio =& $info['audio'];
     $thisfile_video =& $info['video'];
     $thisfile_audio_dataformat =& $thisfile_audio['dataformat'];
     $thisfile_riff_audio =& $thisfile_riff['audio'];
     $thisfile_riff_video =& $thisfile_riff['video'];
     $Original['avdataoffset'] = $info['avdataoffset'];
     $Original['avdataend'] = $info['avdataend'];
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $RIFFheader = fread($this->getid3->fp, 12);
     $RIFFsubtype = substr($RIFFheader, 8, 4);
     switch (substr($RIFFheader, 0, 4)) {
         case 'FORM':
             $info['fileformat'] = 'aiff';
             $thisfile_riff['header_size'] = $this->EitherEndian2Int(substr($RIFFheader, 4, 4));
             $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($info['avdataoffset'] + 12, $info['avdataoffset'] + $thisfile_riff['header_size']);
             break;
         case 'RIFF':
             // AVI, WAV, etc
         // AVI, WAV, etc
         case 'SDSS':
             // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
         // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
         case 'RMP3':
             // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
             $info['fileformat'] = 'riff';
             $thisfile_riff['header_size'] = $this->EitherEndian2Int(substr($RIFFheader, 4, 4));
             if ($RIFFsubtype == 'RMP3') {
                 // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
                 $RIFFsubtype = 'WAVE';
             }
             $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($info['avdataoffset'] + 12, $info['avdataoffset'] + $thisfile_riff['header_size']);
             if ($info['avdataend'] - $info['filesize'] == 1) {
                 // LiteWave appears to incorrectly *not* pad actual output file
                 // to nearest WORD boundary so may appear to be short by one
                 // byte, in which case - skip warning
                 $info['avdataend'] = $info['filesize'];
             }
             $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size'];
             // 8 = "RIFF" + 32-bit offset
             while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
                 if (!Helper::intValueSupported($nextRIFFoffset + 1024)) {
                     $info['error'][] = 'AVI extends beyond ' . round(PHP_INT_MAX / 1073741824) . 'GB and PHP filesystem functions cannot read that far, playtime is probably wrong';
                     $info['warning'][] = '[avdataend] value may be incorrect, multiple AVIX chunks may be present';
                     break;
                 } else {
                     fseek($this->getid3->fp, $nextRIFFoffset, SEEK_SET);
                     $nextRIFFheader = fread($this->getid3->fp, 12);
                     if ($nextRIFFoffset == $info['avdataend'] - 1) {
                         if (substr($nextRIFFheader, 0, 1) == "") {
                             // RIFF padded to WORD boundary, we're actually already at the end
                             break;
                         }
                     }
                     $nextRIFFheaderID = substr($nextRIFFheader, 0, 4);
                     $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
                     $nextRIFFtype = substr($nextRIFFheader, 8, 4);
                     $chunkdata = array();
                     $chunkdata['offset'] = $nextRIFFoffset + 8;
                     $chunkdata['size'] = $nextRIFFsize;
                     $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
                     switch ($nextRIFFheaderID) {
                         case 'RIFF':
                             $info['avdataend'] = $nextRIFFoffset;
                             if (!Helper::intValueSupported($info['avdataend'])) {
                                 $info['error'][] = 'AVI extends beyond ' . round(PHP_INT_MAX / 1073741824) . 'GB and PHP filesystem functions cannot read that far, playtime is probably wrong';
                                 $info['warning'][] = '[avdataend] value may be incorrect, multiple AVIX chunks may be present';
                             }
                             $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $chunkdata['offset'] + $chunkdata['size']);
                             if (!isset($thisfile_riff[$nextRIFFtype])) {
                                 $thisfile_riff[$nextRIFFtype] = array();
                             }
                             $thisfile_riff[$nextRIFFtype][] = $chunkdata;
                             break;
                         case 'JUNK':
                             // ignore
                             $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
                             break;
                         default:
                             if ($info['filesize'] == $chunkdata['offset'] - 8 + 128) {
                                 $DIVXTAG = $nextRIFFheader . fread($this->getid3->fp, 128 - 12);
                                 if (substr($DIVXTAG, -7) == 'DIVXTAG') {
                                     // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file
                                     $info['warning'][] = 'Found wrongly-structured DIVXTAG at offset ' . (ftell($this->getid3->fp) - 128 + 12) . ', parsing anyway';
                                     $thisfile_riff['DIVXTAG'] = $this->ParseDIVXTAG($DIVXTAG);
                                     foreach ($thisfile_riff['DIVXTAG'] as $key => $value) {
                                         if ($value && !preg_match('#_id$#', $key)) {
                                             $thisfile_riff['comments'][$key][] = $value;
                                         }
                                     }
                                     break 2;
                                 }
                             }
                             $info['warning'][] = 'expecting "RIFF" or "JUNK" at ' . $nextRIFFoffset . ', found ' . Helper::PrintHexBytes(substr($nextRIFFheader, 0, 4)) . ' - skipping rest of file';
                             break 2;
                     }
                 }
             }
             if ($RIFFsubtype == 'WAVE') {
                 $thisfile_riff_WAVE =& $thisfile_riff['WAVE'];
             }
             break;
         default:
             $info['error'][] = 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "' . $RIFFsubtype . '" instead';
             unset($info['fileformat']);
             return false;
             break;
     }
     $streamindex = 0;
     switch ($RIFFsubtype) {
         case 'WAVE':
             if (empty($thisfile_audio['bitrate_mode'])) {
                 $thisfile_audio['bitrate_mode'] = 'cbr';
             }
             if (empty($thisfile_audio_dataformat)) {
                 $thisfile_audio_dataformat = 'wav';
             }
             if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
                 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
             }
             if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
                 $thisfile_riff_audio[$streamindex] = self::RIFFparseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
                 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
                 if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || $thisfile_riff_audio[$streamindex]['bitrate'] == 0) {
                     $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
                     return false;
                 }
                 $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
                 unset($thisfile_riff_audio[$streamindex]['raw']);
                 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
                 $thisfile_audio = Helper::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
                 if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
                     $info['warning'][] = 'Audio codec = ' . $thisfile_audio['codec'];
                 }
                 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
                 $info['playtime_seconds'] = (double) (($info['avdataend'] - $info['avdataoffset']) * 8 / $thisfile_audio['bitrate']);
                 $thisfile_audio['lossless'] = false;
                 if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
                     switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
                         case 0x1:
                             // PCM
                             $thisfile_audio['lossless'] = true;
                             break;
                         case 0x2000:
                             // AC-3
                             $thisfile_audio_dataformat = 'ac3';
                             break;
                         default:
                             // do nothing
                             break;
                     }
                 }
                 $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
                 $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                 $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
                 $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
             }
             if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
                 // shortcuts
                 $rgadData =& $thisfile_riff_WAVE['rgad'][0]['data'];
                 $thisfile_riff_raw['rgad'] = array('track' => array(), 'album' => array());
                 $thisfile_riff_raw_rgad =& $thisfile_riff_raw['rgad'];
                 $thisfile_riff_raw_rgad_track =& $thisfile_riff_raw_rgad['track'];
                 $thisfile_riff_raw_rgad_album =& $thisfile_riff_raw_rgad['album'];
                 $thisfile_riff_raw_rgad['fPeakAmplitude'] = Helper::LittleEndian2Float(substr($rgadData, 0, 4));
                 $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2));
                 $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2));
                 $nRadioRgAdjustBitstring = str_pad(Helper::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                 $nAudiophileRgAdjustBitstring = str_pad(Helper::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                 $thisfile_riff_raw_rgad_track['name'] = Helper::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                 $thisfile_riff_raw_rgad_track['originator'] = Helper::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                 $thisfile_riff_raw_rgad_track['signbit'] = Helper::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                 $thisfile_riff_raw_rgad_track['adjustment'] = Helper::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                 $thisfile_riff_raw_rgad_album['name'] = Helper::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                 $thisfile_riff_raw_rgad_album['originator'] = Helper::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                 $thisfile_riff_raw_rgad_album['signbit'] = Helper::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                 $thisfile_riff_raw_rgad_album['adjustment'] = Helper::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                 $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
                 if ($thisfile_riff_raw_rgad_track['name'] != 0 && $thisfile_riff_raw_rgad_track['originator'] != 0) {
                     $thisfile_riff['rgad']['track']['name'] = Helper::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
                     $thisfile_riff['rgad']['track']['originator'] = Helper::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
                     $thisfile_riff['rgad']['track']['adjustment'] = Helper::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
                 }
                 if ($thisfile_riff_raw_rgad_album['name'] != 0 && $thisfile_riff_raw_rgad_album['originator'] != 0) {
                     $thisfile_riff['rgad']['album']['name'] = Helper::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
                     $thisfile_riff['rgad']['album']['originator'] = Helper::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
                     $thisfile_riff['rgad']['album']['adjustment'] = Helper::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
                 }
             }
             if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
                 $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
                 // This should be a good way of calculating exact playtime,
                 // but some sample files have had incorrect number of samples,
                 // so cannot use this method
                 // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
                 //     $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
                 // }
             }
             if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
                 $thisfile_audio['bitrate'] = Helper::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
             }
             if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_bext_0 =& $thisfile_riff_WAVE['bext'][0];
                 $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
                 $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
                 $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
                 $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
                 $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
                 $thisfile_riff_WAVE_bext_0['time_reference'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
                 $thisfile_riff_WAVE_bext_0['bwf_version'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
                 $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
                 $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
                 if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
                     if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
                         list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
                         list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
                         $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
                     } else {
                         $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';
                     }
                 } else {
                     $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';
                 }
                 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
                 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
             }
             if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_MEXT_0 =& $thisfile_riff_WAVE['MEXT'][0];
                 $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
                 $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x1);
                 if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
                     $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x2 ? false : true;
                     $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x4);
                     $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x8);
                     $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
                 }
                 $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
                 $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x1);
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x2);
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x4);
             }
             if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_cart_0 =& $thisfile_riff_WAVE['cart'][0];
                 $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
                 $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
                 $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
                 $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
                 $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
                 $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
                 $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
                 $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
                 $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
                 $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
                 $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
                 $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
                 $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
                 $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
                 $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
                 $thisfile_riff_WAVE_cart_0['zero_db_reference'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
                 for ($i = 0; $i < 8; ++$i) {
                     $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + $i * 8, 4);
                     $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + $i * 8 + 4, 4));
                 }
                 $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
                 $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
                 $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
                 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
             }
             if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
                 // SoundMiner metadata
                 // shortcuts
                 $thisfile_riff_WAVE_SNDM_0 =& $thisfile_riff_WAVE['SNDM'][0];
                 $thisfile_riff_WAVE_SNDM_0_data =& $thisfile_riff_WAVE_SNDM_0['data'];
                 $SNDM_startoffset = 0;
                 $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size'];
                 while ($SNDM_startoffset < $SNDM_endoffset) {
                     $SNDM_thisTagOffset = 0;
                     $SNDM_thisTagSize = Helper::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
                     $SNDM_thisTagOffset += 4;
                     $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
                     $SNDM_thisTagOffset += 4;
                     $SNDM_thisTagDataSize = Helper::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
                     $SNDM_thisTagOffset += 2;
                     $SNDM_thisTagDataFlags = Helper::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
                     $SNDM_thisTagOffset += 2;
                     $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
                     $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
                     if ($SNDM_thisTagSize != 4 + 4 + 2 + 2 + $SNDM_thisTagDataSize) {
                         $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: ' . $SNDM_thisTagSize . ', found: ' . (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize) . ') at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset) . ')';
                         break;
                     } elseif ($SNDM_thisTagSize <= 0) {
                         $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset) . ')';
                         break;
                     }
                     $SNDM_startoffset += $SNDM_thisTagSize;
                     $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
                     if ($parsedkey = $this->RIFFwaveSNDMtagLookup($SNDM_thisTagKey)) {
                         $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
                     } else {
                         $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "' . $SNDM_thisTagKey . '" at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset) . ')';
                     }
                 }
                 $tagmapping = array('tracktitle' => 'title', 'category' => 'genre', 'cdtitle' => 'album', 'tracktitle' => 'title');
                 foreach ($tagmapping as $fromkey => $tokey) {
                     if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
                         $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
                     }
                 }
             }
             if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
                 // requires functions simplexml_load_string and get_object_vars
                 if ($parsedXML = Helper::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
                     $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
                     if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
                         @(list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']));
                         $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
                     }
                     if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
                         @(list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']));
                         $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
                     }
                     if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
                         $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'] . $parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
                         $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE'];
                         $h = floor($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
                         $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - $h * 3600) / 60);
                         $s = floor($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - $h * 3600 - $m * 60);
                         $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - $h * 3600 - $m * 60 - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
                         $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
                         $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
                     }
                     unset($parsedXML);
                 }
             }
             if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
                 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
                 $info['playtime_seconds'] = (double) (($info['avdataend'] - $info['avdataoffset']) * 8 / $thisfile_audio['bitrate']);
             }
             if (!empty($info['wavpack'])) {
                 $thisfile_audio_dataformat = 'wavpack';
                 $thisfile_audio['bitrate_mode'] = 'vbr';
                 $thisfile_audio['encoder'] = 'WavPack v' . $info['wavpack']['version'];
                 // Reset to the way it was - RIFF parsing will have messed this up
                 $info['avdataend'] = $Original['avdataend'];
                 $thisfile_audio['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
                 fseek($this->getid3->fp, $info['avdataoffset'] - 44, SEEK_SET);
                 $RIFFdata = fread($this->getid3->fp, 44);
                 $OrignalRIFFheaderSize = Helper::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
                 $OrignalRIFFdataSize = Helper::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
                 if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
                     $info['avdataend'] -= $OrignalRIFFheaderSize - $OrignalRIFFdataSize;
                     fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
                     $RIFFdata .= fread($this->getid3->fp, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
                 }
                 // move the data chunk after all other chunks (if any)
                 // so that the RIFF parser doesn't see EOF when trying
                 // to skip over the data chunk
                 $RIFFdata = substr($RIFFdata, 0, 36) . substr($RIFFdata, 44) . substr($RIFFdata, 36, 8);
                 $getid3_riff = new self($this->getid3);
                 $getid3_riff->ParseRIFFdata($RIFFdata);
                 unset($getid3_riff);
             }
             if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
                 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
                     case 0x1:
                         // PCM
                         if (!empty($info['ac3'])) {
                             // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
                             $thisfile_audio['wformattag'] = 0x2000;
                             $thisfile_audio['codec'] = $this->RIFFwFormatTagLookup($thisfile_audio['wformattag']);
                             $thisfile_audio['lossless'] = false;
                             $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
                             $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
                         }
                         break;
                     case 0x8ae:
                         // ClearJump LiteWave
                         $thisfile_audio['bitrate_mode'] = 'vbr';
                         $thisfile_audio_dataformat = 'litewave';
                         //typedef struct tagSLwFormat {
                         //  WORD    m_wCompFormat;     // low byte defines compression method, high byte is compression flags
                         //  DWORD   m_dwScale;         // scale factor for lossy compression
                         //  DWORD   m_dwBlockSize;     // number of samples in encoded blocks
                         //  WORD    m_wQuality;        // alias for the scale factor
                         //  WORD    m_wMarkDistance;   // distance between marks in bytes
                         //  WORD    m_wReserved;
                         //
                         //  //following paramters are ignored if CF_FILESRC is not set
                         //  DWORD   m_dwOrgSize;       // original file size in bytes
                         //  WORD    m_bFactExists;     // indicates if 'fact' chunk exists in the original file
                         //  DWORD   m_dwRiffChunkSize; // riff chunk size in the original file
                         //
                         //  PCMWAVEFORMAT m_OrgWf;     // original wave format
                         // }SLwFormat, *PSLwFormat;
                         // shortcut
                         $thisfile_riff['litewave']['raw'] = array();
                         $thisfile_riff_litewave =& $thisfile_riff['litewave'];
                         $thisfile_riff_litewave_raw =& $thisfile_riff_litewave['raw'];
                         $thisfile_riff_litewave_raw['compression_method'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 18, 1));
                         $thisfile_riff_litewave_raw['compression_flags'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 19, 1));
                         $thisfile_riff_litewave_raw['m_dwScale'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 20, 4));
                         $thisfile_riff_litewave_raw['m_dwBlockSize'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 24, 4));
                         $thisfile_riff_litewave_raw['m_wQuality'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 28, 2));
                         $thisfile_riff_litewave_raw['m_wMarkDistance'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 30, 2));
                         $thisfile_riff_litewave_raw['m_wReserved'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 32, 2));
                         $thisfile_riff_litewave_raw['m_dwOrgSize'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 34, 4));
                         $thisfile_riff_litewave_raw['m_bFactExists'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 38, 2));
                         $thisfile_riff_litewave_raw['m_dwRiffChunkSize'] = Helper::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 40, 4));
                         //$thisfile_riff_litewave['quality_factor'] = intval(round((2000 - $thisfile_riff_litewave_raw['m_dwScale']) / 20));
                         $thisfile_riff_litewave['quality_factor'] = $thisfile_riff_litewave_raw['m_wQuality'];
                         $thisfile_riff_litewave['flags']['raw_source'] = $thisfile_riff_litewave_raw['compression_flags'] & 0x1 ? false : true;
                         $thisfile_riff_litewave['flags']['vbr_blocksize'] = $thisfile_riff_litewave_raw['compression_flags'] & 0x2 ? false : true;
                         $thisfile_riff_litewave['flags']['seekpoints'] = (bool) ($thisfile_riff_litewave_raw['compression_flags'] & 0x4);
                         $thisfile_audio['lossless'] = $thisfile_riff_litewave_raw['m_wQuality'] == 100 ? true : false;
                         $thisfile_audio['encoder_options'] = '-q' . $thisfile_riff_litewave['quality_factor'];
                         break;
                     default:
                         break;
                 }
             }
             if ($info['avdataend'] > $info['filesize']) {
                 switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
                     case 'wavpack':
                         // WavPack
                     // WavPack
                     case 'lpac':
                         // LPAC
                     // LPAC
                     case 'ofr':
                         // OptimFROG
                     // OptimFROG
                     case 'ofs':
                         // OptimFROG DualStream
                         // lossless compressed audio formats that keep original RIFF headers - skip warning
                         break;
                     case 'litewave':
                         if ($info['avdataend'] - $info['filesize'] == 1) {
                             // LiteWave appears to incorrectly *not* pad actual output file
                             // to nearest WORD boundary so may appear to be short by one
                             // byte, in which case - skip warning
                         } else {
                             // Short by more than one byte, throw warning
                             $info['warning'][] = 'Probably truncated file - expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' (short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])) . ' bytes)';
                             $info['avdataend'] = $info['filesize'];
                         }
                         break;
                     default:
                         if ($info['avdataend'] - $info['filesize'] == 1 && $thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2 == 0 && ($info['filesize'] - $info['avdataoffset']) % 2 == 1) {
                             // output file appears to be incorrectly *not* padded to nearest WORD boundary
                             // Output less severe warning
                             $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' therefore short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])) . ' bytes)';
                             $info['avdataend'] = $info['filesize'];
                         } else {
                             // Short by more than one byte, throw warning
                             $info['warning'][] = 'Probably truncated file - expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' (short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])) . ' bytes)';
                             $info['avdataend'] = $info['filesize'];
                         }
                         break;
                 }
             }
             if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
                 if ($info['avdataend'] - $info['avdataoffset'] - $info['mpeg']['audio']['LAME']['audio_bytes'] == 1) {
                     --$info['avdataend'];
                     $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
                 }
             }
             if (isset($thisfile_audio_dataformat) && $thisfile_audio_dataformat == 'ac3') {
                 unset($thisfile_audio['bits_per_sample']);
                 if (!empty($info['ac3']['bitrate']) && $info['ac3']['bitrate'] != $thisfile_audio['bitrate']) {
                     $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
                 }
             }
             break;
         case 'AVI ':
             $thisfile_video['bitrate_mode'] = 'vbr';
             // maybe not, but probably
             $thisfile_video['dataformat'] = 'avi';
             $info['mime_type'] = 'video/avi';
             if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
                 if (isset($thisfile_riff['AVIX'])) {
                     $info['avdataend'] = $thisfile_riff['AVIX'][count($thisfile_riff['AVIX']) - 1]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][count($thisfile_riff['AVIX']) - 1]['chunks']['movi']['size'];
                 } else {
                     $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
                 }
                 if ($info['avdataend'] > $info['filesize']) {
                     $info['warning'][] = 'Probably truncated file - expecting ' . ($info['avdataend'] - $info['avdataoffset']) . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' (short by ' . ($info['avdataend'] - $info['filesize']) . ' bytes)';
                     $info['avdataend'] = $info['filesize'];
                 }
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
                 //$bIndexType = array(
                 //    0x00 => 'AVI_INDEX_OF_INDEXES',
                 //	0x01 => 'AVI_INDEX_OF_CHUNKS',
                 //	0x80 => 'AVI_INDEX_IS_DATA',
                 //);
                 //$bIndexSubtype = array(
                 //	0x01 => array(
                 //		0x01 => 'AVI_INDEX_2FIELD',
                 //	),
                 //);
                 foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
                     $thisfile_riff_avi_hdrl_strl_indx_stream_data =& $thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
                     $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 0, 2));
                     $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 2, 1));
                     $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 3, 1));
                     $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 4, 4));
                     $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 8, 4);
                     $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 12, 4));
                     //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name']    =    $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
                     //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
                     unset($thisfile_riff_avi_hdrl_strl_indx_stream_data);
                 }
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                 $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
                 // shortcut
                 $thisfile_riff_raw['avih'] = array();
                 $thisfile_riff_raw_avih =& $thisfile_riff_raw['avih'];
                 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4));
                 // frame display rate (or 0L)
                 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
                     $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                     return false;
                 }
                 $thisfile_riff_raw_avih['dwMaxBytesPerSec'] = $this->EitherEndian2Int(substr($avihData, 4, 4));
                 // max. transfer rate
                 $thisfile_riff_raw_avih['dwPaddingGranularity'] = $this->EitherEndian2Int(substr($avihData, 8, 4));
                 // pad to multiples of this size; normally 2K.
                 $thisfile_riff_raw_avih['dwFlags'] = $this->EitherEndian2Int(substr($avihData, 12, 4));
                 // the ever-present flags
                 $thisfile_riff_raw_avih['dwTotalFrames'] = $this->EitherEndian2Int(substr($avihData, 16, 4));
                 // # frames in file
                 $thisfile_riff_raw_avih['dwInitialFrames'] = $this->EitherEndian2Int(substr($avihData, 20, 4));
                 $thisfile_riff_raw_avih['dwStreams'] = $this->EitherEndian2Int(substr($avihData, 24, 4));
                 $thisfile_riff_raw_avih['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($avihData, 28, 4));
                 $thisfile_riff_raw_avih['dwWidth'] = $this->EitherEndian2Int(substr($avihData, 32, 4));
                 $thisfile_riff_raw_avih['dwHeight'] = $this->EitherEndian2Int(substr($avihData, 36, 4));
                 $thisfile_riff_raw_avih['dwScale'] = $this->EitherEndian2Int(substr($avihData, 40, 4));
                 $thisfile_riff_raw_avih['dwRate'] = $this->EitherEndian2Int(substr($avihData, 44, 4));
                 $thisfile_riff_raw_avih['dwStart'] = $this->EitherEndian2Int(substr($avihData, 48, 4));
                 $thisfile_riff_raw_avih['dwLength'] = $this->EitherEndian2Int(substr($avihData, 52, 4));
                 $thisfile_riff_raw_avih['flags']['hasindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x10);
                 $thisfile_riff_raw_avih['flags']['mustuseindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x20);
                 $thisfile_riff_raw_avih['flags']['interleaved'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x100);
                 $thisfile_riff_raw_avih['flags']['trustcktype'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x800);
                 $thisfile_riff_raw_avih['flags']['capturedfile'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x10000);
                 $thisfile_riff_raw_avih['flags']['copyrighted'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x20010);
                 // shortcut
                 $thisfile_riff_video[$streamindex] = array();
                 $thisfile_riff_video_current =& $thisfile_riff_video[$streamindex];
                 if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
                     $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
                     $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
                 }
                 if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
                     $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
                     $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
                 }
                 if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
                     $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
                     $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
                 }
                 $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
                 $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                 if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
                     for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); ++$i) {
                         if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                             $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                             $strhfccType = substr($strhData, 0, 4);
                             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                 // shortcut
                                 $thisfile_riff_raw_strf_strhfccType_streamindex =& $thisfile_riff_raw['strf'][$strhfccType][$streamindex];
                                 switch ($strhfccType) {
                                     case 'auds':
                                         $thisfile_audio['bitrate_mode'] = 'cbr';
                                         $thisfile_audio_dataformat = 'wav';
                                         if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
                                             $streamindex = count($thisfile_riff_audio);
                                         }
                                         $thisfile_riff_audio[$streamindex] = self::RIFFparseWAVEFORMATex($strfData);
                                         $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
                                         // shortcut
                                         $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
                                         $thisfile_audio_streams_currentstream =& $thisfile_audio['streams'][$streamindex];
                                         if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
                                             unset($thisfile_audio_streams_currentstream['bits_per_sample']);
                                         }
                                         $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
                                         unset($thisfile_audio_streams_currentstream['raw']);
                                         // shortcut
                                         $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
                                         unset($thisfile_riff_audio[$streamindex]['raw']);
                                         $thisfile_audio = Helper::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
                                         $thisfile_audio['lossless'] = false;
                                         switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
                                             case 0x1:
                                                 // PCM
                                                 $thisfile_audio_dataformat = 'wav';
                                                 $thisfile_audio['lossless'] = true;
                                                 break;
                                             case 0x50:
                                                 // MPEG Layer 2 or Layer 1
                                                 $thisfile_audio_dataformat = 'mp2';
                                                 // Assume Layer-2
                                                 break;
                                             case 0x55:
                                                 // MPEG Layer 3
                                                 $thisfile_audio_dataformat = 'mp3';
                                                 break;
                                             case 0xff:
                                                 // AAC
                                                 $thisfile_audio_dataformat = 'aac';
                                                 break;
                                             case 0x161:
                                                 // Windows Media v7 / v8 / v9
                                             // Windows Media v7 / v8 / v9
                                             case 0x162:
                                                 // Windows Media Professional v9
                                             // Windows Media Professional v9
                                             case 0x163:
                                                 // Windows Media Lossess v9
                                                 $thisfile_audio_dataformat = 'wma';
                                                 break;
                                             case 0x2000:
                                                 // AC-3
                                                 $thisfile_audio_dataformat = 'ac3';
                                                 break;
                                             case 0x2001:
                                                 // DTS
                                                 $thisfile_audio_dataformat = 'dts';
                                                 break;
                                             default:
                                                 $thisfile_audio_dataformat = 'wav';
                                                 break;
                                         }
                                         $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
                                         $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
                                         $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                                         break;
                                     case 'iavs':
                                     case 'vids':
                                         // shortcut
                                         $thisfile_riff_raw['strh'][$i] = array();
                                         $thisfile_riff_raw_strh_current =& $thisfile_riff_raw['strh'][$i];
                                         $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4);
                                         // same as $strhfccType;
                                         $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
                                         $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4));
                                         // Contains AVITF_* flags
                                         $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2));
                                         $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2));
                                         $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4));
                                         $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4));
                                         $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4));
                                         $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4));
                                         $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4));
                                         $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
                                         $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4));
                                         $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4));
                                         $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4));
                                         $thisfile_riff_video_current['codec'] = self::RIFFfourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
                                         $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
                                         if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
                                             $thisfile_riff_video_current['codec'] = self::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
                                             $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
                                         }
                                         $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
                                         $thisfile_video['pixel_aspect_ratio'] = (double) 1;
                                         switch ($thisfile_riff_raw_strh_current['fccHandler']) {
                                             case 'HFYU':
                                                 // Huffman Lossless Codec
                                             // Huffman Lossless Codec
                                             case 'IRAW':
                                                 // Intel YUV Uncompressed
                                             // Intel YUV Uncompressed
                                             case 'YUY2':
                                                 // Uncompressed YUV 4:2:2
                                                 $thisfile_video['lossless'] = true;
                                                 break;
                                             default:
                                                 $thisfile_video['lossless'] = false;
                                                 break;
                                         }
                                         switch ($strhfccType) {
                                             case 'vids':
                                                 $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), $info['fileformat'] == 'riff');
                                                 //echo '<pre>'.print_r($thisfile_riff_raw_strf_strhfccType_streamindex, true).'</pre>';
                                                 $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
                                                 if ($thisfile_riff_video_current['codec'] == 'DV') {
                                                     $thisfile_riff_video_current['dv_type'] = 2;
                                                 }
                                                 break;
                                             case 'iavs':
                                                 $thisfile_riff_video_current['dv_type'] = 1;
                                                 break;
                                         }
                                         break;
                                     default:
                                         $info['warning'][] = 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                         break;
                                 }
                             }
                         }
                         if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
                             $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
                             if (self::RIFFfourccLookup($thisfile_video['fourcc'])) {
                                 $thisfile_riff_video_current['codec'] = self::RIFFfourccLookup($thisfile_video['fourcc']);
                                 $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
                             }
                             switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
                                 case 'HFYU':
                                     // Huffman Lossless Codec
                                 // Huffman Lossless Codec
                                 case 'IRAW':
                                     // Intel YUV Uncompressed
                                 // Intel YUV Uncompressed
                                 case 'YUY2':
                                     // Uncompressed YUV 4:2:2
                                     $thisfile_video['lossless'] = true;
                                     //$thisfile_video['bits_per_sample'] = 24;
                                     break;
                                 default:
                                     $thisfile_video['lossless'] = false;
                                     //$thisfile_video['bits_per_sample'] = 24;
                                     break;
                             }
                         }
                     }
                 }
             }
             break;
         case 'CDDA':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = 'cda';
             $thisfile_audio['lossless'] = true;
             unset($info['mime_type']);
             $info['avdataoffset'] = 44;
             if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
                 // shortcut
                 $thisfile_riff_CDDA_fmt_0 =& $thisfile_riff['CDDA']['fmt '][0];
                 $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
                 $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
                 $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
                 $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
                 $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
                 $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
                 $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
                 $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (double) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
                 $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (double) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
                 $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
                 $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
                 // hardcoded data for CD-audio
                 $thisfile_audio['sample_rate'] = 44100;
                 $thisfile_audio['channels'] = 2;
                 $thisfile_audio['bits_per_sample'] = 16;
                 $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
                 $thisfile_audio['bitrate_mode'] = 'cbr';
             }
             break;
         case 'AIFF':
         case 'AIFC':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = 'aiff';
             $thisfile_audio['lossless'] = true;
             $info['mime_type'] = 'audio/x-aiff';
             if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
                 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
                 if ($info['avdataend'] > $info['filesize']) {
                     if ($info['avdataend'] == $info['filesize'] + 1 && $info['filesize'] % 2 == 1) {
                         // structures rounded to 2-byte boundary, but dumb encoders
                         // forget to pad end of file to make this actually work
                     } else {
                         $info['warning'][] = 'Probable truncated AIFF file: expecting ' . $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'] . ' bytes of audio data, only ' . ($info['filesize'] - $info['avdataoffset']) . ' bytes found';
                     }
                     $info['avdataend'] = $info['filesize'];
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_RIFFsubtype_COMM_0_data =& $thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
                 $thisfile_riff_audio['channels'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
                 $thisfile_riff_audio['total_samples'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
                 $thisfile_riff_audio['bits_per_sample'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
                 $thisfile_riff_audio['sample_rate'] = (int) Helper::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
                 if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
                     $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
                     $CodecNameSize = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
                     $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
                     switch ($thisfile_riff_audio['codec_name']) {
                         case 'NONE':
                             $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
                             $thisfile_audio['lossless'] = true;
                             break;
                         case '':
                             switch ($thisfile_riff_audio['codec_fourcc']) {
                                 // http://developer.apple.com/qa/snd/snd07.html
                                 case 'sowt':
                                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
                                     $thisfile_audio['lossless'] = true;
                                     break;
                                 case 'twos':
                                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
                                     $thisfile_audio['lossless'] = true;
                                     break;
                                 default:
                                     break;
                             }
                             break;
                         default:
                             $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
                             $thisfile_audio['lossless'] = false;
                             break;
                     }
                 }
                 $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
                 if ($thisfile_riff_audio['bits_per_sample'] > 0) {
                     $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
                 }
                 $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
                 if ($thisfile_audio['sample_rate'] == 0) {
                     $info['error'][] = 'Corrupted AIFF file: sample_rate == zero';
                     return false;
                 }
                 $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
             }
             if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
                 $offset = 0;
                 $CommentCount = Helper::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
                 $offset += 2;
                 for ($i = 0; $i < $CommentCount; ++$i) {
                     $info['comments_raw'][$i]['timestamp'] = Helper::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
                     $offset += 4;
                     $info['comments_raw'][$i]['marker_id'] = Helper::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
                     $offset += 2;
                     $CommentLength = Helper::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
                     $offset += 2;
                     $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
                     $offset += $CommentLength;
                     $info['comments_raw'][$i]['timestamp_unix'] = Helper::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
                     $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
                 }
             }
             $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
             foreach ($CommentsChunkNames as $key => $value) {
                 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
                     $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
                 }
             }
             break;
         case '8SVX':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = '8svx';
             $thisfile_audio['bits_per_sample'] = 8;
             $thisfile_audio['channels'] = 1;
             // overridden below, if need be
             $info['mime_type'] = 'audio/x-aiff';
             if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
                 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
                 if ($info['avdataend'] > $info['filesize']) {
                     $info['warning'][] = 'Probable truncated AIFF file: expecting ' . $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'] . ' bytes of audio data, only ' . ($info['filesize'] - $info['avdataoffset']) . ' bytes found';
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
                 // shortcut
                 $thisfile_riff_RIFFsubtype_VHDR_0 =& $thisfile_riff[$RIFFsubtype]['VHDR'][0];
                 $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
                 $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
                 $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = Helper::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
                 $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = Helper::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
                 $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
                 switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
                     case 0:
                         $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
                         $thisfile_audio['lossless'] = true;
                         $ActualBitsPerSample = 8;
                         break;
                     case 1:
                         $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
                         $thisfile_audio['lossless'] = false;
                         $ActualBitsPerSample = 4;
                         break;
                     default:
                         $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "' . sCompression . '"';
                         break;
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
                 $ChannelsIndex = Helper::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
                 switch ($ChannelsIndex) {
                     case 6:
                         // Stereo
                         $thisfile_audio['channels'] = 2;
                         break;
                     case 2:
                         // Left channel only
                     // Left channel only
                     case 4:
                         // Right channel only
                         $thisfile_audio['channels'] = 1;
                         break;
                     default:
                         $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "' . $ChannelsIndex . '"';
                         break;
                 }
             }
             $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
             foreach ($CommentsChunkNames as $key => $value) {
                 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
                     $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
                 }
             }
             $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
             if (!empty($thisfile_audio['bitrate'])) {
                 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
             }
             break;
         case 'CDXA':
             $info['mime_type'] = 'video/mpeg';
             if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
                 if (class_exists('GetId3\\Module\\AudioVideo\\Mpeg')) {
                     $getid3_temp = new GetId3Core();
                     $getid3_temp->openfile($this->getid3->filename);
                     $getid3_mpeg = new Mpeg($getid3_temp);
                     $getid3_mpeg->analyze();
                     if (empty($getid3_temp->info['error'])) {
                         $info['audio'] = $getid3_temp->info['audio'];
                         $info['video'] = $getid3_temp->info['video'];
                         $info['mpeg'] = $getid3_temp->info['mpeg'];
                         $info['warning'] = $getid3_temp->info['warning'];
                     }
                     unset($getid3_temp, $getid3_mpeg);
                 }
             }
             break;
         default:
             $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "' . $RIFFsubtype . '" instead';
             unset($info['fileformat']);
             break;
     }
     switch ($RIFFsubtype) {
         case 'WAVE':
         case 'AIFF':
         case 'AIFC':
             if (isset($thisfile_riff[$RIFFsubtype]['ID3 ']) && !array_key_exists('id3 ', $thisfile_riff[$RIFFsubtype])) {
                 $info['warning'][] = 'mapping "ID3 " chunk to "id3 "';
             }
             if (isset($thisfile_riff[$RIFFsubtype]['tag ']) && !array_key_exists('id3 ', $thisfile_riff[$RIFFsubtype])) {
                 $info['warning'][] = 'mapping "tag " chunk to "id3 "';
             }
             if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
                 $getid3_temp = new GetId3Core();
                 $getid3_temp->openfile($this->getid3->filename);
                 $getid3_id3v2 = new Id3v2($getid3_temp);
                 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
                 if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->analyze()) {
                     $info['id3v2'] = $getid3_temp->info['id3v2'];
                 }
                 unset($getid3_temp, $getid3_id3v2);
             }
             break;
     }
     if (isset($thisfile_riff_raw['fmt ']['wFormatTag']) && $thisfile_riff_raw['fmt ']['wFormatTag'] == 1) {
         // http://www.mega-nerd.com/erikd/Blog/Windiots/dts.html
         fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
         $FirstFourBytes = fread($this->getid3->fp, 4);
         if (preg_match('/^\\xFF\\x1F\\x00\\xE8/s', $FirstFourBytes)) {
             // DTSWAV
             $thisfile_audio_dataformat = 'dts';
         } elseif (preg_match('/^\\x7F\\xFF\\x80\\x01/s', $FirstFourBytes)) {
             // DTS, but this probably shouldn't happen
             $thisfile_audio_dataformat = 'dts';
         }
     }
     if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
         $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
     }
     if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
         $this->RIFFcommentsParse($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
     }
     if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
         $this->RIFFcommentsParse($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
     }
     if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
         $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
     }
     if (!isset($info['playtime_seconds'])) {
         $info['playtime_seconds'] = 0;
     }
     if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
         // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
         $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
     } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
         $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
     }
     if ($info['playtime_seconds'] > 0) {
         if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
             if (!isset($info['bitrate'])) {
                 $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
             }
         } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
             if (!isset($thisfile_audio['bitrate'])) {
                 $thisfile_audio['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
             }
         } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
             if (!isset($thisfile_video['bitrate'])) {
                 $thisfile_video['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
             }
         }
     }
     if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && $thisfile_audio['bitrate'] > 0 && $info['playtime_seconds'] > 0) {
         $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
         $thisfile_audio['bitrate'] = 0;
         $thisfile_video['bitrate'] = $info['bitrate'];
         foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
             $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
             $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
         }
         if ($thisfile_video['bitrate'] <= 0) {
             unset($thisfile_video['bitrate']);
         }
         if ($thisfile_audio['bitrate'] <= 0) {
             unset($thisfile_audio['bitrate']);
         }
     }
     if (isset($info['mpeg']['audio'])) {
         $thisfile_audio_dataformat = 'mp' . $info['mpeg']['audio']['layer'];
         $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
         $thisfile_audio['channels'] = $info['mpeg']['audio']['channels'];
         $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate'];
         $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
         if (!empty($info['mpeg']['audio']['codec'])) {
             $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'] . ' ' . $thisfile_audio['codec'];
         }
         if (!empty($thisfile_audio['streams'])) {
             foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
                 if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
                     $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
                     $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
                     $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
                     $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                     $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
                 }
             }
         }
         $getid3_mp3 = new Mp3($this->getid3);
         $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
         unset($getid3_mp3);
     }
     if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && $thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0) {
         switch ($thisfile_audio_dataformat) {
             case 'ac3':
                 // ignore bits_per_sample
                 break;
             default:
                 $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
                 break;
         }
     }
     if (empty($thisfile_riff_raw)) {
         unset($thisfile_riff['raw']);
     }
     if (empty($thisfile_riff_audio)) {
         unset($thisfile_riff['audio']);
     }
     if (empty($thisfile_riff_video)) {
         unset($thisfile_riff['video']);
     }
     return true;
 }
コード例 #17
0
ファイル: Swf.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     $info['fileformat'] = 'swf';
     $info['video']['dataformat'] = 'swf';
     // http://www.openswf.org/spec/SWFfileformat.html
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $SWFfileData = fread($this->getid3->fp, $info['avdataend'] - $info['avdataoffset']);
     // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data
     $info['swf']['header']['signature'] = substr($SWFfileData, 0, 3);
     switch ($info['swf']['header']['signature']) {
         case 'FWS':
             $info['swf']['header']['compressed'] = false;
             break;
         case 'CWS':
             $info['swf']['header']['compressed'] = true;
             break;
         default:
             $info['error'][] = 'Expecting "FWS" or "CWS" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($info['swf']['header']['signature']) . '"';
             unset($info['swf']);
             unset($info['fileformat']);
             return false;
             break;
     }
     $info['swf']['header']['version'] = Helper::LittleEndian2Int(substr($SWFfileData, 3, 1));
     $info['swf']['header']['length'] = Helper::LittleEndian2Int(substr($SWFfileData, 4, 4));
     if ($info['swf']['header']['compressed']) {
         $SWFHead = substr($SWFfileData, 0, 8);
         $SWFfileData = substr($SWFfileData, 8);
         if ($decompressed = @gzuncompress($SWFfileData)) {
             $SWFfileData = $SWFHead . $decompressed;
         } else {
             $info['error'][] = 'Error decompressing compressed SWF data (' . strlen($SWFfileData) . ' bytes compressed, should be ' . ($info['swf']['header']['length'] - 8) . ' bytes uncompressed)';
             return false;
         }
     }
     $FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xf8) >> 3;
     $FrameSizeDataLength = ceil((5 + 4 * $FrameSizeBitsPerValue) / 8);
     $FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x7), 3, '0', STR_PAD_LEFT);
     for ($i = 1; $i < $FrameSizeDataLength; ++$i) {
         $FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT);
     }
     list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1));
     $info['swf']['header']['frame_width'] = Helper::Bin2Dec($X2);
     $info['swf']['header']['frame_height'] = Helper::Bin2Dec($Y2);
     // http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
     // Next in the header is the frame rate, which is kind of weird.
     // It is supposed to be stored as a 16bit integer, but the first byte
     // (or last depending on how you look at it) is completely ignored.
     // Example: 0x000C  ->  0x0C  ->  12     So the frame rate is 12 fps.
     // Byte at (8 + $FrameSizeDataLength) is always zero and ignored
     $info['swf']['header']['frame_rate'] = Helper::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1));
     $info['swf']['header']['frame_count'] = Helper::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2));
     $info['video']['frame_rate'] = $info['swf']['header']['frame_rate'];
     $info['video']['resolution_x'] = intval(round($info['swf']['header']['frame_width'] / 20));
     $info['video']['resolution_y'] = intval(round($info['swf']['header']['frame_height'] / 20));
     $info['video']['pixel_aspect_ratio'] = (double) 1;
     if ($info['swf']['header']['frame_count'] > 0 && $info['swf']['header']['frame_rate'] > 0) {
         $info['playtime_seconds'] = $info['swf']['header']['frame_count'] / $info['swf']['header']['frame_rate'];
     }
     //echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
     // SWF tags
     $CurrentOffset = 12 + $FrameSizeDataLength;
     $SWFdataLength = strlen($SWFfileData);
     while ($CurrentOffset < $SWFdataLength) {
         //echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
         $TagIDTagLength = Helper::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2));
         $TagID = ($TagIDTagLength & 0xfffc) >> 6;
         $TagLength = $TagIDTagLength & 0x3f;
         $CurrentOffset += 2;
         if ($TagLength == 0x3f) {
             $TagLength = Helper::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4));
             $CurrentOffset += 4;
         }
         unset($TagData);
         $TagData['offset'] = $CurrentOffset;
         $TagData['size'] = $TagLength;
         $TagData['id'] = $TagID;
         $TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength);
         switch ($TagID) {
             case 0:
                 // end of movie
                 break 2;
             case 9:
                 // Set background color
                 //$info['swf']['tags'][] = $TagData;
                 $info['swf']['bgcolor'] = strtoupper(str_pad(dechex(Helper::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT));
                 break;
             default:
                 if ($this->ReturnAllTagData) {
                     $info['swf']['tags'][] = $TagData;
                 }
                 break;
         }
         $CurrentOffset += $TagLength;
     }
     return true;
 }
コード例 #18
0
ファイル: Ac3.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     ///AH
     $info['ac3']['raw']['bsi'] = array();
     $thisfile_ac3 =& $info['ac3'];
     $thisfile_ac3_raw =& $thisfile_ac3['raw'];
     $thisfile_ac3_raw_bsi =& $thisfile_ac3_raw['bsi'];
     // http://www.atsc.org/standards/a_52a.pdf
     $info['fileformat'] = 'ac3';
     // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames
     // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256
     // new audio samples per channel. A synchronization information (SI) header at the beginning
     // of each frame contains information needed to acquire and maintain synchronization. A
     // bit stream information (BSI) header follows SI, and contains parameters describing the coded
     // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the
     // end of each frame is an error check field that includes a CRC word for error detection. An
     // additional CRC word is located in the SI header, the use of which, by a decoder, is optional.
     //
     // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC
     // syncinfo() {
     // 	 syncword    16
     // 	 crc1        16
     // 	 fscod        2
     // 	 frmsizecod   6
     // } /* end of syncinfo */
     $this->fseek($info['avdataoffset']);
     $this->AC3header['syncinfo'] = $this->fread(5);
     $magic = "\vw";
     if (strpos($this->AC3header['syncinfo'], $magic) === 0) {
         $thisfile_ac3_raw['synchinfo']['synchword'] = $magic;
         $offset = 2;
     } else {
         if (!$this->isDependencyFor('matroska')) {
             unset($info['fileformat'], $info['ac3']);
             return $this->error('Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)) . '"');
         }
         $offset = 0;
         $this->fseek(-2, SEEK_CUR);
     }
     $info['audio']['dataformat'] = 'ac3';
     $info['audio']['bitrate_mode'] = 'cbr';
     $info['audio']['lossless'] = false;
     $thisfile_ac3_raw['synchinfo']['crc1'] = Helper::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2));
     $ac3_synchinfo_fscod_frmsizecod = Helper::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset + 2, 1));
     $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xc0) >> 6;
     $thisfile_ac3_raw['synchinfo']['frmsizecod'] = $ac3_synchinfo_fscod_frmsizecod & 0x3f;
     $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
     if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
         $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
     }
     $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
     $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
     $info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
     $this->AC3header['bsi'] = Helper::BigEndian2Bin($this->fread(15));
     $ac3_bsi_offset = 0;
     $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5);
     if ($thisfile_ac3_raw_bsi['bsid'] > 8) {
         // Decoders which can decode version 8 will thus be able to decode version numbers less than 8.
         // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used.
         // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8.
         $this->error('Bit stream identification is version ' . $thisfile_ac3_raw_bsi['bsid'] . ', but GetId3Core() only understands up to version 8');
         unset($info['ac3']);
         return false;
     }
     $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
     $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
     $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
     $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
     foreach ($ac3_coding_mode as $key => $value) {
         $thisfile_ac3[$key] = $value;
     }
     switch ($thisfile_ac3_raw_bsi['acmod']) {
         case 0:
         case 1:
             $info['audio']['channelmode'] = 'mono';
             break;
         case 3:
         case 4:
             $info['audio']['channelmode'] = 'stereo';
             break;
         default:
             $info['audio']['channelmode'] = 'surround';
             break;
     }
     $info['audio']['channels'] = $thisfile_ac3['num_channels'];
     if ($thisfile_ac3_raw_bsi['acmod'] & 0x1) {
         // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
         $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
         $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
     }
     if ($thisfile_ac3_raw_bsi['acmod'] & 0x4) {
         // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
         $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
         $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
     }
     if ($thisfile_ac3_raw_bsi['acmod'] == 0x2) {
         // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
         $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
         $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
     }
     $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1);
     $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
     if ($thisfile_ac3_raw_bsi['lfeon']) {
         //$info['audio']['channels']++;
         $info['audio']['channels'] .= '.1';
     }
     $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']);
     // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1–31.
     // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
     $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
     $thisfile_ac3['dialogue_normalization'] = '-' . $thisfile_ac3_raw_bsi['dialnorm'] . 'dB';
     $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1);
     if ($thisfile_ac3_raw_bsi['compre_flag']) {
         $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
         $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
     }
     $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1);
     if ($thisfile_ac3_raw_bsi['langcode_flag']) {
         $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8);
     }
     $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1);
     if ($thisfile_ac3_raw_bsi['audprodie']) {
         $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
         $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);
         $thisfile_ac3['mixing_level'] = 80 + $thisfile_ac3_raw_bsi['mixlevel'] . 'dB';
         $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
     }
     if ($thisfile_ac3_raw_bsi['acmod'] == 0x0) {
         // If acmod is 0, then two completely independent program channels (dual mono)
         // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,
         // a number of additional items are present in BSI or audblk to fully describe Ch2.
         // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1–31.
         // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
         $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
         $thisfile_ac3['dialogue_normalization2'] = '-' . $thisfile_ac3_raw_bsi['dialnorm2'] . 'dB';
         $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1);
         if ($thisfile_ac3_raw_bsi['compre_flag2']) {
             $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
             $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
         }
         $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1);
         if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
             $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8);
         }
         $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1);
         if ($thisfile_ac3_raw_bsi['audprodie2']) {
             $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
             $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);
             $thisfile_ac3['mixing_level2'] = 80 + $thisfile_ac3_raw_bsi['mixlevel2'] . 'dB';
             $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
         }
     }
     $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1);
     $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1);
     $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1);
     if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
         $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14);
     }
     $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1);
     if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
         $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14);
     }
     $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1);
     if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
         $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6);
         $this->AC3header['bsi'] .= Helper::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
         $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
         $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
     }
     return true;
 }
コード例 #19
0
ファイル: Monkey.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // based loosely on code from TMonkey by Jurgen Faul <jfaulØgmx*de>
     // http://jfaul.de/atl  or  http://j-faul.virtualave.net/atl/atl.html
     $info['fileformat'] = 'mac';
     $info['audio']['dataformat'] = 'mac';
     $info['audio']['bitrate_mode'] = 'vbr';
     $info['audio']['lossless'] = true;
     $info['monkeys_audio']['raw'] = array();
     $thisfile_monkeysaudio =& $info['monkeys_audio'];
     $thisfile_monkeysaudio_raw =& $thisfile_monkeysaudio['raw'];
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $MACheaderData = fread($this->getid3->fp, 74);
     $thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4);
     $magic = 'MAC ';
     if ($thisfile_monkeysaudio_raw['magic'] != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($thisfile_monkeysaudio_raw['magic']) . '"';
         unset($info['fileformat']);
         return false;
     }
     $thisfile_monkeysaudio_raw['nVersion'] = Helper::LittleEndian2Int(substr($MACheaderData, 4, 2));
     // appears to be uint32 in 3.98+
     if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
         $thisfile_monkeysaudio_raw['nCompressionLevel'] = Helper::LittleEndian2Int(substr($MACheaderData, 6, 2));
         $thisfile_monkeysaudio_raw['nFormatFlags'] = Helper::LittleEndian2Int(substr($MACheaderData, 8, 2));
         $thisfile_monkeysaudio_raw['nChannels'] = Helper::LittleEndian2Int(substr($MACheaderData, 10, 2));
         $thisfile_monkeysaudio_raw['nSampleRate'] = Helper::LittleEndian2Int(substr($MACheaderData, 12, 4));
         $thisfile_monkeysaudio_raw['nHeaderDataBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, 16, 4));
         $thisfile_monkeysaudio_raw['nWAVTerminatingBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, 20, 4));
         $thisfile_monkeysaudio_raw['nTotalFrames'] = Helper::LittleEndian2Int(substr($MACheaderData, 24, 4));
         $thisfile_monkeysaudio_raw['nFinalFrameSamples'] = Helper::LittleEndian2Int(substr($MACheaderData, 28, 4));
         $thisfile_monkeysaudio_raw['nPeakLevel'] = Helper::LittleEndian2Int(substr($MACheaderData, 32, 4));
         $thisfile_monkeysaudio_raw['nSeekElements'] = Helper::LittleEndian2Int(substr($MACheaderData, 38, 2));
         $offset = 8;
     } else {
         $offset = 8;
         // APE_DESCRIPTOR
         $thisfile_monkeysaudio_raw['nDescriptorBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nHeaderBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nSeekTableBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nHeaderDataBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nAPEFrameDataBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nAPEFrameDataBytesHigh'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nTerminatingDataBytes'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['cFileMD5'] = substr($MACheaderData, $offset, 16);
         $offset += 16;
         // APE_HEADER
         $thisfile_monkeysaudio_raw['nCompressionLevel'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 2));
         $offset += 2;
         $thisfile_monkeysaudio_raw['nFormatFlags'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 2));
         $offset += 2;
         $thisfile_monkeysaudio_raw['nBlocksPerFrame'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nFinalFrameBlocks'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nTotalFrames'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
         $thisfile_monkeysaudio_raw['nBitsPerSample'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 2));
         $offset += 2;
         $thisfile_monkeysaudio_raw['nChannels'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 2));
         $offset += 2;
         $thisfile_monkeysaudio_raw['nSampleRate'] = Helper::LittleEndian2Int(substr($MACheaderData, $offset, 4));
         $offset += 4;
     }
     $thisfile_monkeysaudio['flags']['8-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x1);
     $thisfile_monkeysaudio['flags']['crc-32'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x2);
     $thisfile_monkeysaudio['flags']['peak_level'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x4);
     $thisfile_monkeysaudio['flags']['24-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x8);
     $thisfile_monkeysaudio['flags']['seek_elements'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x10);
     $thisfile_monkeysaudio['flags']['no_wav_header'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x20);
     $thisfile_monkeysaudio['version'] = $thisfile_monkeysaudio_raw['nVersion'] / 1000;
     $thisfile_monkeysaudio['compression'] = $this->MonkeyCompressionLevelNameLookup($thisfile_monkeysaudio_raw['nCompressionLevel']);
     if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
         $thisfile_monkeysaudio['samples_per_frame'] = $this->MonkeySamplesPerFrame($thisfile_monkeysaudio_raw['nVersion'], $thisfile_monkeysaudio_raw['nCompressionLevel']);
     }
     $thisfile_monkeysaudio['bits_per_sample'] = $thisfile_monkeysaudio['flags']['24-bit'] ? 24 : ($thisfile_monkeysaudio['flags']['8-bit'] ? 8 : 16);
     $thisfile_monkeysaudio['channels'] = $thisfile_monkeysaudio_raw['nChannels'];
     $info['audio']['channels'] = $thisfile_monkeysaudio['channels'];
     $thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate'];
     if ($thisfile_monkeysaudio['sample_rate'] == 0) {
         $info['error'][] = 'Corrupt MAC file: frequency == zero';
         return false;
     }
     $info['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate'];
     if ($thisfile_monkeysaudio['flags']['peak_level']) {
         $thisfile_monkeysaudio['peak_level'] = $thisfile_monkeysaudio_raw['nPeakLevel'];
         $thisfile_monkeysaudio['peak_ratio'] = $thisfile_monkeysaudio['peak_level'] / pow(2, $thisfile_monkeysaudio['bits_per_sample'] - 1);
     }
     if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
         $thisfile_monkeysaudio['samples'] = ($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio_raw['nBlocksPerFrame'] + $thisfile_monkeysaudio_raw['nFinalFrameBlocks'];
     } else {
         $thisfile_monkeysaudio['samples'] = ($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio['samples_per_frame'] + $thisfile_monkeysaudio_raw['nFinalFrameSamples'];
     }
     $thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate'];
     if ($thisfile_monkeysaudio['playtime'] == 0) {
         $info['error'][] = 'Corrupt MAC file: playtime == zero';
         return false;
     }
     $info['playtime_seconds'] = $thisfile_monkeysaudio['playtime'];
     $thisfile_monkeysaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset'];
     $thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8);
     if ($thisfile_monkeysaudio['uncompressed_size'] == 0) {
         $info['error'][] = 'Corrupt MAC file: uncompressed_size == zero';
         return false;
     }
     $thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']);
     $thisfile_monkeysaudio['bitrate'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * $thisfile_monkeysaudio['bits_per_sample'] / $thisfile_monkeysaudio['playtime'] * $thisfile_monkeysaudio['compression_ratio'];
     $info['audio']['bitrate'] = $thisfile_monkeysaudio['bitrate'];
     // add size of MAC header to avdataoffset
     if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
         $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nDescriptorBytes'];
         $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderBytes'];
         $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nSeekTableBytes'];
         $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderDataBytes'];
         $info['avdataend'] -= $thisfile_monkeysaudio_raw['nTerminatingDataBytes'];
     } else {
         $info['avdataoffset'] += $offset;
     }
     if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
         if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("", 16)) {
             //$info['warning'][] = 'cFileMD5 is null';
         } else {
             $info['md5_data_source'] = '';
             $md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
             for ($i = 0; $i < strlen($md5); ++$i) {
                 $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
             }
             if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
                 unset($info['md5_data_source']);
             }
         }
     }
     $info['audio']['bits_per_sample'] = $thisfile_monkeysaudio['bits_per_sample'];
     $info['audio']['encoder'] = 'MAC v' . number_format($thisfile_monkeysaudio['version'], 2);
     $info['audio']['encoder_options'] = ucfirst($thisfile_monkeysaudio['compression']) . ' compression';
     return true;
 }
コード例 #20
0
ファイル: Midi.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // shortcut
     $info['midi']['raw'] = array();
     $thisfile_midi =& $info['midi'];
     $thisfile_midi_raw =& $thisfile_midi['raw'];
     $info['fileformat'] = 'midi';
     $info['audio']['dataformat'] = 'midi';
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $MIDIdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
     $offset = 0;
     $MIDIheaderID = substr($MIDIdata, $offset, 4);
     // 'MThd'
     if ($MIDIheaderID != self::GETID3_MIDI_MAGIC_MTHD) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes(self::GETID3_MIDI_MAGIC_MTHD) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($MIDIheaderID) . '"';
         unset($info['fileformat']);
         return false;
     }
     $offset += 4;
     $thisfile_midi_raw['headersize'] = Helper::BigEndian2Int(substr($MIDIdata, $offset, 4));
     $offset += 4;
     $thisfile_midi_raw['fileformat'] = Helper::BigEndian2Int(substr($MIDIdata, $offset, 2));
     $offset += 2;
     $thisfile_midi_raw['tracks'] = Helper::BigEndian2Int(substr($MIDIdata, $offset, 2));
     $offset += 2;
     $thisfile_midi_raw['ticksperqnote'] = Helper::BigEndian2Int(substr($MIDIdata, $offset, 2));
     $offset += 2;
     for ($i = 0; $i < $thisfile_midi_raw['tracks']; ++$i) {
         while (strlen($MIDIdata) - $offset < 8) {
             $MIDIdata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size());
         }
         $trackID = substr($MIDIdata, $offset, 4);
         $offset += 4;
         if ($trackID == self::GETID3_MIDI_MAGIC_MTRK) {
             $tracksize = Helper::BigEndian2Int(substr($MIDIdata, $offset, 4));
             $offset += 4;
             // $thisfile_midi['tracks'][$i]['size'] = $tracksize;
             $trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);
             $offset += $tracksize;
         } else {
             $info['error'][] = 'Expecting "' . Helper::PrintHexBytes(self::GETID3_MIDI_MAGIC_MTRK) . '" at ' . ($offset - 4) . ', found "' . Helper::PrintHexBytes($trackID) . '" instead';
             return false;
         }
     }
     if (!isset($trackdataarray) || !is_array($trackdataarray)) {
         $info['error'][] = 'Cannot find MIDI track information';
         unset($thisfile_midi);
         unset($info['fileformat']);
         return false;
     }
     if ($this->scanwholefile) {
         // this can take quite a long time, so have the option to bypass it if speed is very important
         $thisfile_midi['totalticks'] = 0;
         $info['playtime_seconds'] = 0;
         $CurrentMicroSecondsPerBeat = 500000;
         // 120 beats per minute;  60,000,000 microseconds per minute -> 500,000 microseconds per beat
         $CurrentBeatsPerMinute = 120;
         // 120 beats per minute;  60,000,000 microseconds per minute -> 500,000 microseconds per beat
         $MicroSecondsPerQuarterNoteAfter = array();
         foreach ($trackdataarray as $tracknumber => $trackdata) {
             $eventsoffset = 0;
             $LastIssuedMIDIcommand = 0;
             $LastIssuedMIDIchannel = 0;
             $CumulativeDeltaTime = 0;
             $TicksAtCurrentBPM = 0;
             while ($eventsoffset < strlen($trackdata)) {
                 $eventid = 0;
                 if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) {
                     $eventid = count($MIDIevents[$tracknumber]);
                 }
                 $deltatime = 0;
                 for ($i = 0; $i < 4; ++$i) {
                     $deltatimebyte = ord(substr($trackdata, $eventsoffset++, 1));
                     $deltatime = ($deltatime << 7) + ($deltatimebyte & 0x7f);
                     if ($deltatimebyte & 0x80) {
                         // another byte follows
                     } else {
                         break;
                     }
                 }
                 $CumulativeDeltaTime += $deltatime;
                 $TicksAtCurrentBPM += $deltatime;
                 $MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime;
                 $MIDI_event_channel = ord(substr($trackdata, $eventsoffset++, 1));
                 if ($MIDI_event_channel & 0x80) {
                     // OK, normal event - MIDI command has MSB set
                     $LastIssuedMIDIcommand = $MIDI_event_channel >> 4;
                     $LastIssuedMIDIchannel = $MIDI_event_channel & 0xf;
                 } else {
                     // running event - assume last command
                     --$eventsoffset;
                 }
                 $MIDIevents[$tracknumber][$eventid]['eventid'] = $LastIssuedMIDIcommand;
                 $MIDIevents[$tracknumber][$eventid]['channel'] = $LastIssuedMIDIchannel;
                 if ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x8) {
                     // Note off (key is released)
                     $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
                     $velocity = ord(substr($trackdata, $eventsoffset++, 1));
                 } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x9) {
                     // Note on (key is pressed)
                     $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
                     $velocity = ord(substr($trackdata, $eventsoffset++, 1));
                 } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0xa) {
                     // Key after-touch
                     $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
                     $velocity = ord(substr($trackdata, $eventsoffset++, 1));
                 } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0xb) {
                     // Control Change
                     $controllernum = ord(substr($trackdata, $eventsoffset++, 1));
                     $newvalue = ord(substr($trackdata, $eventsoffset++, 1));
                 } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0xc) {
                     // Program (patch) change
                     $newprogramnum = ord(substr($trackdata, $eventsoffset++, 1));
                     $thisfile_midi_raw['track'][$tracknumber]['instrumentid'] = $newprogramnum;
                     if ($tracknumber == 10) {
                         $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIpercussionLookup($newprogramnum);
                     } else {
                         $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIinstrumentLookup($newprogramnum);
                     }
                 } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0xd) {
                     // Channel after-touch
                     $channelnumber = ord(substr($trackdata, $eventsoffset++, 1));
                 } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0xe) {
                     // Pitch wheel change (2000H is normal or no change)
                     $changeLSB = ord(substr($trackdata, $eventsoffset++, 1));
                     $changeMSB = ord(substr($trackdata, $eventsoffset++, 1));
                     $pitchwheelchange = ($changeMSB & 0x7f) << 7 & ($changeLSB & 0x7f);
                 } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0xf && $MIDIevents[$tracknumber][$eventid]['channel'] == 0xf) {
                     $METAeventCommand = ord(substr($trackdata, $eventsoffset++, 1));
                     $METAeventLength = ord(substr($trackdata, $eventsoffset++, 1));
                     $METAeventData = substr($trackdata, $eventsoffset, $METAeventLength);
                     $eventsoffset += $METAeventLength;
                     switch ($METAeventCommand) {
                         case 0x0:
                             // Set track sequence number
                             $track_sequence_number = Helper::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['seqno'] = $track_sequence_number;
                             break;
                         case 0x1:
                             // Text: generic
                             $text_generic = substr($METAeventData, 0, $METAeventLength);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['text'] = $text_generic;
                             $thisfile_midi['comments']['comment'][] = $text_generic;
                             break;
                         case 0x2:
                             // Text: copyright
                             $text_copyright = substr($METAeventData, 0, $METAeventLength);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['copyright'] = $text_copyright;
                             $thisfile_midi['comments']['copyright'][] = $text_copyright;
                             break;
                         case 0x3:
                             // Text: track name
                             $text_trackname = substr($METAeventData, 0, $METAeventLength);
                             $thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname;
                             break;
                         case 0x4:
                             // Text: track instrument name
                             $text_instrument = substr($METAeventData, 0, $METAeventLength);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['instrument'] = $text_instrument;
                             break;
                         case 0x5:
                             // Text: lyrics
                             $text_lyrics = substr($METAeventData, 0, $METAeventLength);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['lyrics'] = $text_lyrics;
                             if (!isset($thisfile_midi['lyrics'])) {
                                 $thisfile_midi['lyrics'] = '';
                             }
                             $thisfile_midi['lyrics'] .= $text_lyrics . "\n";
                             break;
                         case 0x6:
                             // Text: marker
                             $text_marker = substr($METAeventData, 0, $METAeventLength);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['marker'] = $text_marker;
                             break;
                         case 0x7:
                             // Text: cue point
                             $text_cuepoint = substr($METAeventData, 0, $METAeventLength);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['cuepoint'] = $text_cuepoint;
                             break;
                         case 0x2f:
                             // End Of Track
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['EOT'] = $CumulativeDeltaTime;
                             break;
                         case 0x51:
                             // Tempo: microseconds / quarter note
                             $CurrentMicroSecondsPerBeat = Helper::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
                             if ($CurrentMicroSecondsPerBeat == 0) {
                                 $info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
                                 return false;
                             }
                             $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
                             $CurrentBeatsPerMinute = 1000000 / $CurrentMicroSecondsPerBeat * 60;
                             $MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat;
                             $TicksAtCurrentBPM = 0;
                             break;
                         case 0x58:
                             // Time signature
                             $timesig_numerator = Helper::BigEndian2Int($METAeventData[0]);
                             $timesig_denominator = pow(2, Helper::BigEndian2Int($METAeventData[1]));
                             // $02 -> x/4, $03 -> x/8, etc
                             $timesig_32inqnote = Helper::BigEndian2Int($METAeventData[2]);
                             // number of 32nd notes to the quarter note
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote']   = $timesig_32inqnote;
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator']   = $timesig_numerator;
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator;
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_text']        = $timesig_numerator.'/'.$timesig_denominator;
                             $thisfile_midi['timesignature'][] = $timesig_numerator . '/' . $timesig_denominator;
                             break;
                         case 0x59:
                             // Keysignature
                             $keysig_sharpsflats = Helper::BigEndian2Int($METAeventData[0]);
                             if ($keysig_sharpsflats & 0x80) {
                                 // (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps)
                                 $keysig_sharpsflats -= 256;
                             }
                             $keysig_majorminor = Helper::BigEndian2Int($METAeventData[1]);
                             // 0 -> major, 1 -> minor
                             $keysigs = array(-7 => 'Cb', -6 => 'Gb', -5 => 'Db', -4 => 'Ab', -3 => 'Eb', -2 => 'Bb', -1 => 'F', 0 => 'C', 1 => 'G', 2 => 'D', 3 => 'A', 4 => 'E', 5 => 'B', 6 => 'F#', 7 => 'C#');
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats']  = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0);
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor']  = (bool) $keysig_majorminor;
                             //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_text']   = $keysigs[$keysig_sharpsflats].' '.($thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] ? 'minor' : 'major');
                             // $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect)
                             $thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats] . ' ' . ((bool) $keysig_majorminor ? 'minor' : 'major');
                             break;
                         case 0x7f:
                             // Sequencer specific information
                             $custom_data = substr($METAeventData, 0, $METAeventLength);
                             break;
                         default:
                             $info['warning'][] = 'Unhandled META Event Command: ' . $METAeventCommand;
                             break;
                     }
                 } else {
                     $info['warning'][] = 'Unhandled MIDI Event ID: ' . $MIDIevents[$tracknumber][$eventid]['eventid'] . ' + Channel ID: ' . $MIDIevents[$tracknumber][$eventid]['channel'];
                 }
             }
             if ($tracknumber > 0 || count($trackdataarray) == 1) {
                 $thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime);
             }
         }
         $previoustickoffset = null;
         ksort($MicroSecondsPerQuarterNoteAfter);
         foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
             if (is_null($previoustickoffset)) {
                 $prevmicrosecondsperbeat = $microsecondsperbeat;
                 $previoustickoffset = $tickoffset;
                 continue;
             }
             if ($thisfile_midi['totalticks'] > $tickoffset) {
                 if ($thisfile_midi_raw['ticksperqnote'] == 0) {
                     $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
                     return false;
                 }
                 $info['playtime_seconds'] += ($tickoffset - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote'] * ($prevmicrosecondsperbeat / 1000000);
                 $prevmicrosecondsperbeat = $microsecondsperbeat;
                 $previoustickoffset = $tickoffset;
             }
         }
         if ($thisfile_midi['totalticks'] > $previoustickoffset) {
             if ($thisfile_midi_raw['ticksperqnote'] == 0) {
                 $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
                 return false;
             }
             $info['playtime_seconds'] += ($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote'] * ($microsecondsperbeat / 1000000);
         }
     }
     if (!empty($info['playtime_seconds'])) {
         $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     }
     if (!empty($thisfile_midi['lyrics'])) {
         $thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics'];
     }
     return true;
 }
コード例 #21
0
ファイル: Vqf.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // based loosely on code from TTwinVQ by Jurgen Faul <jfaulØgmx*de>
     // http://jfaul.de/atl  or  http://j-faul.virtualave.net/atl/atl.html
     $info['fileformat'] = 'vqf';
     $info['audio']['dataformat'] = 'vqf';
     $info['audio']['bitrate_mode'] = 'cbr';
     $info['audio']['lossless'] = false;
     // shortcut
     $info['vqf']['raw'] = array();
     $thisfile_vqf =& $info['vqf'];
     $thisfile_vqf_raw =& $thisfile_vqf['raw'];
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $VQFheaderData = fread($this->getid3->fp, 16);
     $offset = 0;
     $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
     $magic = 'TWIN';
     if ($thisfile_vqf_raw['header_tag'] != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($thisfile_vqf_raw['header_tag']) . '"';
         unset($info['vqf']);
         unset($info['fileformat']);
         return false;
     }
     $offset += 4;
     $thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8);
     $offset += 8;
     $thisfile_vqf_raw['size'] = Helper::BigEndian2Int(substr($VQFheaderData, $offset, 4));
     $offset += 4;
     while (ftell($this->getid3->fp) < $info['avdataend']) {
         $ChunkBaseOffset = ftell($this->getid3->fp);
         $chunkoffset = 0;
         $ChunkData = fread($this->getid3->fp, 8);
         $ChunkName = substr($ChunkData, $chunkoffset, 4);
         if ($ChunkName == 'DATA') {
             $info['avdataoffset'] = $ChunkBaseOffset;
             break;
         }
         $chunkoffset += 4;
         $ChunkSize = Helper::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
         $chunkoffset += 4;
         if ($ChunkSize > $info['avdataend'] - ftell($this->getid3->fp)) {
             $info['error'][] = 'Invalid chunk size (' . $ChunkSize . ') for chunk "' . $ChunkName . '" at offset ' . $ChunkBaseOffset;
             break;
         }
         if ($ChunkSize > 0) {
             $ChunkData .= fread($this->getid3->fp, $ChunkSize);
         }
         switch ($ChunkName) {
             case 'COMM':
                 // shortcut
                 $thisfile_vqf['COMM'] = array();
                 $thisfile_vqf_COMM =& $thisfile_vqf['COMM'];
                 $thisfile_vqf_COMM['channel_mode'] = Helper::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
                 $chunkoffset += 4;
                 $thisfile_vqf_COMM['bitrate'] = Helper::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
                 $chunkoffset += 4;
                 $thisfile_vqf_COMM['sample_rate'] = Helper::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
                 $chunkoffset += 4;
                 $thisfile_vqf_COMM['security_level'] = Helper::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
                 $chunkoffset += 4;
                 $info['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1;
                 $info['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']);
                 $info['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000;
                 $info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate'] / 1000);
                 if ($info['audio']['bitrate'] == 0) {
                     $info['error'][] = 'Corrupt VQF file: bitrate_audio == zero';
                     return false;
                 }
                 break;
             case 'NAME':
             case 'AUTH':
             case '(c) ':
             case 'FILE':
             case 'COMT':
             case 'ALBM':
                 $thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8));
                 break;
             case 'DSIZ':
                 $thisfile_vqf['DSIZ'] = Helper::BigEndian2Int(substr($ChunkData, 8, 4));
                 break;
             default:
                 $info['warning'][] = 'Unhandled chunk type "' . $ChunkName . '" at offset ' . $ChunkBaseOffset;
                 break;
         }
     }
     $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
     if (isset($thisfile_vqf['DSIZ']) && $thisfile_vqf['DSIZ'] != $info['avdataend'] - $info['avdataoffset'] - strlen('DATA')) {
         switch ($thisfile_vqf['DSIZ']) {
             case 0:
             case 1:
                 $info['warning'][] = 'Invalid DSIZ value "' . $thisfile_vqf['DSIZ'] . '". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v' . ($thisfile_vqf['DSIZ'] + 1) . '.0';
                 $info['audio']['encoder'] = 'Ahead Nero';
                 break;
             default:
                 $info['warning'][] = 'Probable corrupted file - should be ' . $thisfile_vqf['DSIZ'] . ' bytes, actually ' . ($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'));
                 break;
         }
     }
     return true;
 }
コード例 #22
0
ファイル: Optimfrog.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function ParseOptimFROGheader45()
 {
     // for fileformat of v4.50a and higher
     $info =& $this->getid3->info;
     $RIFFdata = '';
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     while (!feof($this->getid3->fp) && ftell($this->getid3->fp) < $info['avdataend']) {
         $BlockOffset = ftell($this->getid3->fp);
         $BlockData = fread($this->getid3->fp, 8);
         $offset = 8;
         $BlockName = substr($BlockData, 0, 4);
         $BlockSize = Helper::LittleEndian2Int(substr($BlockData, 4, 4));
         if ($BlockName == 'OFRX') {
             $BlockName = 'OFR ';
         }
         if (!isset($info['ofr'][$BlockName])) {
             $info['ofr'][$BlockName] = array();
         }
         $thisfile_ofr_thisblock =& $info['ofr'][$BlockName];
         switch ($BlockName) {
             case 'OFR ':
                 // shortcut
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 $info['audio']['encoder'] = 'OptimFROG 4.50 alpha';
                 switch ($BlockSize) {
                     case 12:
                     case 15:
                         // good
                         break;
                     default:
                         $info['warning'][] = '"' . $BlockName . '" contains more data than expected (expected 12 or 15 bytes, found ' . $BlockSize . ' bytes)';
                         break;
                 }
                 $BlockData .= fread($this->getid3->fp, $BlockSize);
                 $thisfile_ofr_thisblock['total_samples'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 6));
                 $offset += 6;
                 $thisfile_ofr_thisblock['raw']['sample_type'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 1));
                 $thisfile_ofr_thisblock['sample_type'] = $this->OptimFROGsampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']);
                 $offset += 1;
                 $thisfile_ofr_thisblock['channel_config'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 1));
                 $thisfile_ofr_thisblock['channels'] = $thisfile_ofr_thisblock['channel_config'];
                 $offset += 1;
                 $thisfile_ofr_thisblock['sample_rate'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 4));
                 $offset += 4;
                 if ($BlockSize > 12) {
                     // OFR 4.504b or higher
                     $thisfile_ofr_thisblock['channels'] = $this->OptimFROGchannelConfigNumChannelsLookup($thisfile_ofr_thisblock['channel_config']);
                     $thisfile_ofr_thisblock['raw']['encoder_id'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 2));
                     $thisfile_ofr_thisblock['encoder'] = $this->OptimFROGencoderNameLookup($thisfile_ofr_thisblock['raw']['encoder_id']);
                     $offset += 2;
                     $thisfile_ofr_thisblock['raw']['compression'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 1));
                     $thisfile_ofr_thisblock['compression'] = $this->OptimFROGcompressionLookup($thisfile_ofr_thisblock['raw']['compression']);
                     $thisfile_ofr_thisblock['speedup'] = $this->OptimFROGspeedupLookup($thisfile_ofr_thisblock['raw']['compression']);
                     $offset += 1;
                     $info['audio']['encoder'] = 'OptimFROG ' . $thisfile_ofr_thisblock['encoder'];
                     $info['audio']['encoder_options'] = '--mode ' . $thisfile_ofr_thisblock['compression'];
                     if (($thisfile_ofr_thisblock['raw']['encoder_id'] & 0xf0) >> 4 == 7) {
                         // v4.507
                         if (strtolower(Helper::fileextension($info['filename'])) == 'ofs') {
                             // OptimFROG DualStream format is lossy, but as of v4.507 there is no way to tell the difference
                             // between lossless and lossy other than the file extension.
                             $info['audio']['dataformat'] = 'ofs';
                             $info['audio']['lossless'] = true;
                         }
                     }
                 }
                 $info['audio']['channels'] = $thisfile_ofr_thisblock['channels'];
                 $info['audio']['sample_rate'] = $thisfile_ofr_thisblock['sample_rate'];
                 $info['audio']['bits_per_sample'] = $this->OptimFROGbitsPerSampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']);
                 break;
             case 'COMP':
                 // unlike other block types, there CAN be multiple COMP blocks
                 $COMPdata['offset'] = $BlockOffset;
                 $COMPdata['size'] = $BlockSize;
                 if ($info['avdataoffset'] == 0) {
                     $info['avdataoffset'] = $BlockOffset;
                 }
                 // Only interested in first 14 bytes (only first 12 needed for v4.50 alpha), not actual audio data
                 $BlockData .= fread($this->getid3->fp, 14);
                 fseek($this->getid3->fp, $BlockSize - 14, SEEK_CUR);
                 $COMPdata['crc_32'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 4));
                 $offset += 4;
                 $COMPdata['sample_count'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 4));
                 $offset += 4;
                 $COMPdata['raw']['sample_type'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 1));
                 $COMPdata['sample_type'] = $this->OptimFROGsampleTypeLookup($COMPdata['raw']['sample_type']);
                 $offset += 1;
                 $COMPdata['raw']['channel_configuration'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 1));
                 $COMPdata['channel_configuration'] = $this->OptimFROGchannelConfigurationLookup($COMPdata['raw']['channel_configuration']);
                 $offset += 1;
                 $COMPdata['raw']['algorithm_id'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 2));
                 //$COMPdata['algorithm']                    = OptimFROGalgorithmNameLookup($COMPdata['raw']['algorithm_id']);
                 $offset += 2;
                 if ($info['ofr']['OFR ']['size'] > 12) {
                     // OFR 4.504b or higher
                     $COMPdata['raw']['encoder_id'] = Helper::LittleEndian2Int(substr($BlockData, $offset, 2));
                     $COMPdata['encoder'] = $this->OptimFROGencoderNameLookup($COMPdata['raw']['encoder_id']);
                     $offset += 2;
                 }
                 if ($COMPdata['crc_32'] == 0x454e4f4e) {
                     // ASCII value of 'NONE' - placeholder value in v4.50a
                     $COMPdata['crc_32'] = false;
                 }
                 $thisfile_ofr_thisblock[] = $COMPdata;
                 break;
             case 'HEAD':
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 $RIFFdata .= fread($this->getid3->fp, $BlockSize);
                 break;
             case 'TAIL':
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 if ($BlockSize > 0) {
                     $RIFFdata .= fread($this->getid3->fp, $BlockSize);
                 }
                 break;
             case 'RECV':
                 // block contains no useful meta data - simply note and skip
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
                 break;
             case 'APET':
                 // APEtag v2
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 $info['warning'][] = 'APEtag processing inside OptimFROG not supported in this version (' . $this->getid3->version() . ') of GetId3Core()';
                 fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
                 break;
             case 'MD5 ':
                 // APEtag v2
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 if ($BlockSize == 16) {
                     $thisfile_ofr_thisblock['md5_binary'] = fread($this->getid3->fp, $BlockSize);
                     $thisfile_ofr_thisblock['md5_string'] = Helper::PrintHexBytes($thisfile_ofr_thisblock['md5_binary'], true, false, false);
                     $info['md5_data_source'] = $thisfile_ofr_thisblock['md5_string'];
                 } else {
                     $info['warning'][] = 'Expecting block size of 16 in "MD5 " chunk, found ' . $BlockSize . ' instead';
                     fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
                 }
                 break;
             default:
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 $info['warning'][] = 'Unhandled OptimFROG block type "' . $BlockName . '" at offset ' . $thisfile_ofr_thisblock['offset'];
                 fseek($this->getid3->fp, $BlockSize, SEEK_CUR);
                 break;
         }
     }
     if (isset($info['ofr']['TAIL']['offset'])) {
         $info['avdataend'] = $info['ofr']['TAIL']['offset'];
     }
     $info['playtime_seconds'] = (double) $info['ofr']['OFR ']['total_samples'] / ($info['audio']['channels'] * $info['audio']['sample_rate']);
     $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     // move the data chunk after all other chunks (if any)
     // so that the RIFF parser doesn't see EOF when trying
     // to skip over the data chunk
     $RIFFdata = substr($RIFFdata, 0, 36) . substr($RIFFdata, 44) . substr($RIFFdata, 36, 8);
     $getid3_temp = new GetId3Core();
     $getid3_temp->openfile($this->getid3->filename);
     $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
     $getid3_temp->info['avdataend'] = $info['avdataend'];
     $getid3_riff = new Riff($getid3_temp);
     $getid3_riff->ParseRIFFdata($RIFFdata);
     $info['riff'] = $getid3_temp->info['riff'];
     unset($getid3_riff, $getid3_temp, $RIFFdata);
     return true;
 }
コード例 #23
0
ファイル: Png.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // shortcut
     $info['png'] = array();
     $thisfile_png =& $info['png'];
     $info['fileformat'] = 'png';
     $info['video']['dataformat'] = 'png';
     $info['video']['lossless'] = false;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $PNGfiledata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
     $offset = 0;
     $PNGidentifier = substr($PNGfiledata, $offset, 8);
     // $89 $50 $4E $47 $0D $0A $1A $0A
     $offset += 8;
     if ($PNGidentifier != "‰PNG\r\n\n") {
         $info['error'][] = 'First 8 bytes of file (' . Helper::PrintHexBytes($PNGidentifier) . ') did not match expected PNG identifier';
         unset($info['fileformat']);
         return false;
     }
     while (ftell($this->getid3->fp) - (strlen($PNGfiledata) - $offset) < $info['filesize']) {
         $chunk['data_length'] = Helper::BigEndian2Int(substr($PNGfiledata, $offset, 4));
         $offset += 4;
         while (strlen($PNGfiledata) - $offset < $chunk['data_length'] + 4 && ftell($this->getid3->fp) < $info['filesize']) {
             $PNGfiledata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size());
         }
         $chunk['type_text'] = substr($PNGfiledata, $offset, 4);
         $offset += 4;
         $chunk['type_raw'] = Helper::BigEndian2Int($chunk['type_text']);
         $chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']);
         $offset += $chunk['data_length'];
         $chunk['crc'] = Helper::BigEndian2Int(substr($PNGfiledata, $offset, 4));
         $offset += 4;
         $chunk['flags']['ancilliary'] = (bool) ($chunk['type_raw'] & 0x20000000);
         $chunk['flags']['private'] = (bool) ($chunk['type_raw'] & 0x200000);
         $chunk['flags']['reserved'] = (bool) ($chunk['type_raw'] & 0x2000);
         $chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x20);
         // shortcut
         $thisfile_png[$chunk['type_text']] = array();
         $thisfile_png_chunk_type_text =& $thisfile_png[$chunk['type_text']];
         switch ($chunk['type_text']) {
             case 'IHDR':
                 // Image Header
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['width'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 4));
                 $thisfile_png_chunk_type_text['height'] = Helper::BigEndian2Int(substr($chunk['data'], 4, 4));
                 $thisfile_png_chunk_type_text['raw']['bit_depth'] = Helper::BigEndian2Int(substr($chunk['data'], 8, 1));
                 $thisfile_png_chunk_type_text['raw']['color_type'] = Helper::BigEndian2Int(substr($chunk['data'], 9, 1));
                 $thisfile_png_chunk_type_text['raw']['compression_method'] = Helper::BigEndian2Int(substr($chunk['data'], 10, 1));
                 $thisfile_png_chunk_type_text['raw']['filter_method'] = Helper::BigEndian2Int(substr($chunk['data'], 11, 1));
                 $thisfile_png_chunk_type_text['raw']['interlace_method'] = Helper::BigEndian2Int(substr($chunk['data'], 12, 1));
                 $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']);
                 $thisfile_png_chunk_type_text['color_type']['palette'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x1);
                 $thisfile_png_chunk_type_text['color_type']['true_color'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x2);
                 $thisfile_png_chunk_type_text['color_type']['alpha'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x4);
                 $info['video']['resolution_x'] = $thisfile_png_chunk_type_text['width'];
                 $info['video']['resolution_y'] = $thisfile_png_chunk_type_text['height'];
                 $info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']);
                 break;
             case 'PLTE':
                 // Palette
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $paletteoffset = 0;
                 for ($i = 0; $i <= 255; ++$i) {
                     //$thisfile_png_chunk_type_text['red'][$i]   = GetId3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                     //$thisfile_png_chunk_type_text['green'][$i] = GetId3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                     //$thisfile_png_chunk_type_text['blue'][$i]  = GetId3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                     $red = Helper::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                     $green = Helper::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                     $blue = Helper::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                     $thisfile_png_chunk_type_text[$i] = $red << 16 | $green << 8 | $blue;
                 }
                 break;
             case 'tRNS':
                 // Transparency
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 switch ($thisfile_png['IHDR']['raw']['color_type']) {
                     case 0:
                         $thisfile_png_chunk_type_text['transparent_color_gray'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 2));
                         break;
                     case 2:
                         $thisfile_png_chunk_type_text['transparent_color_red'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 2));
                         $thisfile_png_chunk_type_text['transparent_color_green'] = Helper::BigEndian2Int(substr($chunk['data'], 2, 2));
                         $thisfile_png_chunk_type_text['transparent_color_blue'] = Helper::BigEndian2Int(substr($chunk['data'], 4, 2));
                         break;
                     case 3:
                         for ($i = 0; $i < strlen($chunk['data']); ++$i) {
                             $thisfile_png_chunk_type_text['palette_opacity'][$i] = Helper::BigEndian2Int(substr($chunk['data'], $i, 1));
                         }
                         break;
                     case 4:
                     case 6:
                         $info['error'][] = 'Invalid color_type in tRNS chunk: ' . $thisfile_png['IHDR']['raw']['color_type'];
                     default:
                         $info['warning'][] = 'Unhandled color_type in tRNS chunk: ' . $thisfile_png['IHDR']['raw']['color_type'];
                         break;
                 }
                 break;
             case 'gAMA':
                 // Image Gamma
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['gamma'] = Helper::BigEndian2Int($chunk['data']) / 100000;
                 break;
             case 'cHRM':
                 // Primary Chromaticities
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['white_x'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 4)) / 100000;
                 $thisfile_png_chunk_type_text['white_y'] = Helper::BigEndian2Int(substr($chunk['data'], 4, 4)) / 100000;
                 $thisfile_png_chunk_type_text['red_y'] = Helper::BigEndian2Int(substr($chunk['data'], 8, 4)) / 100000;
                 $thisfile_png_chunk_type_text['red_y'] = Helper::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000;
                 $thisfile_png_chunk_type_text['green_y'] = Helper::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000;
                 $thisfile_png_chunk_type_text['green_y'] = Helper::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000;
                 $thisfile_png_chunk_type_text['blue_y'] = Helper::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000;
                 $thisfile_png_chunk_type_text['blue_y'] = Helper::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000;
                 break;
             case 'sRGB':
                 // Standard RGB Color Space
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['reindering_intent'] = Helper::BigEndian2Int($chunk['data']);
                 $thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']);
                 break;
             case 'iCCP':
                 // Embedded ICC Profile
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 list($profilename, $compressiondata) = explode("", $chunk['data'], 2);
                 $thisfile_png_chunk_type_text['profile_name'] = $profilename;
                 $thisfile_png_chunk_type_text['compression_method'] = Helper::BigEndian2Int(substr($compressiondata, 0, 1));
                 $thisfile_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1);
                 $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
                 break;
             case 'tEXt':
                 // Textual Data
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 list($keyword, $text) = explode("", $chunk['data'], 2);
                 $thisfile_png_chunk_type_text['keyword'] = $keyword;
                 $thisfile_png_chunk_type_text['text'] = $text;
                 $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
                 break;
             case 'zTXt':
                 // Compressed Textual Data
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 list($keyword, $otherdata) = explode("", $chunk['data'], 2);
                 $thisfile_png_chunk_type_text['keyword'] = $keyword;
                 $thisfile_png_chunk_type_text['compression_method'] = Helper::BigEndian2Int(substr($otherdata, 0, 1));
                 $thisfile_png_chunk_type_text['compressed_text'] = substr($otherdata, 1);
                 $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
                 switch ($thisfile_png_chunk_type_text['compression_method']) {
                     case 0:
                         $thisfile_png_chunk_type_text['text'] = gzuncompress($thisfile_png_chunk_type_text['compressed_text']);
                         break;
                     default:
                         // unknown compression method
                         break;
                 }
                 if (isset($thisfile_png_chunk_type_text['text'])) {
                     $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
                 }
                 break;
             case 'iTXt':
                 // International Textual Data
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 list($keyword, $otherdata) = explode("", $chunk['data'], 2);
                 $thisfile_png_chunk_type_text['keyword'] = $keyword;
                 $thisfile_png_chunk_type_text['compression'] = (bool) Helper::BigEndian2Int(substr($otherdata, 0, 1));
                 $thisfile_png_chunk_type_text['compression_method'] = Helper::BigEndian2Int(substr($otherdata, 1, 1));
                 $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
                 list($languagetag, $translatedkeyword, $text) = explode("", substr($otherdata, 2), 3);
                 $thisfile_png_chunk_type_text['language_tag'] = $languagetag;
                 $thisfile_png_chunk_type_text['translated_keyword'] = $translatedkeyword;
                 if ($thisfile_png_chunk_type_text['compression']) {
                     switch ($thisfile_png_chunk_type_text['compression_method']) {
                         case 0:
                             $thisfile_png_chunk_type_text['text'] = gzuncompress($text);
                             break;
                         default:
                             // unknown compression method
                             break;
                     }
                 } else {
                     $thisfile_png_chunk_type_text['text'] = $text;
                 }
                 if (isset($thisfile_png_chunk_type_text['text'])) {
                     $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
                 }
                 break;
             case 'bKGD':
                 // Background Color
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 switch ($thisfile_png['IHDR']['raw']['color_type']) {
                     case 0:
                     case 4:
                         $thisfile_png_chunk_type_text['background_gray'] = Helper::BigEndian2Int($chunk['data']);
                         break;
                     case 2:
                     case 6:
                         $thisfile_png_chunk_type_text['background_red'] = Helper::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
                         $thisfile_png_chunk_type_text['background_green'] = Helper::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
                         $thisfile_png_chunk_type_text['background_blue'] = Helper::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
                         break;
                     case 3:
                         $thisfile_png_chunk_type_text['background_index'] = Helper::BigEndian2Int($chunk['data']);
                         break;
                     default:
                         break;
                 }
                 break;
             case 'pHYs':
                 // Physical Pixel Dimensions
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['pixels_per_unit_x'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 4));
                 $thisfile_png_chunk_type_text['pixels_per_unit_y'] = Helper::BigEndian2Int(substr($chunk['data'], 4, 4));
                 $thisfile_png_chunk_type_text['unit_specifier'] = Helper::BigEndian2Int(substr($chunk['data'], 8, 1));
                 $thisfile_png_chunk_type_text['unit'] = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
                 break;
             case 'sBIT':
                 // Significant Bits
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 switch ($thisfile_png['IHDR']['raw']['color_type']) {
                     case 0:
                         $thisfile_png_chunk_type_text['significant_bits_gray'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 1));
                         break;
                     case 2:
                     case 3:
                         $thisfile_png_chunk_type_text['significant_bits_red'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 1));
                         $thisfile_png_chunk_type_text['significant_bits_green'] = Helper::BigEndian2Int(substr($chunk['data'], 1, 1));
                         $thisfile_png_chunk_type_text['significant_bits_blue'] = Helper::BigEndian2Int(substr($chunk['data'], 2, 1));
                         break;
                     case 4:
                         $thisfile_png_chunk_type_text['significant_bits_gray'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 1));
                         $thisfile_png_chunk_type_text['significant_bits_alpha'] = Helper::BigEndian2Int(substr($chunk['data'], 1, 1));
                         break;
                     case 6:
                         $thisfile_png_chunk_type_text['significant_bits_red'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 1));
                         $thisfile_png_chunk_type_text['significant_bits_green'] = Helper::BigEndian2Int(substr($chunk['data'], 1, 1));
                         $thisfile_png_chunk_type_text['significant_bits_blue'] = Helper::BigEndian2Int(substr($chunk['data'], 2, 1));
                         $thisfile_png_chunk_type_text['significant_bits_alpha'] = Helper::BigEndian2Int(substr($chunk['data'], 3, 1));
                         break;
                     default:
                         break;
                 }
                 break;
             case 'sPLT':
                 // Suggested Palette
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 list($palettename, $otherdata) = explode("", $chunk['data'], 2);
                 $thisfile_png_chunk_type_text['palette_name'] = $palettename;
                 $sPLToffset = 0;
                 $thisfile_png_chunk_type_text['sample_depth_bits'] = Helper::BigEndian2Int(substr($otherdata, $sPLToffset, 1));
                 $sPLToffset += 1;
                 $thisfile_png_chunk_type_text['sample_depth_bytes'] = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8;
                 $paletteCounter = 0;
                 while ($sPLToffset < strlen($otherdata)) {
                     $thisfile_png_chunk_type_text['red'][$paletteCounter] = Helper::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
                     $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                     $thisfile_png_chunk_type_text['green'][$paletteCounter] = Helper::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
                     $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                     $thisfile_png_chunk_type_text['blue'][$paletteCounter] = Helper::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
                     $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                     $thisfile_png_chunk_type_text['alpha'][$paletteCounter] = Helper::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
                     $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                     $thisfile_png_chunk_type_text['frequency'][$paletteCounter] = Helper::BigEndian2Int(substr($otherdata, $sPLToffset, 2));
                     $sPLToffset += 2;
                     ++$paletteCounter;
                 }
                 break;
             case 'hIST':
                 // Palette Histogram
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $hISTcounter = 0;
                 while ($hISTcounter < strlen($chunk['data'])) {
                     $thisfile_png_chunk_type_text[$hISTcounter] = Helper::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2));
                     $hISTcounter += 2;
                 }
                 break;
             case 'tIME':
                 // Image Last-Modification Time
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['year'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 2));
                 $thisfile_png_chunk_type_text['month'] = Helper::BigEndian2Int(substr($chunk['data'], 2, 1));
                 $thisfile_png_chunk_type_text['day'] = Helper::BigEndian2Int(substr($chunk['data'], 3, 1));
                 $thisfile_png_chunk_type_text['hour'] = Helper::BigEndian2Int(substr($chunk['data'], 4, 1));
                 $thisfile_png_chunk_type_text['minute'] = Helper::BigEndian2Int(substr($chunk['data'], 5, 1));
                 $thisfile_png_chunk_type_text['second'] = Helper::BigEndian2Int(substr($chunk['data'], 6, 1));
                 $thisfile_png_chunk_type_text['unix'] = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']);
                 break;
             case 'oFFs':
                 // Image Offset
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['position_x'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 4), false, true);
                 $thisfile_png_chunk_type_text['position_y'] = Helper::BigEndian2Int(substr($chunk['data'], 4, 4), false, true);
                 $thisfile_png_chunk_type_text['unit_specifier'] = Helper::BigEndian2Int(substr($chunk['data'], 8, 1));
                 $thisfile_png_chunk_type_text['unit'] = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
                 break;
             case 'pCAL':
                 // Calibration Of Pixel Values
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 list($calibrationname, $otherdata) = explode("", $chunk['data'], 2);
                 $thisfile_png_chunk_type_text['calibration_name'] = $calibrationname;
                 $pCALoffset = 0;
                 $thisfile_png_chunk_type_text['original_zero'] = Helper::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
                 $pCALoffset += 4;
                 $thisfile_png_chunk_type_text['original_max'] = Helper::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
                 $pCALoffset += 4;
                 $thisfile_png_chunk_type_text['equation_type'] = Helper::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
                 $pCALoffset += 1;
                 $thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']);
                 $thisfile_png_chunk_type_text['parameter_count'] = Helper::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
                 $pCALoffset += 1;
                 $thisfile_png_chunk_type_text['parameters'] = explode("", substr($chunk['data'], $pCALoffset));
                 break;
             case 'sCAL':
                 // Physical Scale Of Image Subject
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $thisfile_png_chunk_type_text['unit_specifier'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 1));
                 $thisfile_png_chunk_type_text['unit'] = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
                 list($pixelwidth, $pixelheight) = explode("", substr($chunk['data'], 1));
                 $thisfile_png_chunk_type_text['pixel_width'] = $pixelwidth;
                 $thisfile_png_chunk_type_text['pixel_height'] = $pixelheight;
                 break;
             case 'gIFg':
                 // GIF Graphic Control Extension
                 $gIFgCounter = 0;
                 if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
                     $gIFgCounter = count($thisfile_png_chunk_type_text);
                 }
                 $thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk;
                 $thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = Helper::BigEndian2Int(substr($chunk['data'], 0, 1));
                 $thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = Helper::BigEndian2Int(substr($chunk['data'], 1, 1));
                 $thisfile_png_chunk_type_text[$gIFgCounter]['delay_time'] = Helper::BigEndian2Int(substr($chunk['data'], 2, 2));
                 break;
             case 'gIFx':
                 // GIF Application Extension
                 $gIFxCounter = 0;
                 if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
                     $gIFxCounter = count($thisfile_png_chunk_type_text);
                 }
                 $thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk;
                 $thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8);
                 $thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3);
                 $thisfile_png_chunk_type_text[$gIFxCounter]['application_data'] = substr($chunk['data'], 11);
                 break;
             case 'IDAT':
                 // Image Data
                 $idatinformationfieldindex = 0;
                 if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) {
                     $idatinformationfieldindex = count($thisfile_png['IDAT']);
                 }
                 unset($chunk['data']);
                 $thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk;
                 break;
             case 'IEND':
                 // Image Trailer
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 break;
             default:
                 //unset($chunk['data']);
                 $thisfile_png_chunk_type_text['header'] = $chunk;
                 $info['warning'][] = 'Unhandled chunk type: ' . $chunk['type_text'];
                 break;
         }
     }
     return true;
 }
コード例 #24
0
ファイル: Tta.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     $info['fileformat'] = 'tta';
     $info['audio']['dataformat'] = 'tta';
     $info['audio']['lossless'] = true;
     $info['audio']['bitrate_mode'] = 'vbr';
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $ttaheader = fread($this->getid3->fp, 26);
     $info['tta']['magic'] = substr($ttaheader, 0, 3);
     $magic = 'TTA';
     if ($info['tta']['magic'] != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($info['tta']['magic']) . '"';
         unset($info['fileformat']);
         unset($info['audio']);
         unset($info['tta']);
         return false;
     }
     switch ($ttaheader[3]) {
         case "":
             // TTA v1.x
         // TTA v1.x
         case "":
             // TTA v1.x
         // TTA v1.x
         case "":
             // TTA v1.x
             // "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year."
             $info['tta']['major_version'] = 1;
             $info['avdataoffset'] += 16;
             $info['tta']['compression_level'] = ord($ttaheader[3]);
             $info['tta']['channels'] = Helper::LittleEndian2Int(substr($ttaheader, 4, 2));
             $info['tta']['bits_per_sample'] = Helper::LittleEndian2Int(substr($ttaheader, 6, 2));
             $info['tta']['sample_rate'] = Helper::LittleEndian2Int(substr($ttaheader, 8, 4));
             $info['tta']['samples_per_channel'] = Helper::LittleEndian2Int(substr($ttaheader, 12, 4));
             $info['audio']['encoder_options'] = '-e' . $info['tta']['compression_level'];
             $info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['tta']['sample_rate'];
             break;
         case '2':
             // TTA v2.x
             // "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4."
             $info['tta']['major_version'] = 2;
             $info['avdataoffset'] += 20;
             $info['tta']['compression_level'] = Helper::LittleEndian2Int(substr($ttaheader, 4, 2));
             $info['tta']['audio_format'] = Helper::LittleEndian2Int(substr($ttaheader, 6, 2));
             $info['tta']['channels'] = Helper::LittleEndian2Int(substr($ttaheader, 8, 2));
             $info['tta']['bits_per_sample'] = Helper::LittleEndian2Int(substr($ttaheader, 10, 2));
             $info['tta']['sample_rate'] = Helper::LittleEndian2Int(substr($ttaheader, 12, 4));
             $info['tta']['data_length'] = Helper::LittleEndian2Int(substr($ttaheader, 16, 4));
             $info['audio']['encoder_options'] = '-e' . $info['tta']['compression_level'];
             $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate'];
             break;
         case '1':
             // TTA v3.x
             // "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher."
             $info['tta']['major_version'] = 3;
             $info['avdataoffset'] += 26;
             $info['tta']['audio_format'] = Helper::LittleEndian2Int(substr($ttaheader, 4, 2));
             // GetId3_riff::RIFFwFormatTagLookup()
             $info['tta']['channels'] = Helper::LittleEndian2Int(substr($ttaheader, 6, 2));
             $info['tta']['bits_per_sample'] = Helper::LittleEndian2Int(substr($ttaheader, 8, 2));
             $info['tta']['sample_rate'] = Helper::LittleEndian2Int(substr($ttaheader, 10, 4));
             $info['tta']['data_length'] = Helper::LittleEndian2Int(substr($ttaheader, 14, 4));
             $info['tta']['crc32_footer'] = substr($ttaheader, 18, 4);
             $info['tta']['seek_point'] = Helper::LittleEndian2Int(substr($ttaheader, 22, 4));
             $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate'];
             break;
         default:
             $info['error'][] = 'This version of GetId3Core() [' . $this->getid3->version() . '] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v' . $ttaheader[3];
             return false;
             break;
     }
     $info['audio']['encoder'] = 'TTA v' . $info['tta']['major_version'];
     $info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample'];
     $info['audio']['sample_rate'] = $info['tta']['sample_rate'];
     $info['audio']['channels'] = $info['tta']['channels'];
     $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     return true;
 }
コード例 #25
0
ファイル: Quicktime.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @param  type    $atomname
  * @param  type    $atomsize
  * @param  type    $atom_data
  * @param  type    $baseoffset
  * @param  type    $atomHierarchy
  * @param  type    $ParseAllPossibleAtoms
  *
  * @return bool
  *
  * @link http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
  */
 public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms)
 {
     $info =& $this->getid3->info;
     $atom_parent = array_pop($atomHierarchy);
     array_push($atomHierarchy, $atomname);
     $atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
     $atom_structure['name'] = $atomname;
     $atom_structure['size'] = $atomsize;
     $atom_structure['offset'] = $baseoffset;
     //echo GetId3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'<br>';
     //echo GetId3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'<br><br>';
     switch ($atomname) {
         case 'moov':
             // MOVie container atom
         // MOVie container atom
         case 'trak':
             // TRAcK container atom
         // TRAcK container atom
         case 'clip':
             // CLIPping container atom
         // CLIPping container atom
         case 'matt':
             // track MATTe container atom
         // track MATTe container atom
         case 'edts':
             // EDiTS container atom
         // EDiTS container atom
         case 'tref':
             // Track REFerence container atom
         // Track REFerence container atom
         case 'mdia':
             // MeDIA container atom
         // MeDIA container atom
         case 'minf':
             // Media INFormation container atom
         // Media INFormation container atom
         case 'dinf':
             // Data INFormation container atom
         // Data INFormation container atom
         case 'udta':
             // User DaTA container atom
         // User DaTA container atom
         case 'cmov':
             // Compressed MOVie container atom
         // Compressed MOVie container atom
         case 'rmra':
             // Reference Movie Record Atom
         // Reference Movie Record Atom
         case 'rmda':
             // Reference Movie Descriptor Atom
         // Reference Movie Descriptor Atom
         case 'gmhd':
             // Generic Media info HeaDer atom (seen on QTVR)
             $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
             break;
         case 'ilst':
             // Item LiST container atom
             $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
             // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
             $allnumericnames = true;
             foreach ($atom_structure['subatoms'] as $subatomarray) {
                 if (!is_int($subatomarray['name']) || count($subatomarray['subatoms']) != 1) {
                     $allnumericnames = false;
                     break;
                 }
             }
             if ($allnumericnames) {
                 $newData = array();
                 foreach ($atom_structure['subatoms'] as $subatomarray) {
                     foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
                         unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
                         $newData[$subatomarray['name']] = $newData_subatomarray;
                         break;
                     }
                 }
                 $atom_structure['data'] = $newData;
                 unset($atom_structure['subatoms']);
             }
             break;
         case "":
         case "":
         case "":
         case "":
         case "":
             $atomname = Helper::BigEndian2Int($atomname);
             $atom_structure['name'] = $atomname;
             $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
             break;
         case 'stbl':
             // Sample TaBLe container atom
             $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
             $isVideo = false;
             $framerate = 0;
             $framecount = 0;
             foreach ($atom_structure['subatoms'] as $key => $value_array) {
                 if (isset($value_array['sample_description_table'])) {
                     foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
                         if (isset($value_array2['data_format'])) {
                             switch ($value_array2['data_format']) {
                                 case 'avc1':
                                 case 'mp4v':
                                     // video data
                                     $isVideo = true;
                                     break;
                                 case 'mp4a':
                                     // audio data
                                     break;
                             }
                         }
                     }
                 } elseif (isset($value_array['time_to_sample_table'])) {
                     foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
                         if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && $value_array2['sample_duration'] > 0) {
                             $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
                             $framecount = $value_array2['sample_count'];
                         }
                     }
                 }
             }
             if ($isVideo && $framerate) {
                 $info['quicktime']['video']['frame_rate'] = $framerate;
                 $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
             }
             if ($isVideo && $framecount) {
                 $info['quicktime']['video']['frame_count'] = $framecount;
             }
             break;
         case 'aART':
             // Album ARTist
         // Album ARTist
         case 'catg':
             // CaTeGory
         // CaTeGory
         case 'covr':
             // COVeR artwork
         // COVeR artwork
         case 'cpil':
             // ComPILation
         // ComPILation
         case 'cprt':
             // CoPyRighT
         // CoPyRighT
         case 'desc':
             // DESCription
         // DESCription
         case 'disk':
             // DISK number
         // DISK number
         case 'egid':
             // Episode Global ID
         // Episode Global ID
         case 'gnre':
             // GeNRE
         // GeNRE
         case 'keyw':
             // KEYWord
         // KEYWord
         case 'ldes':
         case 'pcst':
             // PodCaST
         // PodCaST
         case 'pgap':
             // GAPless Playback
         // GAPless Playback
         case 'purd':
             // PURchase Date
         // PURchase Date
         case 'purl':
             // Podcast URL
         // Podcast URL
         case 'rati':
         case 'rndu':
         case 'rpdu':
         case 'rtng':
             // RaTiNG
         // RaTiNG
         case 'stik':
         case 'tmpo':
             // TeMPO (BPM)
         // TeMPO (BPM)
         case 'trkn':
             // TRacK Number
         // TRacK Number
         case 'tves':
             // TV EpiSode
         // TV EpiSode
         case 'tvnn':
             // TV Network Name
         // TV Network Name
         case 'tvsh':
             // TV SHow Name
         // TV SHow Name
         case 'tvsn':
             // TV SeasoN
         // TV SeasoN
         case 'akID':
             // iTunes store account type
         // iTunes store account type
         case 'apID':
         case 'atID':
         case 'cmID':
         case 'cnID':
         case 'geID':
         case 'plID':
         case 'sfID':
             // iTunes store country
         // iTunes store country
         case '©alb':
             // ALBum
         // ALBum
         case '©art':
             // ARTist
         // ARTist
         case '©ART':
         case '©aut':
         case '©cmt':
             // CoMmenT
         // CoMmenT
         case '©com':
             // COMposer
         // COMposer
         case '©cpy':
         case '©day':
             // content created year
         // content created year
         case '©dir':
         case '©ed1':
         case '©ed2':
         case '©ed3':
         case '©ed4':
         case '©ed5':
         case '©ed6':
         case '©ed7':
         case '©ed8':
         case '©ed9':
         case '©enc':
         case '©fmt':
         case '©gen':
             // GENre
         // GENre
         case '©grp':
             // GRouPing
         // GRouPing
         case '©hst':
         case '©inf':
         case '©lyr':
             // LYRics
         // LYRics
         case '©mak':
         case '©mod':
         case '©nam':
             // full NAMe
         // full NAMe
         case '©ope':
         case '©PRD':
         case '©prd':
         case '©prf':
         case '©req':
         case '©src':
         case '©swr':
         case '©too':
             // encoder
         // encoder
         case '©trk':
             // TRacK
         // TRacK
         case '©url':
         case '©wrn':
         case '©wrt':
             // WRiTer
         // WRiTer
         case '----':
             // itunes specific
             if ($atom_parent == 'udta') {
                 // User data atom handler
                 $atom_structure['data_length'] = Helper::BigEndian2Int(substr($atom_data, 0, 2));
                 $atom_structure['language_id'] = Helper::BigEndian2Int(substr($atom_data, 2, 2));
                 $atom_structure['data'] = substr($atom_data, 4);
                 $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
                 if (empty($info['comments']['language']) || !in_array($atom_structure['language'], $info['comments']['language'])) {
                     $info['comments']['language'][] = $atom_structure['language'];
                 }
             } else {
                 // Apple item list box atom handler
                 $atomoffset = 0;
                 if (substr($atom_data, 2, 2) == "�") {
                     // not sure what it means, but observed on iPhone4 data.
                     // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
                     while ($atomoffset < strlen($atom_data)) {
                         $boxsmallsize = Helper::BigEndian2Int(substr($atom_data, $atomoffset, 2));
                         $boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
                         $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
                         switch ($boxsmalltype) {
                             case "�":
                                 $atom_structure['data'] = $boxsmalldata;
                                 break;
                             default:
                                 $info['warning'][] = 'Unknown QuickTime smallbox type: "' . Helper::PrintHexBytes($boxsmalltype) . '" at offset ' . $baseoffset;
                                 $atom_structure['data'] = $atom_data;
                                 break;
                         }
                         $atomoffset += 4 + $boxsmallsize;
                     }
                 } else {
                     while ($atomoffset < strlen($atom_data)) {
                         $boxsize = Helper::BigEndian2Int(substr($atom_data, $atomoffset, 4));
                         $boxtype = substr($atom_data, $atomoffset + 4, 4);
                         $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
                         if ($boxsize <= 1) {
                             $info['warning'][] = 'Invalid QuickTime atom box size "' . $boxsize . '" in atom "' . $atomname . '" at offset: ' . ($atom_structure['offset'] + $atomoffset);
                             $atom_structure['data'] = null;
                             $atomoffset = strlen($atom_data);
                             break;
                         }
                         $atomoffset += $boxsize;
                         switch ($boxtype) {
                             case 'mean':
                             case 'name':
                                 $atom_structure[$boxtype] = substr($boxdata, 4);
                                 break;
                             case 'data':
                                 $atom_structure['version'] = Helper::BigEndian2Int(substr($boxdata, 0, 1));
                                 $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($boxdata, 1, 3));
                                 switch ($atom_structure['flags_raw']) {
                                     case 0:
                                         // data flag
                                     // data flag
                                     case 21:
                                         // tmpo/cpil flag
                                         switch ($atomname) {
                                             case 'cpil':
                                             case 'pcst':
                                             case 'pgap':
                                                 $atom_structure['data'] = Helper::BigEndian2Int(substr($boxdata, 8, 1));
                                                 break;
                                             case 'tmpo':
                                                 $atom_structure['data'] = Helper::BigEndian2Int(substr($boxdata, 8, 2));
                                                 break;
                                             case 'disk':
                                             case 'trkn':
                                                 $num = Helper::BigEndian2Int(substr($boxdata, 10, 2));
                                                 $num_total = Helper::BigEndian2Int(substr($boxdata, 12, 2));
                                                 $atom_structure['data'] = empty($num) ? '' : $num;
                                                 $atom_structure['data'] .= empty($num_total) ? '' : '/' . $num_total;
                                                 break;
                                             case 'gnre':
                                                 $GenreID = Helper::BigEndian2Int(substr($boxdata, 8, 4));
                                                 $atom_structure['data'] = Module\Tag\Id3v1::LookupGenreName($GenreID - 1);
                                                 break;
                                             case 'rtng':
                                                 $atom_structure[$atomname] = Helper::BigEndian2Int(substr($boxdata, 8, 1));
                                                 $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
                                                 break;
                                             case 'stik':
                                                 $atom_structure[$atomname] = Helper::BigEndian2Int(substr($boxdata, 8, 1));
                                                 $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
                                                 break;
                                             case 'sfID':
                                                 $atom_structure[$atomname] = Helper::BigEndian2Int(substr($boxdata, 8, 4));
                                                 $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
                                                 break;
                                             case 'egid':
                                             case 'purl':
                                                 $atom_structure['data'] = substr($boxdata, 8);
                                                 break;
                                             default:
                                                 $atom_structure['data'] = Helper::BigEndian2Int(substr($boxdata, 8, 4));
                                         }
                                         break;
                                     case 1:
                                         // text flag
                                     // text flag
                                     case 13:
                                         // image flag
                                     // image flag
                                     default:
                                         $atom_structure['data'] = substr($boxdata, 8);
                                         break;
                                 }
                                 break;
                             default:
                                 $info['warning'][] = 'Unknown QuickTime box type: "' . Helper::PrintHexBytes($boxtype) . '" at offset ' . $baseoffset;
                                 $atom_structure['data'] = $atom_data;
                         }
                     }
                 }
             }
             $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
             break;
         case 'play':
             // auto-PLAY atom
             $atom_structure['autoplay'] = (bool) Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $info['quicktime']['autoplay'] = $atom_structure['autoplay'];
             break;
         case 'WLOC':
             // Window LOCation atom
             $atom_structure['location_x'] = Helper::BigEndian2Int(substr($atom_data, 0, 2));
             $atom_structure['location_y'] = Helper::BigEndian2Int(substr($atom_data, 2, 2));
             break;
         case 'LOOP':
             // LOOPing atom
         // LOOPing atom
         case 'SelO':
             // play SELection Only atom
         // play SELection Only atom
         case 'AllF':
             // play ALL Frames atom
             $atom_structure['data'] = Helper::BigEndian2Int($atom_data);
             break;
         case 'name':
             //
         //
         case 'MCPS':
             // Media Cleaner PRo
         // Media Cleaner PRo
         case '@PRM':
             // adobe PReMiere version
         // adobe PReMiere version
         case '@PRQ':
             // adobe PRemiere Quicktime version
             $atom_structure['data'] = $atom_data;
             break;
         case 'cmvd':
             // Compressed MooV Data atom
             // Code by ubergeekØubergeek*tv based on information from
             // http://developer.apple.com/quicktime/icefloe/dispatch012.html
             $atom_structure['unCompressedSize'] = Helper::BigEndian2Int(substr($atom_data, 0, 4));
             $CompressedFileData = substr($atom_data, 4);
             if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
                 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
             } else {
                 $info['warning'][] = 'Error decompressing compressed MOV atom at offset ' . $atom_structure['offset'];
             }
             break;
         case 'dcom':
             // Data COMpression atom
             $atom_structure['compression_id'] = $atom_data;
             $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
             break;
         case 'rdrf':
             // Reference movie Data ReFerence atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x1);
             $atom_structure['reference_type_name'] = substr($atom_data, 4, 4);
             $atom_structure['reference_length'] = Helper::BigEndian2Int(substr($atom_data, 8, 4));
             switch ($atom_structure['reference_type_name']) {
                 case 'url ':
                     $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12));
                     break;
                 case 'alis':
                     $atom_structure['file_alias'] = substr($atom_data, 12);
                     break;
                 case 'rsrc':
                     $atom_structure['resource_alias'] = substr($atom_data, 12);
                     break;
                 default:
                     $atom_structure['data'] = substr($atom_data, 12);
                     break;
             }
             break;
         case 'rmqu':
             // Reference Movie QUality atom
             $atom_structure['movie_quality'] = Helper::BigEndian2Int($atom_data);
             break;
         case 'rmcs':
             // Reference Movie Cpu Speed atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['cpu_speed_rating'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             break;
         case 'rmvc':
             // Reference Movie Version Check atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4);
             $atom_structure['gestalt_value_mask'] = Helper::BigEndian2Int(substr($atom_data, 8, 4));
             $atom_structure['gestalt_value'] = Helper::BigEndian2Int(substr($atom_data, 12, 4));
             $atom_structure['gestalt_check_type'] = Helper::BigEndian2Int(substr($atom_data, 14, 2));
             break;
         case 'rmcd':
             // Reference Movie Component check atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['component_type'] = substr($atom_data, 4, 4);
             $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
             $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
             $atom_structure['component_flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 16, 4));
             $atom_structure['component_flags_mask'] = Helper::BigEndian2Int(substr($atom_data, 20, 4));
             $atom_structure['component_min_version'] = Helper::BigEndian2Int(substr($atom_data, 24, 4));
             break;
         case 'rmdr':
             // Reference Movie Data Rate atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['data_rate'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
             break;
         case 'rmla':
             // Reference Movie Language Atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['language_id'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
             if (empty($info['comments']['language']) || !in_array($atom_structure['language'], $info['comments']['language'])) {
                 $info['comments']['language'][] = $atom_structure['language'];
             }
             break;
         case 'rmla':
             // Reference Movie Language Atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['track_id'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             break;
         case 'ptv ':
             // Print To Video - defines a movie's full screen mode
             // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
             $atom_structure['display_size_raw'] = Helper::BigEndian2Int(substr($atom_data, 0, 2));
             $atom_structure['reserved_1'] = Helper::BigEndian2Int(substr($atom_data, 2, 2));
             // hardcoded: 0x0000
             $atom_structure['reserved_2'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             // hardcoded: 0x0000
             $atom_structure['slide_show_flag'] = Helper::BigEndian2Int(substr($atom_data, 6, 1));
             $atom_structure['play_on_open_flag'] = Helper::BigEndian2Int(substr($atom_data, 7, 1));
             $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
             $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
             $ptv_lookup[0] = 'normal';
             $ptv_lookup[1] = 'double';
             $ptv_lookup[2] = 'half';
             $ptv_lookup[3] = 'full';
             $ptv_lookup[4] = 'current';
             if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
                 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
             } else {
                 $info['warning'][] = 'unknown "ptv " display constant (' . $atom_structure['display_size_raw'] . ')';
             }
             break;
         case 'stsd':
             // Sample Table Sample Description atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $stsdEntriesDataOffset = 8;
             for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                 $atom_structure['sample_description_table'][$i]['size'] = Helper::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
                 $stsdEntriesDataOffset += 4;
                 $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4);
                 $stsdEntriesDataOffset += 4;
                 $atom_structure['sample_description_table'][$i]['reserved'] = Helper::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
                 $stsdEntriesDataOffset += 6;
                 $atom_structure['sample_description_table'][$i]['reference_index'] = Helper::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
                 $stsdEntriesDataOffset += 2;
                 $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, $atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
                 $stsdEntriesDataOffset += $atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2;
                 $atom_structure['sample_description_table'][$i]['encoder_version'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2));
                 $atom_structure['sample_description_table'][$i]['encoder_revision'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2));
                 $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
                 switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
                     case "":
                         // audio atom
                         $atom_structure['sample_description_table'][$i]['audio_channels'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2));
                         $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2));
                         $atom_structure['sample_description_table'][$i]['audio_compression_id'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2));
                         $atom_structure['sample_description_table'][$i]['audio_packet_size'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2));
                         $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = Helper::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4));
                         switch ($atom_structure['sample_description_table'][$i]['data_format']) {
                             case 'avc1':
                             case 'mp4v':
                                 $info['fileformat'] = 'mp4';
                                 $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
                                 //$info['warning'][] = 'This version of GetId3Core() ['.$this->getid3->version().'] does not fully support MPEG-4 audio/video streams'; // 2011-02-18: why am I warning about this again? What's not supported?
                                 break;
                             case 'qtvr':
                                 $info['video']['dataformat'] = 'quicktimevr';
                                 break;
                             case 'mp4a':
                             default:
                                 $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
                                 $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
                                 $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels'];
                                 $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
                                 $info['audio']['codec'] = $info['quicktime']['audio']['codec'];
                                 $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate'];
                                 $info['audio']['channels'] = $info['quicktime']['audio']['channels'];
                                 $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth'];
                                 switch ($atom_structure['sample_description_table'][$i]['data_format']) {
                                     case 'raw ':
                                         // PCM
                                     // PCM
                                     case 'alac':
                                         // Apple Lossless Audio Codec
                                         $info['audio']['lossless'] = true;
                                         break;
                                     default:
                                         $info['audio']['lossless'] = false;
                                         break;
                                 }
                                 break;
                         }
                         break;
                     default:
                         switch ($atom_structure['sample_description_table'][$i]['data_format']) {
                             case 'mp4s':
                                 $info['fileformat'] = 'mp4';
                                 break;
                             default:
                                 // video atom
                                 $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
                                 $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
                                 $atom_structure['sample_description_table'][$i]['video_frame_width'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
                                 $atom_structure['sample_description_table'][$i]['video_frame_height'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
                                 $atom_structure['sample_description_table'][$i]['video_resolution_x'] = Helper::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4));
                                 $atom_structure['sample_description_table'][$i]['video_resolution_y'] = Helper::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
                                 $atom_structure['sample_description_table'][$i]['video_data_size'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
                                 $atom_structure['sample_description_table'][$i]['video_frame_count'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2));
                                 $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1));
                                 $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']);
                                 $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
                                 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = Helper::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
                                 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32 ? 'grayscale' : 'color';
                                 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
                                 if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
                                     $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
                                     $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
                                     $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'];
                                     $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
                                     $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
                                     $info['video']['codec'] = $info['quicktime']['video']['codec'];
                                     $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
                                 }
                                 $info['video']['lossless'] = false;
                                 $info['video']['pixel_aspect_ratio'] = (double) 1;
                                 break;
                         }
                         break;
                 }
                 switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
                     case 'mp4a':
                         $info['audio']['dataformat'] = 'mp4';
                         $info['quicktime']['audio']['codec'] = 'mp4';
                         break;
                     case '3ivx':
                     case '3iv1':
                     case '3iv2':
                         $info['video']['dataformat'] = '3ivx';
                         break;
                     case 'xvid':
                         $info['video']['dataformat'] = 'xvid';
                         break;
                     case 'mp4v':
                         $info['video']['dataformat'] = 'mpeg4';
                         break;
                     case 'divx':
                     case 'div1':
                     case 'div2':
                     case 'div3':
                     case 'div4':
                     case 'div5':
                     case 'div6':
                         $info['video']['dataformat'] = 'divx';
                         break;
                     default:
                         // do nothing
                         break;
                 }
                 unset($atom_structure['sample_description_table'][$i]['data']);
             }
             break;
         case 'stts':
             // Sample Table Time-to-Sample atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $sttsEntriesDataOffset = 8;
             //$FrameRateCalculatorArray = array();
             $frames_count = 0;
             for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                 $atom_structure['time_to_sample_table'][$i]['sample_count'] = Helper::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
                 $sttsEntriesDataOffset += 4;
                 $atom_structure['time_to_sample_table'][$i]['sample_duration'] = Helper::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
                 $sttsEntriesDataOffset += 4;
                 $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
                 // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
                 //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
                 //	$stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
                 //	if ($stts_new_framerate <= 60) {
                 //		// some atoms have durations of "1" giving a very large framerate, which probably is not right
                 //		$info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
                 //	}
                 //}
                 //
                 //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
             }
             $info['quicktime']['stts_framecount'][] = $frames_count;
             //$sttsFramesTotal  = 0;
             //$sttsSecondsTotal = 0;
             //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
             //	if (($frames_per_second > 60) || ($frames_per_second < 1)) {
             //		// not video FPS information, probably audio information
             //		$sttsFramesTotal  = 0;
             //		$sttsSecondsTotal = 0;
             //		break;
             //	}
             //	$sttsFramesTotal  += $frame_count;
             //	$sttsSecondsTotal += $frame_count / $frames_per_second;
             //}
             //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
             //	if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
             //		$info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
             //	}
             //}
             break;
         case 'stss':
             // Sample Table Sync Sample (key frames) atom
             if ($ParseAllPossibleAtoms) {
                 $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
                 $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
                 // hardcoded: 0x0000
                 $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
                 $stssEntriesDataOffset = 8;
                 for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                     $atom_structure['time_to_sample_table'][$i] = Helper::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
                     $stssEntriesDataOffset += 4;
                 }
             }
             break;
         case 'stsc':
             // Sample Table Sample-to-Chunk atom
             if ($ParseAllPossibleAtoms) {
                 $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
                 $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
                 // hardcoded: 0x0000
                 $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
                 $stscEntriesDataOffset = 8;
                 for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                     $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = Helper::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
                     $stscEntriesDataOffset += 4;
                     $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = Helper::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
                     $stscEntriesDataOffset += 4;
                     $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = Helper::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
                     $stscEntriesDataOffset += 4;
                 }
             }
             break;
         case 'stsz':
             // Sample Table SiZe atom
             if ($ParseAllPossibleAtoms) {
                 $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
                 $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
                 // hardcoded: 0x0000
                 $atom_structure['sample_size'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
                 $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 8, 4));
                 $stszEntriesDataOffset = 12;
                 if ($atom_structure['sample_size'] == 0) {
                     for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                         $atom_structure['sample_size_table'][$i] = Helper::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
                         $stszEntriesDataOffset += 4;
                     }
                 }
             }
             break;
         case 'stco':
             // Sample Table Chunk Offset atom
             if ($ParseAllPossibleAtoms) {
                 $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
                 $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
                 // hardcoded: 0x0000
                 $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
                 $stcoEntriesDataOffset = 8;
                 for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                     $atom_structure['chunk_offset_table'][$i] = Helper::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
                     $stcoEntriesDataOffset += 4;
                 }
             }
             break;
         case 'co64':
             // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
             if ($ParseAllPossibleAtoms) {
                 $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
                 $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
                 // hardcoded: 0x0000
                 $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
                 $stcoEntriesDataOffset = 8;
                 for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                     $atom_structure['chunk_offset_table'][$i] = Helper::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
                     $stcoEntriesDataOffset += 8;
                 }
             }
             break;
         case 'dref':
             // Data REFerence atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $drefDataOffset = 8;
             for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                 $atom_structure['data_references'][$i]['size'] = Helper::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
                 $drefDataOffset += 4;
                 $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
                 $drefDataOffset += 4;
                 $atom_structure['data_references'][$i]['version'] = Helper::BigEndian2Int(substr($atom_data, $drefDataOffset, 1));
                 $drefDataOffset += 1;
                 $atom_structure['data_references'][$i]['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, $drefDataOffset, 3));
                 // hardcoded: 0x0000
                 $drefDataOffset += 3;
                 $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, $atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
                 $drefDataOffset += $atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3;
                 $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x1);
             }
             break;
         case 'gmin':
             // base Media INformation atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['graphics_mode'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             $atom_structure['opcolor_red'] = Helper::BigEndian2Int(substr($atom_data, 6, 2));
             $atom_structure['opcolor_green'] = Helper::BigEndian2Int(substr($atom_data, 8, 2));
             $atom_structure['opcolor_blue'] = Helper::BigEndian2Int(substr($atom_data, 10, 2));
             $atom_structure['balance'] = Helper::BigEndian2Int(substr($atom_data, 12, 2));
             $atom_structure['reserved'] = Helper::BigEndian2Int(substr($atom_data, 14, 2));
             break;
         case 'smhd':
             // Sound Media information HeaDer atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['balance'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             $atom_structure['reserved'] = Helper::BigEndian2Int(substr($atom_data, 6, 2));
             break;
         case 'vmhd':
             // Video Media information HeaDer atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             $atom_structure['graphics_mode'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             $atom_structure['opcolor_red'] = Helper::BigEndian2Int(substr($atom_data, 6, 2));
             $atom_structure['opcolor_green'] = Helper::BigEndian2Int(substr($atom_data, 8, 2));
             $atom_structure['opcolor_blue'] = Helper::BigEndian2Int(substr($atom_data, 10, 2));
             $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x1);
             break;
         case 'hdlr':
             // HanDLeR reference atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['component_type'] = substr($atom_data, 4, 4);
             $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
             $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
             $atom_structure['component_flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 16, 4));
             $atom_structure['component_flags_mask'] = Helper::BigEndian2Int(substr($atom_data, 20, 4));
             $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));
             if ($atom_structure['component_subtype'] == 'STpn' && $atom_structure['component_manufacturer'] == 'zzzz') {
                 $info['video']['dataformat'] = 'quicktimevr';
             }
             break;
         case 'mdhd':
             // MeDia HeaDer atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['creation_time'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $atom_structure['modify_time'] = Helper::BigEndian2Int(substr($atom_data, 8, 4));
             $atom_structure['time_scale'] = Helper::BigEndian2Int(substr($atom_data, 12, 4));
             $atom_structure['duration'] = Helper::BigEndian2Int(substr($atom_data, 16, 4));
             $atom_structure['language_id'] = Helper::BigEndian2Int(substr($atom_data, 20, 2));
             $atom_structure['quality'] = Helper::BigEndian2Int(substr($atom_data, 22, 2));
             if ($atom_structure['time_scale'] == 0) {
                 $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
                 return false;
             }
             $info['quicktime']['time_scale'] = isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale'];
             $atom_structure['creation_time_unix'] = Helper::DateMac2Unix($atom_structure['creation_time']);
             $atom_structure['modify_time_unix'] = Helper::DateMac2Unix($atom_structure['modify_time']);
             $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
             $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
             if (empty($info['comments']['language']) || !in_array($atom_structure['language'], $info['comments']['language'])) {
                 $info['comments']['language'][] = $atom_structure['language'];
             }
             break;
         case 'pnot':
             // Preview atom
             $atom_structure['modification_date'] = Helper::BigEndian2Int(substr($atom_data, 0, 4));
             // "standard Macintosh format"
             $atom_structure['version_number'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             // hardcoded: 0x00
             $atom_structure['atom_type'] = substr($atom_data, 6, 4);
             // usually: 'PICT'
             $atom_structure['atom_index'] = Helper::BigEndian2Int(substr($atom_data, 10, 2));
             // usually: 0x01
             $atom_structure['modification_date_unix'] = Helper::DateMac2Unix($atom_structure['modification_date']);
             break;
         case 'crgn':
             // Clipping ReGioN atom
             $atom_structure['region_size'] = Helper::BigEndian2Int(substr($atom_data, 0, 2));
             // The Region size, Region boundary box,
             $atom_structure['boundary_box'] = Helper::BigEndian2Int(substr($atom_data, 2, 8));
             // and Clipping region data fields
             $atom_structure['clipping_data'] = substr($atom_data, 10);
             // constitute a QuickDraw region.
             break;
         case 'load':
             // track LOAD settings atom
             $atom_structure['preload_start_time'] = Helper::BigEndian2Int(substr($atom_data, 0, 4));
             $atom_structure['preload_duration'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $atom_structure['preload_flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 8, 4));
             $atom_structure['default_hints_raw'] = Helper::BigEndian2Int(substr($atom_data, 12, 4));
             $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x20);
             $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x100);
             break;
         case 'tmcd':
             // TiMe CoDe atom
         // TiMe CoDe atom
         case 'chap':
             // CHAPter list atom
         // CHAPter list atom
         case 'sync':
             // SYNChronization atom
         // SYNChronization atom
         case 'scpt':
             // tranSCriPT atom
         // tranSCriPT atom
         case 'ssrc':
             // non-primary SouRCe atom
             for ($i = 0; $i < strlen($atom_data) % 4; ++$i) {
                 $atom_structure['track_id'][$i] = Helper::BigEndian2Int(substr($atom_data, $i * 4, 4));
             }
             break;
         case 'elst':
             // Edit LiST atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['number_entries'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             for ($i = 0; $i < $atom_structure['number_entries']; ++$i) {
                 $atom_structure['edit_list'][$i]['track_duration'] = Helper::BigEndian2Int(substr($atom_data, 8 + $i * 12 + 0, 4));
                 $atom_structure['edit_list'][$i]['media_time'] = Helper::BigEndian2Int(substr($atom_data, 8 + $i * 12 + 4, 4));
                 $atom_structure['edit_list'][$i]['media_rate'] = Helper::FixedPoint16_16(substr($atom_data, 8 + $i * 12 + 8, 4));
             }
             break;
         case 'kmat':
             // compressed MATte atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             // hardcoded: 0x0000
             $atom_structure['matte_data_raw'] = substr($atom_data, 4);
             break;
         case 'ctab':
             // Color TABle atom
             $atom_structure['color_table_seed'] = Helper::BigEndian2Int(substr($atom_data, 0, 4));
             // hardcoded: 0x00000000
             $atom_structure['color_table_flags'] = Helper::BigEndian2Int(substr($atom_data, 4, 2));
             // hardcoded: 0x8000
             $atom_structure['color_table_size'] = Helper::BigEndian2Int(substr($atom_data, 6, 2)) + 1;
             for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; ++$colortableentry) {
                 $atom_structure['color_table'][$colortableentry]['alpha'] = Helper::BigEndian2Int(substr($atom_data, 8 + $colortableentry * 8 + 0, 2));
                 $atom_structure['color_table'][$colortableentry]['red'] = Helper::BigEndian2Int(substr($atom_data, 8 + $colortableentry * 8 + 2, 2));
                 $atom_structure['color_table'][$colortableentry]['green'] = Helper::BigEndian2Int(substr($atom_data, 8 + $colortableentry * 8 + 4, 2));
                 $atom_structure['color_table'][$colortableentry]['blue'] = Helper::BigEndian2Int(substr($atom_data, 8 + $colortableentry * 8 + 6, 2));
             }
             break;
         case 'mvhd':
             // MoVie HeaDer atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             $atom_structure['creation_time'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $atom_structure['modify_time'] = Helper::BigEndian2Int(substr($atom_data, 8, 4));
             $atom_structure['time_scale'] = Helper::BigEndian2Int(substr($atom_data, 12, 4));
             $atom_structure['duration'] = Helper::BigEndian2Int(substr($atom_data, 16, 4));
             $atom_structure['preferred_rate'] = Helper::FixedPoint16_16(substr($atom_data, 20, 4));
             $atom_structure['preferred_volume'] = Helper::FixedPoint8_8(substr($atom_data, 24, 2));
             $atom_structure['reserved'] = substr($atom_data, 26, 10);
             $atom_structure['matrix_a'] = Helper::FixedPoint16_16(substr($atom_data, 36, 4));
             $atom_structure['matrix_b'] = Helper::FixedPoint16_16(substr($atom_data, 40, 4));
             $atom_structure['matrix_u'] = Helper::FixedPoint2_30(substr($atom_data, 44, 4));
             $atom_structure['matrix_c'] = Helper::FixedPoint16_16(substr($atom_data, 48, 4));
             $atom_structure['matrix_d'] = Helper::FixedPoint16_16(substr($atom_data, 52, 4));
             $atom_structure['matrix_v'] = Helper::FixedPoint2_30(substr($atom_data, 56, 4));
             $atom_structure['matrix_x'] = Helper::FixedPoint16_16(substr($atom_data, 60, 4));
             $atom_structure['matrix_y'] = Helper::FixedPoint16_16(substr($atom_data, 64, 4));
             $atom_structure['matrix_w'] = Helper::FixedPoint2_30(substr($atom_data, 68, 4));
             $atom_structure['preview_time'] = Helper::BigEndian2Int(substr($atom_data, 72, 4));
             $atom_structure['preview_duration'] = Helper::BigEndian2Int(substr($atom_data, 76, 4));
             $atom_structure['poster_time'] = Helper::BigEndian2Int(substr($atom_data, 80, 4));
             $atom_structure['selection_time'] = Helper::BigEndian2Int(substr($atom_data, 84, 4));
             $atom_structure['selection_duration'] = Helper::BigEndian2Int(substr($atom_data, 88, 4));
             $atom_structure['current_time'] = Helper::BigEndian2Int(substr($atom_data, 92, 4));
             $atom_structure['next_track_id'] = Helper::BigEndian2Int(substr($atom_data, 96, 4));
             if ($atom_structure['time_scale'] == 0) {
                 $info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero';
                 return false;
             }
             $atom_structure['creation_time_unix'] = Helper::DateMac2Unix($atom_structure['creation_time']);
             $atom_structure['modify_time_unix'] = Helper::DateMac2Unix($atom_structure['modify_time']);
             $info['quicktime']['time_scale'] = isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale'];
             $info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
             $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
             break;
         case 'tkhd':
             // TracK HeaDer atom
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             $atom_structure['creation_time'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $atom_structure['modify_time'] = Helper::BigEndian2Int(substr($atom_data, 8, 4));
             $atom_structure['trackid'] = Helper::BigEndian2Int(substr($atom_data, 12, 4));
             $atom_structure['reserved1'] = Helper::BigEndian2Int(substr($atom_data, 16, 4));
             $atom_structure['duration'] = Helper::BigEndian2Int(substr($atom_data, 20, 4));
             $atom_structure['reserved2'] = Helper::BigEndian2Int(substr($atom_data, 24, 8));
             $atom_structure['layer'] = Helper::BigEndian2Int(substr($atom_data, 32, 2));
             $atom_structure['alternate_group'] = Helper::BigEndian2Int(substr($atom_data, 34, 2));
             $atom_structure['volume'] = Helper::FixedPoint8_8(substr($atom_data, 36, 2));
             $atom_structure['reserved3'] = Helper::BigEndian2Int(substr($atom_data, 38, 2));
             $atom_structure['matrix_a'] = Helper::FixedPoint16_16(substr($atom_data, 40, 4));
             $atom_structure['matrix_b'] = Helper::FixedPoint16_16(substr($atom_data, 44, 4));
             $atom_structure['matrix_u'] = Helper::FixedPoint16_16(substr($atom_data, 48, 4));
             $atom_structure['matrix_c'] = Helper::FixedPoint16_16(substr($atom_data, 52, 4));
             $atom_structure['matrix_d'] = Helper::FixedPoint16_16(substr($atom_data, 56, 4));
             $atom_structure['matrix_v'] = Helper::FixedPoint16_16(substr($atom_data, 60, 4));
             $atom_structure['matrix_x'] = Helper::FixedPoint2_30(substr($atom_data, 64, 4));
             $atom_structure['matrix_y'] = Helper::FixedPoint2_30(substr($atom_data, 68, 4));
             $atom_structure['matrix_w'] = Helper::FixedPoint2_30(substr($atom_data, 72, 4));
             $atom_structure['width'] = Helper::FixedPoint16_16(substr($atom_data, 76, 4));
             $atom_structure['height'] = Helper::FixedPoint16_16(substr($atom_data, 80, 4));
             $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x1);
             $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x2);
             $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x4);
             $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x8);
             $atom_structure['creation_time_unix'] = Helper::DateMac2Unix($atom_structure['creation_time']);
             $atom_structure['modify_time_unix'] = Helper::DateMac2Unix($atom_structure['modify_time']);
             if ($atom_structure['flags']['enabled'] == 1) {
                 if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
                     $info['video']['resolution_x'] = $atom_structure['width'];
                     $info['video']['resolution_y'] = $atom_structure['height'];
                 }
                 $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
                 $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
                 $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
                 $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
             } else {
                 if (isset($info['video']['resolution_x'])) {
                     unset($info['video']['resolution_x']);
                 }
                 if (isset($info['video']['resolution_y'])) {
                     unset($info['video']['resolution_y']);
                 }
                 if (isset($info['quicktime']['video'])) {
                     unset($info['quicktime']['video']);
                 }
             }
             break;
         case 'iods':
             // Initial Object DeScriptor atom
             // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
             // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
             $offset = 0;
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
             $offset += 1;
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, $offset, 3));
             $offset += 3;
             $atom_structure['mp4_iod_tag'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
             $offset += 1;
             $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
             //$offset already adjusted by quicktime_read_mp4_descr_length()
             $atom_structure['object_descriptor_id'] = Helper::BigEndian2Int(substr($atom_data, $offset, 2));
             $offset += 2;
             $atom_structure['od_profile_level'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
             $offset += 1;
             $atom_structure['scene_profile_level'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
             $offset += 1;
             $atom_structure['audio_profile_id'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
             $offset += 1;
             $atom_structure['video_profile_id'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
             $offset += 1;
             $atom_structure['graphics_profile_level'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
             $offset += 1;
             $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6;
             // 6 bytes would only be right if all tracks use 1-byte length fields
             for ($i = 0; $i < $atom_structure['num_iods_tracks']; ++$i) {
                 $atom_structure['track'][$i]['ES_ID_IncTag'] = Helper::BigEndian2Int(substr($atom_data, $offset, 1));
                 $offset += 1;
                 $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
                 //$offset already adjusted by quicktime_read_mp4_descr_length()
                 $atom_structure['track'][$i]['track_id'] = Helper::BigEndian2Int(substr($atom_data, $offset, 4));
                 $offset += 4;
             }
             $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
             $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
             break;
         case 'ftyp':
             // FileTYPe (?) atom (for MP4 it seems)
             $atom_structure['signature'] = substr($atom_data, 0, 4);
             $atom_structure['unknown_1'] = Helper::BigEndian2Int(substr($atom_data, 4, 4));
             $atom_structure['fourcc'] = substr($atom_data, 8, 4);
             break;
         case 'mdat':
             // Media DATa atom
         // Media DATa atom
         case 'free':
             // FREE space atom
         // FREE space atom
         case 'skip':
             // SKIP atom
         // SKIP atom
         case 'wide':
             // 64-bit expansion placeholder atom
             // 'mdat' data is too big to deal with, contains no useful metadata
             // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
             // When writing QuickTime files, it is sometimes necessary to update an atom's size.
             // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
             // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
             // puts an 8-byte placeholder atom before any atoms it may have to update the size of.
             // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
             // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
             // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
             break;
         case 'nsav':
             // NoSAVe atom
             // http://developer.apple.com/technotes/tn/tn2038.html
             $atom_structure['data'] = Helper::BigEndian2Int(substr($atom_data, 0, 4));
             break;
         case 'ctyp':
             // Controller TYPe atom (seen on QTVR)
             // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
             // some controller names are:
             //   0x00 + 'std' for linear movie
             //   'none' for no controls
             $atom_structure['ctyp'] = substr($atom_data, 0, 4);
             $info['quicktime']['controller'] = $atom_structure['ctyp'];
             switch ($atom_structure['ctyp']) {
                 case 'qtvr':
                     $info['video']['dataformat'] = 'quicktimevr';
                     break;
             }
             break;
         case 'pano':
             // PANOrama track (seen on QTVR)
             $atom_structure['pano'] = Helper::BigEndian2Int(substr($atom_data, 0, 4));
             break;
         case 'hint':
             // HINT track
         // HINT track
         case 'hinf':
             //
         //
         case 'hinv':
             //
         //
         case 'hnti':
             //
             $info['quicktime']['hinting'] = true;
             break;
         case 'imgt':
             // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
             for ($i = 0; $i < $atom_structure['size'] - 8; $i += 4) {
                 $atom_structure['imgt'][] = Helper::BigEndian2Int(substr($atom_data, $i, 4));
             }
             break;
             // Observed-but-not-handled atom types are just listed here to prevent warnings being generated
         // Observed-but-not-handled atom types are just listed here to prevent warnings being generated
         case 'FXTC':
             // Something to do with Adobe After Effects (?)
         // Something to do with Adobe After Effects (?)
         case 'PrmA':
         case 'code':
         case 'FIEL':
             // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
         // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
         case 'tapt':
             // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
             // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
             // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
             // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
         // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
         // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
         // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
         // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
         case 'ctts':
             //  STCompositionOffsetAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
         //  STCompositionOffsetAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
         case 'cslg':
             //  STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
         //  STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
         case 'sdtp':
             //  STSampleDependencyAID              - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
         //  STSampleDependencyAID              - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
         case 'stps':
             //  STPartialSyncSampleAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
             //$atom_structure['data'] = $atom_data;
             break;
         case '©xyz':
             // GPS latitude+longitude+altitude
             $atom_structure['data'] = $atom_data;
             if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
                 @(list($all, $latitude, $longitude, $altitude) = $matches);
                 $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude);
                 $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
                 if (!empty($altitude)) {
                     $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
                 }
             } else {
                 $info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset ' . $baseoffset . '. Please report as GetId3Core() bug.';
             }
             break;
         case 'NCDT':
             // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
             // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
             $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
             break;
         case 'NCTH':
             // Nikon Camera THumbnail image
         // Nikon Camera THumbnail image
         case 'NCVW':
             // Nikon Camera preVieW image
             // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
             if (preg_match('/^\\xFF\\xD8\\xFF/', $atom_data)) {
                 $atom_structure['data'] = $atom_data;
                 $atom_structure['image_mime'] = 'image/jpeg';
                 $atom_structure['description'] = $atomname == 'NCTH' ? 'Nikon Camera Thumbnail Image' : ($atomname == 'NCVW' ? 'Nikon Camera Preview Image' : 'Nikon preview image');
                 $info['quicktime']['comments']['picture'][] = array('image_mime' => $atom_structure['image_mime'], 'data' => $atom_data, 'description' => $atom_structure['description']);
             }
             break;
         case 'NCHD':
             // MakerNoteVersion
             // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
             $atom_structure['data'] = $atom_data;
             break;
         case 'NCTG':
             // NikonTags
             // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
             $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
             break;
         case 'NCDB':
             // NikonTags
             // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
             $atom_structure['data'] = $atom_data;
             break;
         case "":
         case 'meta':
             // METAdata atom
             // some kind of metacontainer, may contain a big data dump such as:
             // mdta keys  mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst   data DEApple 0  (data DE2011-05-11T17:54:04+0200 2  *data DE+52.4936+013.3897+040.247/   data DE4.3.1  data DEiPhone 4
             // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
             $atom_structure['version'] = Helper::BigEndian2Int(substr($atom_data, 0, 1));
             $atom_structure['flags_raw'] = Helper::BigEndian2Int(substr($atom_data, 1, 3));
             $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
             //$atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
             break;
         case 'data':
             // metaDATA atom
             // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
             $atom_structure['language'] = substr($atom_data, 4 + 0, 2);
             $atom_structure['unknown'] = Helper::BigEndian2Int(substr($atom_data, 4 + 2, 2));
             $atom_structure['data'] = substr($atom_data, 4 + 4);
             break;
         default:
             $info['warning'][] = 'Unknown QuickTime atom type: "' . $atomname . '" (' . trim(Helper::PrintHexBytes($atomname)) . ') at offset ' . $baseoffset;
             $atom_structure['data'] = $atom_data;
             break;
     }
     array_pop($atomHierarchy);
     return $atom_structure;
 }
コード例 #26
0
ファイル: La.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     $offset = 0;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $rawdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
     switch (substr($rawdata, $offset, 4)) {
         case 'LA02':
         case 'LA03':
         case 'LA04':
             $info['fileformat'] = 'la';
             $info['audio']['dataformat'] = 'la';
             $info['audio']['lossless'] = true;
             $info['la']['version_major'] = (int) substr($rawdata, $offset + 2, 1);
             $info['la']['version_minor'] = (int) substr($rawdata, $offset + 3, 1);
             $info['la']['version'] = (double) $info['la']['version_major'] + $info['la']['version_minor'] / 10;
             $offset += 4;
             $info['la']['uncompressed_size'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             if ($info['la']['uncompressed_size'] == 0) {
                 $info['error'][] = 'Corrupt LA file: uncompressed_size == zero';
                 return false;
             }
             $WAVEchunk = substr($rawdata, $offset, 4);
             if ($WAVEchunk !== 'WAVE') {
                 $info['error'][] = 'Expected "WAVE" (' . Helper::PrintHexBytes('WAVE') . ') at offset ' . $offset . ', found "' . $WAVEchunk . '" (' . Helper::PrintHexBytes($WAVEchunk) . ') instead.';
                 return false;
             }
             $offset += 4;
             $info['la']['fmt_size'] = 24;
             if ($info['la']['version'] >= 0.3) {
                 $info['la']['fmt_size'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
                 $info['la']['header_size'] = 49 + $info['la']['fmt_size'] - 24;
                 $offset += 4;
             } else {
                 // version 0.2 didn't support additional data blocks
                 $info['la']['header_size'] = 41;
             }
             $fmt_chunk = substr($rawdata, $offset, 4);
             if ($fmt_chunk !== 'fmt ') {
                 $info['error'][] = 'Expected "fmt " (' . Helper::PrintHexBytes('fmt ') . ') at offset ' . $offset . ', found "' . $fmt_chunk . '" (' . Helper::PrintHexBytes($fmt_chunk) . ') instead.';
                 return false;
             }
             $offset += 4;
             $fmt_size = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             $info['la']['raw']['format'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 2));
             $offset += 2;
             $info['la']['channels'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 2));
             $offset += 2;
             if ($info['la']['channels'] == 0) {
                 $info['error'][] = 'Corrupt LA file: channels == zero';
                 return false;
             }
             $info['la']['sample_rate'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             if ($info['la']['sample_rate'] == 0) {
                 $info['error'][] = 'Corrupt LA file: sample_rate == zero';
                 return false;
             }
             $info['la']['bytes_per_second'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             $info['la']['bytes_per_sample'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 2));
             $offset += 2;
             $info['la']['bits_per_sample'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 2));
             $offset += 2;
             $info['la']['samples'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             $info['la']['raw']['flags'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 1));
             $offset += 1;
             $info['la']['flags']['seekable'] = (bool) ($info['la']['raw']['flags'] & 0x1);
             if ($info['la']['version'] >= 0.4) {
                 $info['la']['flags']['high_compression'] = (bool) ($info['la']['raw']['flags'] & 0x2);
             }
             $info['la']['original_crc'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             // mikeØbevin*de
             // Basically, the blocksize/seekevery are 61440/19 in La0.4 and 73728/16
             // in earlier versions. A seekpoint is added every blocksize * seekevery
             // samples, so 4 * int(totalSamples / (blockSize * seekEvery)) should
             // give the number of bytes used for the seekpoints. Of course, if seeking
             // is disabled, there are no seekpoints stored.
             if ($info['la']['version'] >= 0.4) {
                 $info['la']['blocksize'] = 61440;
                 $info['la']['seekevery'] = 19;
             } else {
                 $info['la']['blocksize'] = 73728;
                 $info['la']['seekevery'] = 16;
             }
             $info['la']['seekpoint_count'] = 0;
             if ($info['la']['flags']['seekable']) {
                 $info['la']['seekpoint_count'] = floor($info['la']['samples'] / ($info['la']['blocksize'] * $info['la']['seekevery']));
                 for ($i = 0; $i < $info['la']['seekpoint_count']; ++$i) {
                     $info['la']['seekpoints'][] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
                     $offset += 4;
                 }
             }
             if ($info['la']['version'] >= 0.3) {
                 // Following the main header information, the program outputs all of the
                 // seekpoints. Following these is what I called the 'footer start',
                 // i.e. the position immediately after the La audio data is finished.
                 $info['la']['footerstart'] = Helper::LittleEndian2Int(substr($rawdata, $offset, 4));
                 $offset += 4;
                 if ($info['la']['footerstart'] > $info['filesize']) {
                     $info['warning'][] = 'FooterStart value points to offset ' . $info['la']['footerstart'] . ' which is beyond end-of-file (' . $info['filesize'] . ')';
                     $info['la']['footerstart'] = $info['filesize'];
                 }
             } else {
                 // La v0.2 didn't have FooterStart value
                 $info['la']['footerstart'] = $info['avdataend'];
             }
             if ($info['la']['footerstart'] < $info['avdataend']) {
                 if ($RIFFtempfilename = tempnam(GetId3Core::getTempDir(), 'id3')) {
                     if ($RIFF_fp = fopen($RIFFtempfilename, 'w+b')) {
                         $RIFFdata = 'WAVE';
                         if ($info['la']['version'] == 0.2) {
                             $RIFFdata .= substr($rawdata, 12, 24);
                         } else {
                             $RIFFdata .= substr($rawdata, 16, 24);
                         }
                         if ($info['la']['footerstart'] < $info['avdataend']) {
                             fseek($this->getid3->fp, $info['la']['footerstart'], SEEK_SET);
                             $RIFFdata .= fread($this->getid3->fp, $info['avdataend'] - $info['la']['footerstart']);
                         }
                         $RIFFdata = 'RIFF' . Helper::LittleEndian2String(strlen($RIFFdata), 4, false) . $RIFFdata;
                         fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata));
                         fclose($RIFF_fp);
                         $getid3_temp = new GetId3Core();
                         $getid3_temp->openfile($RIFFtempfilename);
                         $getid3_riff = new Riff($getid3_temp);
                         $getid3_riff->analyze();
                         if (empty($getid3_temp->info['error'])) {
                             $info['riff'] = $getid3_temp->info['riff'];
                         } else {
                             $info['warning'][] = 'Error parsing RIFF portion of La file: ' . implode($getid3_temp->info['error']);
                         }
                         unset($getid3_temp, $getid3_riff);
                     }
                     unlink($RIFFtempfilename);
                 }
             }
             // $info['avdataoffset'] should be zero to begin with, but just in case it's not, include the addition anyway
             $info['avdataend'] = $info['avdataoffset'] + $info['la']['footerstart'];
             $info['avdataoffset'] = $info['avdataoffset'] + $offset;
             //$info['la']['codec']                = RIFFwFormatTagLookup($info['la']['raw']['format']);
             $info['la']['compression_ratio'] = (double) (($info['avdataend'] - $info['avdataoffset']) / $info['la']['uncompressed_size']);
             $info['playtime_seconds'] = (double) ($info['la']['samples'] / $info['la']['sample_rate']) / $info['la']['channels'];
             if ($info['playtime_seconds'] == 0) {
                 $info['error'][] = 'Corrupt LA file: playtime_seconds == zero';
                 return false;
             }
             $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
             //$info['audio']['codec']              = $info['la']['codec'];
             $info['audio']['bits_per_sample'] = $info['la']['bits_per_sample'];
             break;
         default:
             if (substr($rawdata, $offset, 2) == 'LA') {
                 $info['error'][] = 'This version of GetId3Core() [' . $this->getid3->version() . '] does not support LA version ' . substr($rawdata, $offset + 2, 1) . '.' . substr($rawdata, $offset + 3, 1) . ' which this appears to be - check http://getid3.sourceforge.net for updates.';
             } else {
                 $info['error'][] = 'Not a LA (Lossless-Audio) file';
             }
             return false;
             break;
     }
     $info['audio']['channels'] = $info['la']['channels'];
     $info['audio']['sample_rate'] = (int) $info['la']['sample_rate'];
     $info['audio']['encoder'] = 'LA v' . $info['la']['version'];
     return true;
 }
コード例 #27
0
ファイル: Bonk.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // shortcut
     $info['bonk'] = array();
     $thisfile_bonk =& $info['bonk'];
     $thisfile_bonk['dataoffset'] = $info['avdataoffset'];
     $thisfile_bonk['dataend'] = $info['avdataend'];
     if (!Helper::intValueSupported($thisfile_bonk['dataend'])) {
         $info['warning'][] = 'Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to ' . round(PHP_INT_MAX / 1073741824) . 'GB';
     } else {
         // scan-from-end method, for v0.6 and higher
         fseek($this->getid3->fp, $thisfile_bonk['dataend'] - 8, SEEK_SET);
         $PossibleBonkTag = fread($this->getid3->fp, 8);
         while ($this->BonkIsValidTagName(substr($PossibleBonkTag, 4, 4), true)) {
             $BonkTagSize = Helper::LittleEndian2Int(substr($PossibleBonkTag, 0, 4));
             fseek($this->getid3->fp, 0 - $BonkTagSize, SEEK_CUR);
             $BonkTagOffset = ftell($this->getid3->fp);
             $TagHeaderTest = fread($this->getid3->fp, 5);
             if ($TagHeaderTest[0] != "" || substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4))) {
                 $info['error'][] = 'Expecting "' . Helper::PrintHexBytes("" . strtoupper(substr($PossibleBonkTag, 4, 4))) . '" at offset ' . $BonkTagOffset . ', found "' . Helper::PrintHexBytes($TagHeaderTest) . '"';
                 return false;
             }
             $BonkTagName = substr($TagHeaderTest, 1, 4);
             $thisfile_bonk[$BonkTagName]['size'] = $BonkTagSize;
             $thisfile_bonk[$BonkTagName]['offset'] = $BonkTagOffset;
             $this->HandleBonkTags($BonkTagName);
             $NextTagEndOffset = $BonkTagOffset - 8;
             if ($NextTagEndOffset < $thisfile_bonk['dataoffset']) {
                 if (empty($info['audio']['encoder'])) {
                     $info['audio']['encoder'] = 'Extended BONK v0.9+';
                 }
                 return true;
             }
             fseek($this->getid3->fp, $NextTagEndOffset, SEEK_SET);
             $PossibleBonkTag = fread($this->getid3->fp, 8);
         }
     }
     // seek-from-beginning method for v0.4 and v0.5
     if (empty($thisfile_bonk['BONK'])) {
         fseek($this->getid3->fp, $thisfile_bonk['dataoffset'], SEEK_SET);
         do {
             $TagHeaderTest = fread($this->getid3->fp, 5);
             switch ($TagHeaderTest) {
                 case "" . 'BONK':
                     if (empty($info['audio']['encoder'])) {
                         $info['audio']['encoder'] = 'BONK v0.4';
                     }
                     break;
                 case "" . 'INFO':
                     $info['audio']['encoder'] = 'Extended BONK v0.5';
                     break;
                 default:
                     break 2;
             }
             $BonkTagName = substr($TagHeaderTest, 1, 4);
             $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
             $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
             $this->HandleBonkTags($BonkTagName);
         } while (true);
     }
     // parse META block for v0.6 - v0.8
     if (empty($thisfile_bonk['INFO']) && isset($thisfile_bonk['META']['tags']['info'])) {
         fseek($this->getid3->fp, $thisfile_bonk['META']['tags']['info'], SEEK_SET);
         $TagHeaderTest = fread($this->getid3->fp, 5);
         if ($TagHeaderTest == "" . 'INFO') {
             $info['audio']['encoder'] = 'Extended BONK v0.6 - v0.8';
             $BonkTagName = substr($TagHeaderTest, 1, 4);
             $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
             $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
             $this->HandleBonkTags($BonkTagName);
         }
     }
     if (empty($info['audio']['encoder'])) {
         $info['audio']['encoder'] = 'Extended BONK v0.9+';
     }
     if (empty($thisfile_bonk['BONK'])) {
         unset($info['bonk']);
     }
     return true;
 }
コード例 #28
0
ファイル: Gif.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     $info['fileformat'] = 'gif';
     $info['video']['dataformat'] = 'gif';
     $info['video']['lossless'] = true;
     $info['video']['pixel_aspect_ratio'] = (double) 1;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $GIFheader = fread($this->getid3->fp, 13);
     $offset = 0;
     $info['gif']['header']['raw']['identifier'] = substr($GIFheader, $offset, 3);
     $offset += 3;
     $magic = 'GIF';
     if ($info['gif']['header']['raw']['identifier'] != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($info['gif']['header']['raw']['identifier']) . '"';
         unset($info['fileformat']);
         unset($info['gif']);
         return false;
     }
     $info['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3);
     $offset += 3;
     $info['gif']['header']['raw']['width'] = Helper::LittleEndian2Int(substr($GIFheader, $offset, 2));
     $offset += 2;
     $info['gif']['header']['raw']['height'] = Helper::LittleEndian2Int(substr($GIFheader, $offset, 2));
     $offset += 2;
     $info['gif']['header']['raw']['flags'] = Helper::LittleEndian2Int(substr($GIFheader, $offset, 1));
     $offset += 1;
     $info['gif']['header']['raw']['bg_color_index'] = Helper::LittleEndian2Int(substr($GIFheader, $offset, 1));
     $offset += 1;
     $info['gif']['header']['raw']['aspect_ratio'] = Helper::LittleEndian2Int(substr($GIFheader, $offset, 1));
     $offset += 1;
     $info['video']['resolution_x'] = $info['gif']['header']['raw']['width'];
     $info['video']['resolution_y'] = $info['gif']['header']['raw']['height'];
     $info['gif']['version'] = $info['gif']['header']['raw']['version'];
     $info['gif']['header']['flags']['global_color_table'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x80);
     if ($info['gif']['header']['raw']['flags'] & 0x80) {
         // Number of bits per primary color available to the original image, minus 1
         $info['gif']['header']['bits_per_pixel'] = 3 * ((($info['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1);
     } else {
         $info['gif']['header']['bits_per_pixel'] = 0;
     }
     $info['gif']['header']['flags']['global_color_sorted'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x40);
     if ($info['gif']['header']['flags']['global_color_table']) {
         // the number of bytes contained in the Global Color Table. To determine that
         // actual size of the color table, raise 2 to [the value of the field + 1]
         $info['gif']['header']['global_color_size'] = pow(2, ($info['gif']['header']['raw']['flags'] & 0x7) + 1);
         $info['video']['bits_per_sample'] = ($info['gif']['header']['raw']['flags'] & 0x7) + 1;
     } else {
         $info['gif']['header']['global_color_size'] = 0;
     }
     if ($info['gif']['header']['raw']['aspect_ratio'] != 0) {
         // Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
         $info['gif']['header']['aspect_ratio'] = ($info['gif']['header']['raw']['aspect_ratio'] + 15) / 64;
     }
     //		if ($info['gif']['header']['flags']['global_color_table']) {
     //			$GIFcolorTable = fread($this->getid3->fp, 3 * $info['gif']['header']['global_color_size']);
     //			$offset = 0;
     //			for ($i = 0; $i < $info['gif']['header']['global_color_size']; $i++) {
     //				$red   = GetId3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
     //				$green = GetId3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
     //				$blue  = GetId3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
     //				$info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
     //			}
     //		}
     //
     //		// Image Descriptor
     //		while (!feof($this->getid3->fp)) {
     //			$NextBlockTest = fread($this->getid3->fp, 1);
     //			switch ($NextBlockTest) {
     //
     //				case ',': // ',' - Image separator character
     //
     //					$ImageDescriptorData = $NextBlockTest.fread($this->getid3->fp, 9);
     //					$ImageDescriptor = array();
     //					$ImageDescriptor['image_left']   = GetId3_lib::LittleEndian2Int(substr($ImageDescriptorData, 1, 2));
     //					$ImageDescriptor['image_top']    = GetId3_lib::LittleEndian2Int(substr($ImageDescriptorData, 3, 2));
     //					$ImageDescriptor['image_width']  = GetId3_lib::LittleEndian2Int(substr($ImageDescriptorData, 5, 2));
     //					$ImageDescriptor['image_height'] = GetId3_lib::LittleEndian2Int(substr($ImageDescriptorData, 7, 2));
     //					$ImageDescriptor['flags_raw']    = GetId3_lib::LittleEndian2Int(substr($ImageDescriptorData, 9, 1));
     //					$ImageDescriptor['flags']['use_local_color_map'] = (bool) ($ImageDescriptor['flags_raw'] & 0x80);
     //					$ImageDescriptor['flags']['image_interlaced']    = (bool) ($ImageDescriptor['flags_raw'] & 0x40);
     //					$info['gif']['image_descriptor'][] = $ImageDescriptor;
     //
     //					if ($ImageDescriptor['flags']['use_local_color_map']) {
     //
     //						$info['warning'][] = 'This version of GetId3Core() cannot parse local color maps for GIFs';
     //						return true;
     //
     //					}
     //echo 'Start of raster data: '.ftell($this->getid3->fp).'<BR>';
     //					$RasterData = array();
     //					$RasterData['code_size']        = GetId3_lib::LittleEndian2Int(fread($this->getid3->fp, 1));
     //					$RasterData['block_byte_count'] = GetId3_lib::LittleEndian2Int(fread($this->getid3->fp, 1));
     //					$info['gif']['raster_data'][count($info['gif']['image_descriptor']) - 1] = $RasterData;
     //
     //					$CurrentCodeSize = $RasterData['code_size'] + 1;
     //					for ($i = 0; $i < pow(2, $RasterData['code_size']); $i++) {
     //						$DefaultDataLookupTable[$i] = chr($i);
     //					}
     //					$DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 0] = ''; // Clear Code
     //					$DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 1] = ''; // End Of Image Code
     //
     //
     //					$NextValue = $this->GetLSBits($CurrentCodeSize);
     //					echo 'Clear Code: '.$NextValue.'<BR>';
     //
     //					$NextValue = $this->GetLSBits($CurrentCodeSize);
     //					echo 'First Color: '.$NextValue.'<BR>';
     //
     //					$Prefix = $NextValue;
     //$i = 0;
     //					while ($i++ < 20) {
     //						$NextValue = $this->GetLSBits($CurrentCodeSize);
     //						echo $NextValue.'<BR>';
     //					}
     //return true;
     //					break;
     //
     //				case '!':
     //					// GIF Extension Block
     //					$ExtensionBlockData = $NextBlockTest.fread($this->getid3->fp, 2);
     //					$ExtensionBlock = array();
     //					$ExtensionBlock['function_code']  = GetId3_lib::LittleEndian2Int(substr($ExtensionBlockData, 1, 1));
     //					$ExtensionBlock['byte_length']    = GetId3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1));
     //					$ExtensionBlock['data']           = fread($this->getid3->fp, $ExtensionBlock['byte_length']);
     //					$info['gif']['extension_blocks'][] = $ExtensionBlock;
     //					break;
     //
     //				case ';':
     //					$info['gif']['terminator_offset'] = ftell($this->getid3->fp) - 1;
     //					// GIF Terminator
     //					break;
     //
     //				default:
     //					break;
     //
     //
     //			}
     //		}
     return true;
 }
コード例 #29
0
ファイル: Wavpack.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     while (true) {
         $wavpackheader = fread($this->getid3->fp, 32);
         if (ftell($this->getid3->fp) >= $info['avdataend']) {
             break;
         } elseif (feof($this->getid3->fp)) {
             break;
         } elseif (isset($info['wavpack']['blockheader']['total_samples']) && isset($info['wavpack']['blockheader']['block_samples']) && $info['wavpack']['blockheader']['total_samples'] > 0 && $info['wavpack']['blockheader']['block_samples'] > 0 && (!isset($info['wavpack']['riff_trailer_size']) || $info['wavpack']['riff_trailer_size'] <= 0) && (isset($info['wavpack']['config_flags']['md5_checksum']) && $info['wavpack']['config_flags']['md5_checksum'] === false || !empty($info['md5_data_source']))) {
             break;
         }
         $blockheader_offset = ftell($this->getid3->fp) - 32;
         $blockheader_magic = substr($wavpackheader, 0, 4);
         $blockheader_size = Helper::LittleEndian2Int(substr($wavpackheader, 4, 4));
         $magic = 'wvpk';
         if ($blockheader_magic != $magic) {
             $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $blockheader_offset . ', found "' . Helper::PrintHexBytes($blockheader_magic) . '"';
             switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
                 case 'wavpack':
                 case 'wvc':
                     break;
                 default:
                     unset($info['fileformat']);
                     unset($info['audio']);
                     unset($info['wavpack']);
                     break;
             }
             return false;
         }
         if (empty($info['wavpack']['blockheader']['block_samples']) || empty($info['wavpack']['blockheader']['total_samples']) || $info['wavpack']['blockheader']['block_samples'] <= 0 || $info['wavpack']['blockheader']['total_samples'] <= 0) {
             // Also, it is possible that the first block might not have
             // any samples (block_samples == 0) and in this case you should skip blocks
             // until you find one with samples because the other information (like
             // total_samples) are not guaranteed to be correct until (block_samples > 0)
             // Finally, I have defined a format for files in which the length is not known
             // (for example when raw files are created using pipes). In these cases
             // total_samples will be -1 and you must seek to the final block to determine
             // the total number of samples.
             $info['audio']['dataformat'] = 'wavpack';
             $info['fileformat'] = 'wavpack';
             $info['audio']['lossless'] = true;
             $info['audio']['bitrate_mode'] = 'vbr';
             $info['wavpack']['blockheader']['offset'] = $blockheader_offset;
             $info['wavpack']['blockheader']['magic'] = $blockheader_magic;
             $info['wavpack']['blockheader']['size'] = $blockheader_size;
             if ($info['wavpack']['blockheader']['size'] >= 0x100000) {
                 $info['error'][] = 'Expecting WavPack block size less than "0x100000", found "' . $info['wavpack']['blockheader']['size'] . '" at offset ' . $info['wavpack']['blockheader']['offset'];
                 switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
                     case 'wavpack':
                     case 'wvc':
                         break;
                     default:
                         unset($info['fileformat']);
                         unset($info['audio']);
                         unset($info['wavpack']);
                         break;
                 }
                 return false;
             }
             $info['wavpack']['blockheader']['minor_version'] = ord($wavpackheader[8]);
             $info['wavpack']['blockheader']['major_version'] = ord($wavpackheader[9]);
             if ($info['wavpack']['blockheader']['major_version'] != 4 || $info['wavpack']['blockheader']['minor_version'] < 4 && $info['wavpack']['blockheader']['minor_version'] > 16) {
                 $info['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "' . $info['wavpack']['blockheader']['major_version'] . '.' . $info['wavpack']['blockheader']['minor_version'] . '" at offset ' . $info['wavpack']['blockheader']['offset'];
                 switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') {
                     case 'wavpack':
                     case 'wvc':
                         break;
                     default:
                         unset($info['fileformat']);
                         unset($info['audio']);
                         unset($info['wavpack']);
                         break;
                 }
                 return false;
             }
             $info['wavpack']['blockheader']['track_number'] = ord($wavpackheader[10]);
             // unused
             $info['wavpack']['blockheader']['index_number'] = ord($wavpackheader[11]);
             // unused
             $info['wavpack']['blockheader']['total_samples'] = Helper::LittleEndian2Int(substr($wavpackheader, 12, 4));
             $info['wavpack']['blockheader']['block_index'] = Helper::LittleEndian2Int(substr($wavpackheader, 16, 4));
             $info['wavpack']['blockheader']['block_samples'] = Helper::LittleEndian2Int(substr($wavpackheader, 20, 4));
             $info['wavpack']['blockheader']['flags_raw'] = Helper::LittleEndian2Int(substr($wavpackheader, 24, 4));
             $info['wavpack']['blockheader']['crc'] = Helper::LittleEndian2Int(substr($wavpackheader, 28, 4));
             $info['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($info['wavpack']['blockheader']['flags_raw'] & 0x3);
             $info['wavpack']['blockheader']['flags']['mono'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x4);
             $info['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x8);
             $info['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x10);
             $info['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x20);
             $info['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x40);
             $info['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x80);
             $info['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x100);
             $info['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x200);
             $info['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x400);
             $info['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x800);
             $info['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x1000);
             $info['audio']['lossless'] = !$info['wavpack']['blockheader']['flags']['hybrid'];
         }
         while (!feof($this->getid3->fp) && ftell($this->getid3->fp) < $blockheader_offset + $blockheader_size + 8) {
             $metablock = array('offset' => ftell($this->getid3->fp));
             $metablockheader = fread($this->getid3->fp, 2);
             if (feof($this->getid3->fp)) {
                 break;
             }
             $metablock['id'] = ord($metablockheader[0]);
             $metablock['function_id'] = $metablock['id'] & 0x3f;
             $metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']);
             // The 0x20 bit in the id of the meta subblocks (which is defined as
             // ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that
             // if a decoder encounters an id that it does not know about, it uses
             // that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set
             // then the decoder simply ignores the metadata, but if it is zero
             // then the decoder should quit because it means that an understanding
             // of the metadata is required to correctly decode the audio.
             $metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20);
             $metablock['padded_data'] = (bool) ($metablock['id'] & 0x40);
             $metablock['large_block'] = (bool) ($metablock['id'] & 0x80);
             if ($metablock['large_block']) {
                 $metablockheader .= fread($this->getid3->fp, 2);
             }
             $metablock['size'] = Helper::LittleEndian2Int(substr($metablockheader, 1)) * 2;
             // size is stored in words
             $metablock['data'] = null;
             if ($metablock['size'] > 0) {
                 switch ($metablock['function_id']) {
                     case 0x21:
                         // ID_RIFF_HEADER
                     // ID_RIFF_HEADER
                     case 0x22:
                         // ID_RIFF_TRAILER
                     // ID_RIFF_TRAILER
                     case 0x23:
                         // ID_REPLAY_GAIN
                     // ID_REPLAY_GAIN
                     case 0x24:
                         // ID_CUESHEET
                     // ID_CUESHEET
                     case 0x25:
                         // ID_CONFIG_BLOCK
                     // ID_CONFIG_BLOCK
                     case 0x26:
                         // ID_MD5_CHECKSUM
                         $metablock['data'] = fread($this->getid3->fp, $metablock['size']);
                         if ($metablock['padded_data']) {
                             // padded to the nearest even byte
                             --$metablock['size'];
                             $metablock['data'] = substr($metablock['data'], 0, -1);
                         }
                         break;
                     case 0x0:
                         // ID_DUMMY
                     // ID_DUMMY
                     case 0x1:
                         // ID_ENCODER_INFO
                     // ID_ENCODER_INFO
                     case 0x2:
                         // ID_DECORR_TERMS
                     // ID_DECORR_TERMS
                     case 0x3:
                         // ID_DECORR_WEIGHTS
                     // ID_DECORR_WEIGHTS
                     case 0x4:
                         // ID_DECORR_SAMPLES
                     // ID_DECORR_SAMPLES
                     case 0x5:
                         // ID_ENTROPY_VARS
                     // ID_ENTROPY_VARS
                     case 0x6:
                         // ID_HYBRID_PROFILE
                     // ID_HYBRID_PROFILE
                     case 0x7:
                         // ID_SHAPING_WEIGHTS
                     // ID_SHAPING_WEIGHTS
                     case 0x8:
                         // ID_FLOAT_INFO
                     // ID_FLOAT_INFO
                     case 0x9:
                         // ID_INT32_INFO
                     // ID_INT32_INFO
                     case 0xa:
                         // ID_WV_BITSTREAM
                     // ID_WV_BITSTREAM
                     case 0xb:
                         // ID_WVC_BITSTREAM
                     // ID_WVC_BITSTREAM
                     case 0xc:
                         // ID_WVX_BITSTREAM
                     // ID_WVX_BITSTREAM
                     case 0xd:
                         // ID_CHANNEL_INFO
                         fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
                         break;
                     default:
                         $info['warning'][] = 'Unexpected metablock type "0x' . str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT) . '" at offset ' . $metablock['offset'];
                         fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
                         break;
                 }
                 switch ($metablock['function_id']) {
                     case 0x21:
                         // ID_RIFF_HEADER
                         $original_wav_filesize = Helper::LittleEndian2Int(substr($metablock['data'], 4, 4));
                         $getid3_temp = new GetId3Core();
                         $getid3_temp->openfile($this->getid3->filename);
                         $getid3_riff = new Riff($getid3_temp);
                         $getid3_riff->ParseRIFFdata($metablock['data']);
                         $metablock['riff'] = $getid3_temp->info['riff'];
                         $info['audio']['sample_rate'] = $getid3_temp->info['riff']['raw']['fmt ']['nSamplesPerSec'];
                         unset($getid3_riff, $getid3_temp);
                         $metablock['riff']['original_filesize'] = $original_wav_filesize;
                         $info['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size'];
                         $info['playtime_seconds'] = $info['wavpack']['blockheader']['total_samples'] / $info['audio']['sample_rate'];
                         // Safe RIFF header in case there's a RIFF footer later
                         $metablockRIFFheader = $metablock['data'];
                         break;
                     case 0x22:
                         // ID_RIFF_TRAILER
                         $metablockRIFFfooter = $metablockRIFFheader . $metablock['data'];
                         $startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
                         $getid3_temp = new GetId3Core();
                         $getid3_temp->openfile($this->getid3->filename);
                         $getid3_temp->info['avdataend'] = $info['avdataend'];
                         $getid3_temp->info['fileformat'] = 'riff';
                         $getid3_riff = new Riff($getid3_temp);
                         $metablock['riff'] = $getid3_riff->ParseRIFF($startoffset, $startoffset + $metablock['size']);
                         if (!empty($metablock['riff']['INFO'])) {
                             $getid3_riff->RIFFcommentsParse($metablock['riff']['INFO'], $metablock['comments']);
                             $info['tags']['riff'] = $metablock['comments'];
                         }
                         unset($getid3_temp, $getid3_riff);
                         break;
                     case 0x23:
                         // ID_REPLAY_GAIN
                         $info['warning'][] = 'WavPack "Replay Gain" contents not yet handled by GetId3Core() in metablock at offset ' . $metablock['offset'];
                         break;
                     case 0x24:
                         // ID_CUESHEET
                         $info['warning'][] = 'WavPack "Cuesheet" contents not yet handled by GetId3Core() in metablock at offset ' . $metablock['offset'];
                         break;
                     case 0x25:
                         // ID_CONFIG_BLOCK
                         $metablock['flags_raw'] = Helper::LittleEndian2Int(substr($metablock['data'], 0, 3));
                         $metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x1);
                         // "adobe" mode for 32-bit floats
                         $metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x2);
                         // fast mode
                         $metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x4);
                         // double fast
                         $metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x8);
                         // high quality mode
                         $metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x10);
                         // double high (not used yet)
                         $metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x20);
                         // bitrate is kbps, not bits / sample
                         $metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x40);
                         // automatic noise shaping
                         $metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x80);
                         // shaping mode specified
                         $metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x100);
                         // joint-stereo mode specified
                         $metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x200);
                         // copy file-time from source
                         $metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x400);
                         // create executable
                         $metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x800);
                         // create correction file
                         $metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x1000);
                         // maximize bybrid compression
                         $metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x2000);
                         // psychoacoustic quality mode
                         $metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x4000);
                         // raw mode (not implemented yet)
                         $metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x8000);
                         // calc noise in hybrid mode
                         $metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x10000);
                         // obsolete (for information)
                         $metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x20000);
                         // extra processing mode
                         $metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x40000);
                         // no wvx stream w/ floats & big ints
                         $metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x80000);
                         // compute & store MD5 signature
                         $metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000);
                         // don't report progress %
                         $info['wavpack']['config_flags'] = $metablock['flags'];
                         $info['audio']['encoder_options'] = '';
                         if ($info['wavpack']['blockheader']['flags']['hybrid']) {
                             $info['audio']['encoder_options'] .= ' -b???';
                         }
                         $info['audio']['encoder_options'] .= $metablock['flags']['adobe_mode'] ? ' -a' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['optimize_wvc'] ? ' -cc' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['create_exe'] ? ' -e' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['fast_flag'] ? ' -f' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['joint_override'] ? ' -j?' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['high_flag'] ? ' -h' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['md5_checksum'] ? ' -m' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['calc_noise'] ? ' -n' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['shape_override'] ? ' -s?' : '';
                         $info['audio']['encoder_options'] .= $metablock['flags']['extra_mode'] ? ' -x?' : '';
                         if (!empty($info['audio']['encoder_options'])) {
                             $info['audio']['encoder_options'] = trim($info['audio']['encoder_options']);
                         } elseif (isset($info['audio']['encoder_options'])) {
                             unset($info['audio']['encoder_options']);
                         }
                         break;
                     case 0x26:
                         // ID_MD5_CHECKSUM
                         if (strlen($metablock['data']) == 16) {
                             $info['md5_data_source'] = strtolower(Helper::PrintHexBytes($metablock['data'], true, false, false));
                         } else {
                             $info['warning'][] = 'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset ' . $metablock['offset'] . ', but found ' . strlen($metablock['data']) . ' bytes';
                         }
                         break;
                     case 0x0:
                         // ID_DUMMY
                     // ID_DUMMY
                     case 0x1:
                         // ID_ENCODER_INFO
                     // ID_ENCODER_INFO
                     case 0x2:
                         // ID_DECORR_TERMS
                     // ID_DECORR_TERMS
                     case 0x3:
                         // ID_DECORR_WEIGHTS
                     // ID_DECORR_WEIGHTS
                     case 0x4:
                         // ID_DECORR_SAMPLES
                     // ID_DECORR_SAMPLES
                     case 0x5:
                         // ID_ENTROPY_VARS
                     // ID_ENTROPY_VARS
                     case 0x6:
                         // ID_HYBRID_PROFILE
                     // ID_HYBRID_PROFILE
                     case 0x7:
                         // ID_SHAPING_WEIGHTS
                     // ID_SHAPING_WEIGHTS
                     case 0x8:
                         // ID_FLOAT_INFO
                     // ID_FLOAT_INFO
                     case 0x9:
                         // ID_INT32_INFO
                     // ID_INT32_INFO
                     case 0xa:
                         // ID_WV_BITSTREAM
                     // ID_WV_BITSTREAM
                     case 0xb:
                         // ID_WVC_BITSTREAM
                     // ID_WVC_BITSTREAM
                     case 0xc:
                         // ID_WVX_BITSTREAM
                     // ID_WVX_BITSTREAM
                     case 0xd:
                         // ID_CHANNEL_INFO
                         unset($metablock);
                         break;
                 }
             }
             if (!empty($metablock)) {
                 $info['wavpack']['metablocks'][] = $metablock;
             }
         }
     }
     $info['audio']['encoder'] = 'WavPack v' . $info['wavpack']['blockheader']['major_version'] . '.' . str_pad($info['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT);
     $info['audio']['bits_per_sample'] = $info['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8;
     $info['audio']['channels'] = $info['wavpack']['blockheader']['flags']['mono'] ? 1 : 2;
     if (!empty($info['playtime_seconds'])) {
         $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     } else {
         $info['audio']['dataformat'] = 'wvc';
     }
     return true;
 }
コード例 #30
0
ファイル: Bmp.php プロジェクト: Nattpyre/rocketfiles
 /**
  * @return bool
  */
 public function analyze()
 {
     $info =& $this->getid3->info;
     // shortcuts
     $info['bmp']['header']['raw'] = array();
     $thisfile_bmp =& $info['bmp'];
     $thisfile_bmp_header =& $thisfile_bmp['header'];
     $thisfile_bmp_header_raw =& $thisfile_bmp_header['raw'];
     // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
     // all versions
     // WORD    bfType;
     // DWORD   bfSize;
     // WORD    bfReserved1;
     // WORD    bfReserved2;
     // DWORD   bfOffBits;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $offset = 0;
     $BMPheader = fread($this->getid3->fp, 14 + 40);
     $thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
     $offset += 2;
     $magic = 'BM';
     if ($thisfile_bmp_header_raw['identifier'] != $magic) {
         $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes($thisfile_bmp_header_raw['identifier']) . '"';
         unset($info['fileformat']);
         unset($info['bmp']);
         return false;
     }
     $thisfile_bmp_header_raw['filesize'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
     $offset += 4;
     $thisfile_bmp_header_raw['reserved1'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
     $offset += 2;
     $thisfile_bmp_header_raw['reserved2'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
     $offset += 2;
     $thisfile_bmp_header_raw['data_offset'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
     $offset += 4;
     $thisfile_bmp_header_raw['header_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
     $offset += 4;
     // check if the hardcoded-to-1 "planes" is at offset 22 or 26
     $planes22 = Helper::LittleEndian2Int(substr($BMPheader, 22, 2));
     $planes26 = Helper::LittleEndian2Int(substr($BMPheader, 26, 2));
     if ($planes22 == 1 && $planes26 != 1) {
         $thisfile_bmp['type_os'] = 'OS/2';
         $thisfile_bmp['type_version'] = 1;
     } elseif ($planes26 == 1 && $planes22 != 1) {
         $thisfile_bmp['type_os'] = 'Windows';
         $thisfile_bmp['type_version'] = 1;
     } elseif ($thisfile_bmp_header_raw['header_size'] == 12) {
         $thisfile_bmp['type_os'] = 'OS/2';
         $thisfile_bmp['type_version'] = 1;
     } elseif ($thisfile_bmp_header_raw['header_size'] == 40) {
         $thisfile_bmp['type_os'] = 'Windows';
         $thisfile_bmp['type_version'] = 1;
     } elseif ($thisfile_bmp_header_raw['header_size'] == 84) {
         $thisfile_bmp['type_os'] = 'Windows';
         $thisfile_bmp['type_version'] = 4;
     } elseif ($thisfile_bmp_header_raw['header_size'] == 100) {
         $thisfile_bmp['type_os'] = 'Windows';
         $thisfile_bmp['type_version'] = 5;
     } else {
         $info['error'][] = 'Unknown BMP subtype (or not a BMP file)';
         unset($info['fileformat']);
         unset($info['bmp']);
         return false;
     }
     $info['fileformat'] = 'bmp';
     $info['video']['dataformat'] = 'bmp';
     $info['video']['lossless'] = true;
     $info['video']['pixel_aspect_ratio'] = (double) 1;
     if ($thisfile_bmp['type_os'] == 'OS/2') {
         // OS/2-format BMP
         // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
         // DWORD  Size;             /* Size of this structure in bytes */
         // DWORD  Width;            /* Bitmap width in pixels */
         // DWORD  Height;           /* Bitmap height in pixel */
         // WORD   NumPlanes;        /* Number of bit planes (color depth) */
         // WORD   BitsPerPixel;     /* Number of bits per pixel per plane */
         $thisfile_bmp_header_raw['width'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
         $offset += 2;
         $thisfile_bmp_header_raw['height'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
         $offset += 2;
         $thisfile_bmp_header_raw['planes'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
         $offset += 2;
         $thisfile_bmp_header_raw['bits_per_pixel'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
         $offset += 2;
         $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
         $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
         $info['video']['codec'] = 'BI_RGB ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
         $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
         if ($thisfile_bmp['type_version'] >= 2) {
             // DWORD  Compression;      /* Bitmap compression scheme */
             // DWORD  ImageDataSize;    /* Size of bitmap data in bytes */
             // DWORD  XResolution;      /* X resolution of display device */
             // DWORD  YResolution;      /* Y resolution of display device */
             // DWORD  ColorsUsed;       /* Number of color table indices used */
             // DWORD  ColorsImportant;  /* Number of important color indices */
             // WORD   Units;            /* Type of units used to measure resolution */
             // WORD   Reserved;         /* Pad structure to 4-byte boundary */
             // WORD   Recording;        /* Recording algorithm */
             // WORD   Rendering;        /* Halftoning algorithm used */
             // DWORD  Size1;            /* Reserved for halftoning algorithm use */
             // DWORD  Size2;            /* Reserved for halftoning algorithm use */
             // DWORD  ColorEncoding;    /* Color model used in bitmap */
             // DWORD  Identifier;       /* Reserved for application use */
             $thisfile_bmp_header_raw['compression'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['bmp_data_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['resolution_h'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['resolution_v'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['colors_used'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['colors_important'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['resolution_units'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
             $offset += 2;
             $thisfile_bmp_header_raw['reserved1'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
             $offset += 2;
             $thisfile_bmp_header_raw['recording'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
             $offset += 2;
             $thisfile_bmp_header_raw['rendering'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
             $offset += 2;
             $thisfile_bmp_header_raw['size1'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['size2'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['color_encoding'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['identifier'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']);
             $info['video']['codec'] = $thisfile_bmp_header['compression'] . ' ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
         }
     } elseif ($thisfile_bmp['type_os'] == 'Windows') {
         // Windows-format BMP
         // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
         // all versions
         // DWORD  biSize;
         // LONG   biWidth;
         // LONG   biHeight;
         // WORD   biPlanes;
         // WORD   biBitCount;
         // DWORD  biCompression;
         // DWORD  biSizeImage;
         // LONG   biXPelsPerMeter;
         // LONG   biYPelsPerMeter;
         // DWORD  biClrUsed;
         // DWORD  biClrImportant;
         // possibly integrate this section and module.audio-video.riff.php::ParseBITMAPINFOHEADER() ?
         $thisfile_bmp_header_raw['width'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
         $offset += 4;
         $thisfile_bmp_header_raw['height'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
         $offset += 4;
         $thisfile_bmp_header_raw['planes'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
         $offset += 2;
         $thisfile_bmp_header_raw['bits_per_pixel'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
         $offset += 2;
         $thisfile_bmp_header_raw['compression'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
         $offset += 4;
         $thisfile_bmp_header_raw['bmp_data_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
         $offset += 4;
         $thisfile_bmp_header_raw['resolution_h'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
         $offset += 4;
         $thisfile_bmp_header_raw['resolution_v'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
         $offset += 4;
         $thisfile_bmp_header_raw['colors_used'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
         $offset += 4;
         $thisfile_bmp_header_raw['colors_important'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
         $offset += 4;
         $thisfile_bmp_header['compression'] = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']);
         $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
         $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
         $info['video']['codec'] = $thisfile_bmp_header['compression'] . ' ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
         $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
         if ($thisfile_bmp['type_version'] >= 4 || $thisfile_bmp_header_raw['compression'] == 3) {
             // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
             $BMPheader .= fread($this->getid3->fp, 44);
             // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
             // Win95+, WinNT4.0+
             // DWORD        bV4RedMask;
             // DWORD        bV4GreenMask;
             // DWORD        bV4BlueMask;
             // DWORD        bV4AlphaMask;
             // DWORD        bV4CSType;
             // CIEXYZTRIPLE bV4Endpoints;
             // DWORD        bV4GammaRed;
             // DWORD        bV4GammaGreen;
             // DWORD        bV4GammaBlue;
             $thisfile_bmp_header_raw['red_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['green_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['blue_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['alpha_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['cs_type'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4);
             $offset += 4;
             $thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
             $offset += 4;
             $thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4);
             $offset += 4;
             $thisfile_bmp_header_raw['gamma_red'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['gamma_green'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['gamma_blue'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header['ciexyz_red'] = Helper::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red']));
             $thisfile_bmp_header['ciexyz_green'] = Helper::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green']));
             $thisfile_bmp_header['ciexyz_blue'] = Helper::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue']));
         }
         if ($thisfile_bmp['type_version'] >= 5) {
             $BMPheader .= fread($this->getid3->fp, 16);
             // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
             // Win98+, Win2000+
             // DWORD        bV5Intent;
             // DWORD        bV5ProfileData;
             // DWORD        bV5ProfileSize;
             // DWORD        bV5Reserved;
             $thisfile_bmp_header_raw['intent'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['profile_data_offset'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['profile_data_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
             $thisfile_bmp_header_raw['reserved3'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
             $offset += 4;
         }
     } else {
         $info['error'][] = 'Unknown BMP format in header.';
         return false;
     }
     if ($this->ExtractPalette || $this->ExtractData) {
         $PaletteEntries = 0;
         if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
             $PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']);
         } elseif (isset($thisfile_bmp_header_raw['colors_used']) && $thisfile_bmp_header_raw['colors_used'] > 0 && $thisfile_bmp_header_raw['colors_used'] <= 256) {
             $PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
         }
         if ($PaletteEntries > 0) {
             $BMPpalette = fread($this->getid3->fp, 4 * $PaletteEntries);
             $paletteoffset = 0;
             for ($i = 0; $i < $PaletteEntries; ++$i) {
                 // RGBQUAD          - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
                 // BYTE    rgbBlue;
                 // BYTE    rgbGreen;
                 // BYTE    rgbRed;
                 // BYTE    rgbReserved;
                 $blue = Helper::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                 $green = Helper::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                 $red = Helper::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                 if ($thisfile_bmp['type_os'] == 'OS/2' && $thisfile_bmp['type_version'] == 1) {
                     // no padding byte
                 } else {
                     ++$paletteoffset;
                     // padding byte
                 }
                 $thisfile_bmp['palette'][$i] = $red << 16 | $green << 8 | $blue;
             }
         }
     }
     if ($this->ExtractData) {
         fseek($this->getid3->fp, $thisfile_bmp_header_raw['data_offset'], SEEK_SET);
         $RowByteLength = ceil($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8) / 4) * 4;
         // round up to nearest DWORD boundry
         $BMPpixelData = fread($this->getid3->fp, $thisfile_bmp_header_raw['height'] * $RowByteLength);
         $pixeldataoffset = 0;
         $thisfile_bmp_header_raw['compression'] = isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : '';
         switch ($thisfile_bmp_header_raw['compression']) {
             case 0:
                 // BI_RGB
                 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
                     case 1:
                         for ($row = $thisfile_bmp_header_raw['height'] - 1; $row >= 0; --$row) {
                             for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
                                 $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]);
                                 for ($i = 7; $i >= 0; --$i) {
                                     $paletteindex = ($paletteindexbyte & 0x1 << $i) >> $i;
                                     $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
                                     ++$col;
                                 }
                             }
                             while ($pixeldataoffset % 4 != 0) {
                                 // lines are padded to nearest DWORD
                                 ++$pixeldataoffset;
                             }
                         }
                         break;
                     case 4:
                         for ($row = $thisfile_bmp_header_raw['height'] - 1; $row >= 0; --$row) {
                             for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
                                 $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]);
                                 for ($i = 1; $i >= 0; --$i) {
                                     $paletteindex = ($paletteindexbyte & 0xf << 4 * $i) >> 4 * $i;
                                     $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
                                     ++$col;
                                 }
                             }
                             while ($pixeldataoffset % 4 != 0) {
                                 // lines are padded to nearest DWORD
                                 ++$pixeldataoffset;
                             }
                         }
                         break;
                     case 8:
                         for ($row = $thisfile_bmp_header_raw['height'] - 1; $row >= 0; --$row) {
                             for ($col = 0; $col < $thisfile_bmp_header_raw['width']; ++$col) {
                                 $paletteindex = ord($BMPpixelData[$pixeldataoffset++]);
                                 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
                             }
                             while ($pixeldataoffset % 4 != 0) {
                                 // lines are padded to nearest DWORD
                                 ++$pixeldataoffset;
                             }
                         }
                         break;
                     case 24:
                         for ($row = $thisfile_bmp_header_raw['height'] - 1; $row >= 0; --$row) {
                             for ($col = 0; $col < $thisfile_bmp_header_raw['width']; ++$col) {
                                 $thisfile_bmp['data'][$row][$col] = ord($BMPpixelData[$pixeldataoffset + 2]) << 16 | ord($BMPpixelData[$pixeldataoffset + 1]) << 8 | ord($BMPpixelData[$pixeldataoffset]);
                                 $pixeldataoffset += 3;
                             }
                             while ($pixeldataoffset % 4 != 0) {
                                 // lines are padded to nearest DWORD
                                 ++$pixeldataoffset;
                             }
                         }
                         break;
                     case 32:
                         for ($row = $thisfile_bmp_header_raw['height'] - 1; $row >= 0; --$row) {
                             for ($col = 0; $col < $thisfile_bmp_header_raw['width']; ++$col) {
                                 $thisfile_bmp['data'][$row][$col] = ord($BMPpixelData[$pixeldataoffset + 3]) << 24 | ord($BMPpixelData[$pixeldataoffset + 2]) << 16 | ord($BMPpixelData[$pixeldataoffset + 1]) << 8 | ord($BMPpixelData[$pixeldataoffset]);
                                 $pixeldataoffset += 4;
                             }
                             while ($pixeldataoffset % 4 != 0) {
                                 // lines are padded to nearest DWORD
                                 ++$pixeldataoffset;
                             }
                         }
                         break;
                     case 16:
                         // ?
                         break;
                     default:
                         $info['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
                         break;
                 }
                 break;
             case 1:
                 // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
                 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
                     case 8:
                         $pixelcounter = 0;
                         while ($pixeldataoffset < strlen($BMPpixelData)) {
                             $firstbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                             $secondbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                             if ($firstbyte == 0) {
                                 // escaped/absolute mode - the first byte of the pair can be set to zero to
                                 // indicate an escape character that denotes the end of a line, the end of
                                 // a bitmap, or a delta, depending on the value of the second byte.
                                 switch ($secondbyte) {
                                     case 0:
                                         // end of line
                                         // no need for special processing, just ignore
                                         break;
                                     case 1:
                                         // end of bitmap
                                         $pixeldataoffset = strlen($BMPpixelData);
                                         // force to exit loop just in case
                                         break;
                                     case 2:
                                         // delta - The 2 bytes following the escape contain unsigned values
                                         // indicating the horizontal and vertical offsets of the next pixel
                                         // from the current position.
                                         $colincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                         $rowincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                         $col = $pixelcounter % $thisfile_bmp_header_raw['width'] + $colincrement;
                                         $row = $thisfile_bmp_header_raw['height'] - 1 - ($pixelcounter - $col) / $thisfile_bmp_header_raw['width'] - $rowincrement;
                                         $pixelcounter = $row * $thisfile_bmp_header_raw['width'] + $col;
                                         break;
                                     default:
                                         // In absolute mode, the first byte is zero and the second byte is a
                                         // value in the range 03H through FFH. The second byte represents the
                                         // number of bytes that follow, each of which contains the color index
                                         // of a single pixel. Each run must be aligned on a word boundary.
                                         for ($i = 0; $i < $secondbyte; ++$i) {
                                             $paletteindex = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                             $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
                                             $row = $thisfile_bmp_header_raw['height'] - 1 - ($pixelcounter - $col) / $thisfile_bmp_header_raw['width'];
                                             $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
                                             ++$pixelcounter;
                                         }
                                         while ($pixeldataoffset % 2 != 0) {
                                             // Each run must be aligned on a word boundary.
                                             ++$pixeldataoffset;
                                         }
                                         break;
                                 }
                             } else {
                                 // encoded mode - the first byte specifies the number of consecutive pixels
                                 // to be drawn using the color index contained in the second byte.
                                 for ($i = 0; $i < $firstbyte; ++$i) {
                                     $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
                                     $row = $thisfile_bmp_header_raw['height'] - 1 - ($pixelcounter - $col) / $thisfile_bmp_header_raw['width'];
                                     $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte];
                                     ++$pixelcounter;
                                 }
                             }
                         }
                         break;
                     default:
                         $info['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
                         break;
                 }
                 break;
             case 2:
                 // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
                 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
                     case 4:
                         $pixelcounter = 0;
                         while ($pixeldataoffset < strlen($BMPpixelData)) {
                             $firstbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                             $secondbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                             if ($firstbyte == 0) {
                                 // escaped/absolute mode - the first byte of the pair can be set to zero to
                                 // indicate an escape character that denotes the end of a line, the end of
                                 // a bitmap, or a delta, depending on the value of the second byte.
                                 switch ($secondbyte) {
                                     case 0:
                                         // end of line
                                         // no need for special processing, just ignore
                                         break;
                                     case 1:
                                         // end of bitmap
                                         $pixeldataoffset = strlen($BMPpixelData);
                                         // force to exit loop just in case
                                         break;
                                     case 2:
                                         // delta - The 2 bytes following the escape contain unsigned values
                                         // indicating the horizontal and vertical offsets of the next pixel
                                         // from the current position.
                                         $colincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                         $rowincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                         $col = $pixelcounter % $thisfile_bmp_header_raw['width'] + $colincrement;
                                         $row = $thisfile_bmp_header_raw['height'] - 1 - ($pixelcounter - $col) / $thisfile_bmp_header_raw['width'] - $rowincrement;
                                         $pixelcounter = $row * $thisfile_bmp_header_raw['width'] + $col;
                                         break;
                                     default:
                                         // In absolute mode, the first byte is zero. The second byte contains the number
                                         // of color indexes that follow. Subsequent bytes contain color indexes in their
                                         // high- and low-order 4 bits, one color index for each pixel. In absolute mode,
                                         // each run must be aligned on a word boundary.
                                         unset($paletteindexes);
                                         for ($i = 0; $i < ceil($secondbyte / 2); ++$i) {
                                             $paletteindexbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                             $paletteindexes[] = ($paletteindexbyte & 0xf0) >> 4;
                                             $paletteindexes[] = $paletteindexbyte & 0xf;
                                         }
                                         while ($pixeldataoffset % 2 != 0) {
                                             // Each run must be aligned on a word boundary.
                                             ++$pixeldataoffset;
                                         }
                                         foreach ($paletteindexes as $paletteindex) {
                                             $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
                                             $row = $thisfile_bmp_header_raw['height'] - 1 - ($pixelcounter - $col) / $thisfile_bmp_header_raw['width'];
                                             $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
                                             ++$pixelcounter;
                                         }
                                         break;
                                 }
                             } else {
                                 // encoded mode - the first byte of the pair contains the number of pixels to be
                                 // drawn using the color indexes in the second byte. The second byte contains two
                                 // color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
                                 // The first of the pixels is drawn using the color specified by the high-order
                                 // 4 bits, the second is drawn using the color in the low-order 4 bits, the third
                                 // is drawn using the color in the high-order 4 bits, and so on, until all the
                                 // pixels specified by the first byte have been drawn.
                                 $paletteindexes[0] = ($secondbyte & 0xf0) >> 4;
                                 $paletteindexes[1] = $secondbyte & 0xf;
                                 for ($i = 0; $i < $firstbyte; ++$i) {
                                     $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
                                     $row = $thisfile_bmp_header_raw['height'] - 1 - ($pixelcounter - $col) / $thisfile_bmp_header_raw['width'];
                                     $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[$i % 2]];
                                     ++$pixelcounter;
                                 }
                             }
                         }
                         break;
                     default:
                         $info['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
                         break;
                 }
                 break;
             case 3:
                 // BI_BITFIELDS
                 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
                     case 16:
                     case 32:
                         $redshift = 0;
                         $greenshift = 0;
                         $blueshift = 0;
                         while (($thisfile_bmp_header_raw['red_mask'] >> $redshift & 0x1) == 0) {
                             ++$redshift;
                         }
                         while (($thisfile_bmp_header_raw['green_mask'] >> $greenshift & 0x1) == 0) {
                             ++$greenshift;
                         }
                         while (($thisfile_bmp_header_raw['blue_mask'] >> $blueshift & 0x1) == 0) {
                             ++$blueshift;
                         }
                         for ($row = $thisfile_bmp_header_raw['height'] - 1; $row >= 0; --$row) {
                             for ($col = 0; $col < $thisfile_bmp_header_raw['width']; ++$col) {
                                 $pixelvalue = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8));
                                 $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
                                 $red = intval(round((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift) * 255));
                                 $green = intval(round((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift) * 255));
                                 $blue = intval(round((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) * 255));
                                 $thisfile_bmp['data'][$row][$col] = $red << 16 | $green << 8 | $blue;
                             }
                             while ($pixeldataoffset % 4 != 0) {
                                 // lines are padded to nearest DWORD
                                 ++$pixeldataoffset;
                             }
                         }
                         break;
                     default:
                         $info['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
                         break;
                 }
                 break;
             default:
                 // unhandled compression type
                 $info['error'][] = 'Unknown/unhandled compression type value (' . $thisfile_bmp_header_raw['compression'] . ') - cannot decompress pixel data';
                 break;
         }
     }
     return true;
 }