Beispiel #1
0
 public function DeleteLyrics3()
 {
     // Initialize getID3 engine
     $getID3 = new GetID3();
     $ThisFileInfo = $getID3->analyze($this->filename);
     if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
         if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) {
             flock($fp, LOCK_EX);
             $oldignoreuserabort = ignore_user_abort(true);
             fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end']);
             $DataAfterLyrics3 = '';
             if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) {
                 $DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']);
             }
             ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']);
             if (!empty($DataAfterLyrics3)) {
                 fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start']);
                 fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3));
             }
             flock($fp, LOCK_UN);
             fclose($fp);
             ignore_user_abort($oldignoreuserabort);
             return true;
         } else {
             $this->errors[] = 'Cannot fopen(' . $this->filename . ', "a+b")';
             return false;
         }
     }
     // no Lyrics3 present
     return true;
 }
Beispiel #2
0
 public function saveAttachment($name, $offset, $length, $image_mime = null)
 {
     try {
         // do not extract at all
         if ($this->getid3->option_save_attachments === GetID3::ATTACHMENTS_NONE) {
             $attachment = null;
             // do not set any
             // extract to return array
         } elseif ($this->getid3->option_save_attachments === GetID3::ATTACHMENTS_INLINE) {
             $this->fseek($offset);
             $attachment = $this->fread($length);
             // get whole data in one pass, till it is anyway stored in memory
             if ($attachment === false || strlen($attachment) != $length) {
                 throw new \Exception('failed to read attachment data');
             }
             // assume directory path is given
         } else {
             // set up destination path
             $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
             if (!is_dir($dir) || !is_writable($dir)) {
                 // check supplied directory
                 throw new \Exception('supplied path (' . $dir . ') does not exist, or is not writable');
             }
             $dest = $dir . DIRECTORY_SEPARATOR . $name . ($image_mime ? '.' . Utils::ImageExtFromMime($image_mime) : '');
             // create dest file
             if (($fp_dest = fopen($dest, 'wb')) == false) {
                 throw new \Exception('failed to create file ' . $dest);
             }
             // copy data
             $this->fseek($offset);
             $buffersize = $this->data_string_flag ? $length : $this->getid3->fread_buffer_size();
             $bytesleft = $length;
             while ($bytesleft > 0) {
                 if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || $byteswritten === 0) {
                     throw new \Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space');
                 }
                 $bytesleft -= $byteswritten;
             }
             fclose($fp_dest);
             $attachment = $dest;
         }
     } catch (\Exception $e) {
         // close and remove dest file if created
         if (isset($fp_dest) && is_resource($fp_dest)) {
             fclose($fp_dest);
             unlink($dest);
         }
         // do not set any is case of error
         $attachment = null;
         $this->warning('Failed to extract attachment ' . $name . ': ' . $e->getMessage());
     }
     // seek to the end of attachment
     $this->fseek($offset + $length);
     return $attachment;
 }
Beispiel #3
0
 public function ParseRIFFdata(&$RIFFdata)
 {
     $info =& $this->getid3->info;
     if ($RIFFdata) {
         $tempfile = tempnam(Utils::getTempDirectory(), 'getID3');
         $fp_temp = fopen($tempfile, 'wb');
         $RIFFdataLength = strlen($RIFFdata);
         $NewLengthString = Utils::LittleEndian2String($RIFFdataLength, 4);
         for ($i = 0; $i < 4; $i++) {
             $RIFFdata[$i + 4] = $NewLengthString[$i];
         }
         fwrite($fp_temp, $RIFFdata);
         fclose($fp_temp);
         $getid3_temp = new GetID3();
         $getid3_temp->openfile($tempfile);
         $getid3_temp->info['filesize'] = $RIFFdataLength;
         $getid3_temp->info['filenamepath'] = $info['filenamepath'];
         $getid3_temp->info['tags'] = $info['tags'];
         $getid3_temp->info['warning'] = $info['warning'];
         $getid3_temp->info['error'] = $info['error'];
         $getid3_temp->info['comments'] = $info['comments'];
         $getid3_temp->info['audio'] = isset($info['audio']) ? $info['audio'] : array();
         $getid3_temp->info['video'] = isset($info['video']) ? $info['video'] : array();
         $getid3_riff = new Riff($getid3_temp);
         $getid3_riff->Analyze();
         $info['riff'] = $getid3_temp->info['riff'];
         $info['warning'] = $getid3_temp->info['warning'];
         $info['error'] = $getid3_temp->info['error'];
         $info['tags'] = $getid3_temp->info['tags'];
         $info['comments'] = $getid3_temp->info['comments'];
         unset($getid3_riff, $getid3_temp);
         unlink($tempfile);
     }
     return false;
 }
Beispiel #4
0
 /**
  * analyze file and cache them, if cached pull from the db
  * @param type $filename
  * @return boolean
  */
 public function analyze($filename)
 {
     if (!file_exists($filename)) {
         return false;
     }
     // items to track for caching
     $filetime = filemtime($filename);
     $filesize = filesize($filename);
     // this will be saved for a quick directory lookup of analized files
     // ... why do 50 seperate sql quries when you can do 1 for the same result
     $dirname = dirname($filename);
     // Lookup file
     $db = $this->db;
     $sql = $this->get_id3_data;
     $stmt = $db->prepare($sql);
     $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
     $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
     $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
     $res = $stmt->execute();
     list($result) = $res->fetchArray();
     if (count($result) > 0) {
         return unserialize(base64_decode($result));
     }
     // if it hasn't been analyzed before, then do it now
     $analysis = parent::analyze($filename);
     // Save result
     $sql = $this->cache_file;
     $stmt = $db->prepare($sql);
     $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
     $stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
     $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER);
     $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
     $stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
     $stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
     $res = $stmt->execute();
     return $analysis;
 }
Beispiel #5
0
 public function RemoveReal()
 {
     // File MUST be writeable - CHMOD(646) at least
     if (is_writeable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) {
         // Initialize getID3 engine
         $getID3 = new GetID3();
         $OldThisFileInfo = $getID3->analyze($this->filename);
         if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
             $this->errors[] = 'Cannot remove Real tags from old-style file format';
             fclose($fp_source);
             return false;
         }
         if (empty($OldThisFileInfo['real']['chunks'])) {
             $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file';
             fclose($fp_source);
             return false;
         }
         foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
             $oldChunkInfo[$chunkarray['name']] = $chunkarray;
         }
         if (empty($oldChunkInfo['CONT'])) {
             // no existing CONT chunk
             fclose($fp_source);
             return true;
         }
         $BeforeOffset = $oldChunkInfo['CONT']['offset'];
         $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
         if ($tempfilename = tempnam(Utils::getTempDirectory(), 'getID3')) {
             if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) {
                 rewind($fp_source);
                 fwrite($fp_temp, fread($fp_source, $BeforeOffset));
                 fseek($fp_source, $AfterOffset);
                 while ($buffer = fread($fp_source, $this->fread_buffer_size)) {
                     fwrite($fp_temp, $buffer, strlen($buffer));
                 }
                 fclose($fp_temp);
                 if (copy($tempfilename, $this->filename)) {
                     unlink($tempfilename);
                     fclose($fp_source);
                     return true;
                 }
                 unlink($tempfilename);
                 $this->errors[] = 'FAILED: copy(' . $tempfilename . ', ' . $this->filename . ')';
             } else {
                 $this->errors[] = 'Could not fopen("' . $tempfilename . '", "wb")';
             }
         }
         fclose($fp_source);
         return false;
     }
     $this->errors[] = 'Could not fopen("' . $this->filename . '", "r+b")';
     return false;
 }
Beispiel #6
0
 public function Analyze()
 {
     $info =& $this->getid3->info;
     $this->fseek($info['avdataoffset']);
     $LPACheader = $this->fread(14);
     if (substr($LPACheader, 0, 4) != 'LPAC') {
         $info['error'][] = 'Expected "LPAC" at offset ' . $info['avdataoffset'] . ', found "' . $StreamMarker . '"';
         return false;
     }
     $info['avdataoffset'] += 14;
     $info['fileformat'] = 'lpac';
     $info['audio']['dataformat'] = 'lpac';
     $info['audio']['lossless'] = true;
     $info['audio']['bitrate_mode'] = 'vbr';
     $info['lpac']['file_version'] = Utils::BigEndian2Int(substr($LPACheader, 4, 1));
     $flags['audio_type'] = Utils::BigEndian2Int(substr($LPACheader, 5, 1));
     $info['lpac']['total_samples'] = Utils::BigEndian2Int(substr($LPACheader, 6, 4));
     $flags['parameters'] = Utils::BigEndian2Int(substr($LPACheader, 10, 4));
     $info['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40);
     $info['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x4);
     $info['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x2);
     $info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x1);
     if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) {
         $info['warning'][] = '24-bit and 16-bit flags cannot both be set';
     }
     $info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
     $info['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x8000000);
     $info['lpac']['block_length'] = pow(2, ($flags['parameters'] & 0x7000000) >> 24) * 256;
     $info['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x800000);
     $info['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x400000);
     $info['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x40000);
     $info['lpac']['quantization'] = ($flags['parameters'] & 0x1f00) >> 8;
     $info['lpac']['max_prediction_order'] = $flags['parameters'] & 0x3f;
     if ($info['lpac']['flags']['fast_compress'] && $info['lpac']['max_prediction_order'] != 3) {
         $info['warning'][] = 'max_prediction_order expected to be "3" if fast_compress is true, actual value is "' . $info['lpac']['max_prediction_order'] . '"';
     }
     switch ($info['lpac']['file_version']) {
         case 6:
             if ($info['lpac']['flags']['adaptive_quantization']) {
                 $info['warning'][] = 'adaptive_quantization expected to be false in LPAC file stucture v6, actually true';
             }
             if ($info['lpac']['quantization'] != 20) {
                 $info['warning'][] = 'Quantization expected to be 20 in LPAC file stucture v6, actually ' . $info['lpac']['flags']['Q'];
             }
             break;
         default:
             //$info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org';
             break;
     }
     $getid3_temp = new GetID3();
     $getid3_temp->openfile($this->getid3->filename);
     $getid3_temp->info = $info;
     $getid3_riff = new Riff($getid3_temp);
     $getid3_riff->Analyze();
     $info['avdataoffset'] = $getid3_temp->info['avdataoffset'];
     $info['riff'] = $getid3_temp->info['riff'];
     $info['error'] = $getid3_temp->info['error'];
     $info['warning'] = $getid3_temp->info['warning'];
     $info['lpac']['comments']['comment'] = $getid3_temp->info['comments'];
     $info['audio']['sample_rate'] = $getid3_temp->info['audio']['sample_rate'];
     unset($getid3_temp, $getid3_riff);
     $info['audio']['channels'] = $info['lpac']['flags']['stereo'] ? 2 : 1;
     if ($info['lpac']['flags']['24_bit']) {
         $info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample'];
     } elseif ($info['lpac']['flags']['16_bit']) {
         $info['audio']['bits_per_sample'] = 16;
     } else {
         $info['audio']['bits_per_sample'] = 8;
     }
     if ($info['lpac']['flags']['fast_compress']) {
         // fast
         $info['audio']['encoder_options'] = '-1';
     } else {
         switch ($info['lpac']['max_prediction_order']) {
             case 20:
                 // simple
                 $info['audio']['encoder_options'] = '-2';
                 break;
             case 30:
                 // medium
                 $info['audio']['encoder_options'] = '-3';
                 break;
             case 40:
                 // high
                 $info['audio']['encoder_options'] = '-4';
                 break;
             case 60:
                 // extrahigh
                 $info['audio']['encoder_options'] = '-5';
                 break;
         }
     }
     $info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate'];
     $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
     return true;
 }
Beispiel #7
0
 public function Analyze()
 {
     $info =& $this->getid3->info;
     $this->fseek($info['avdataoffset']);
     while (true) {
         $wavpackheader = $this->fread(32);
         if ($this->ftell() >= $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 = $this->ftell() - 32;
         $blockheader_magic = substr($wavpackheader, 0, 4);
         $blockheader_size = Utils::LittleEndian2Int(substr($wavpackheader, 4, 4));
         $magic = 'wvpk';
         if ($blockheader_magic != $magic) {
             $info['error'][] = 'Expecting "' . Utils::PrintHexBytes($magic) . '" at offset ' . $blockheader_offset . ', found "' . Utils::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'] = Utils::LittleEndian2Int(substr($wavpackheader, 12, 4));
             $info['wavpack']['blockheader']['block_index'] = Utils::LittleEndian2Int(substr($wavpackheader, 16, 4));
             $info['wavpack']['blockheader']['block_samples'] = Utils::LittleEndian2Int(substr($wavpackheader, 20, 4));
             $info['wavpack']['blockheader']['flags_raw'] = Utils::LittleEndian2Int(substr($wavpackheader, 24, 4));
             $info['wavpack']['blockheader']['crc'] = Utils::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) && $this->ftell() < $blockheader_offset + $blockheader_size + 8) {
             $metablock = array('offset' => $this->ftell());
             $metablockheader = $this->fread(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 .= $this->fread(2);
             }
             $metablock['size'] = Utils::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'] = $this->fread($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
                         $this->fseek($metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size']);
                         break;
                     default:
                         $info['warning'][] = 'Unexpected metablock type "0x' . str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT) . '" at offset ' . $metablock['offset'];
                         $this->fseek($metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size']);
                         break;
                 }
                 switch ($metablock['function_id']) {
                     case 0x21:
                         // ID_RIFF_HEADER
                         $original_wav_filesize = Utils::LittleEndian2Int(substr($metablock['data'], 4, 4));
                         $getid3_temp = new GetID3();
                         $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 GetID3();
                         $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'])) {
                             Riff::parseComments($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 getID3() in metablock at offset ' . $metablock['offset'];
                         break;
                     case 0x24:
                         // ID_CUESHEET
                         $info['warning'][] = 'WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset ' . $metablock['offset'];
                         break;
                     case 0x25:
                         // ID_CONFIG_BLOCK
                         $metablock['flags_raw'] = Utils::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(Utils::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;
 }
Beispiel #8
0
 public function analyze($filename)
 {
     if (file_exists($filename)) {
         // Short-hands
         $filetime = filemtime($filename);
         $filesize = filesize($filename);
         // Lookup file
         $SQLquery = 'SELECT `value`';
         $SQLquery .= ' FROM `' . mysql_real_escape_string($this->table) . '`';
         $SQLquery .= ' WHERE (`filename` = \'' . mysql_real_escape_string($filename) . '\')';
         $SQLquery .= '   AND (`filesize` = \'' . mysql_real_escape_string($filesize) . '\')';
         $SQLquery .= '   AND (`filetime` = \'' . mysql_real_escape_string($filetime) . '\')';
         $this->cursor = mysql_query($SQLquery, $this->connection);
         if (mysql_num_rows($this->cursor) > 0) {
             // Hit
             list($result) = mysql_fetch_array($this->cursor);
             return unserialize(base64_decode($result));
         }
     }
     // Miss
     $analysis = parent::analyze($filename);
     // Save result
     if (file_exists($filename)) {
         $SQLquery = 'INSERT INTO `' . mysql_real_escape_string($this->table) . '` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
         $SQLquery .= '\'' . mysql_real_escape_string($filename) . '\'';
         $SQLquery .= ', \'' . mysql_real_escape_string($filesize) . '\'';
         $SQLquery .= ', \'' . mysql_real_escape_string($filetime) . '\'';
         $SQLquery .= ', \'' . mysql_real_escape_string(time()) . '\'';
         $SQLquery .= ', \'' . mysql_real_escape_string(base64_encode(serialize($analysis))) . '\')';
         $this->cursor = mysql_query($SQLquery, $this->connection);
     }
     return $analysis;
 }
Beispiel #9
0
 public function Analyze()
 {
     $info =& $this->getid3->info;
     // http://www.volweb.cz/str/tags.htm
     if (!Utils::intValueSupported($info['filesize'])) {
         $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than ' . round(PHP_INT_MAX / 1073741824) . 'GB';
         return false;
     }
     $this->fseek(0 - 128 - 9 - 6, SEEK_END);
     // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
     $lyrics3_id3v1 = $this->fread(128 + 9 + 6);
     $lyrics3lsz = substr($lyrics3_id3v1, 0, 6);
     // Lyrics3size
     $lyrics3end = substr($lyrics3_id3v1, 6, 9);
     // LYRICSEND or LYRICS200
     $id3v1tag = substr($lyrics3_id3v1, 15, 128);
     // ID3v1
     if ($lyrics3end == 'LYRICSEND') {
         // Lyrics3v1, ID3v1, no APE
         $lyrics3size = 5100;
         $lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
         $lyrics3version = 1;
     } elseif ($lyrics3end == 'LYRICS200') {
         // Lyrics3v2, ID3v1, no APE
         // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
         $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
         $lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
         $lyrics3version = 2;
     } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) {
         // Lyrics3v1, no ID3v1, no APE
         $lyrics3size = 5100;
         $lyrics3offset = $info['filesize'] - $lyrics3size;
         $lyrics3version = 1;
         $lyrics3offset = $info['filesize'] - $lyrics3size;
     } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) {
         // Lyrics3v2, no ID3v1, no APE
         $lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200');
         // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
         $lyrics3offset = $info['filesize'] - $lyrics3size;
         $lyrics3version = 2;
     } else {
         if (isset($info['ape']['tag_offset_start']) && $info['ape']['tag_offset_start'] > 15) {
             $this->fseek($info['ape']['tag_offset_start'] - 15);
             $lyrics3lsz = $this->fread(6);
             $lyrics3end = $this->fread(9);
             if ($lyrics3end == 'LYRICSEND') {
                 // Lyrics3v1, APE, maybe ID3v1
                 $lyrics3size = 5100;
                 $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
                 $info['avdataend'] = $lyrics3offset;
                 $lyrics3version = 1;
                 $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
             } elseif ($lyrics3end == 'LYRICS200') {
                 // Lyrics3v2, APE, maybe ID3v1
                 $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
                 // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
                 $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
                 $lyrics3version = 2;
                 $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
             }
         }
     }
     if (isset($lyrics3offset)) {
         $info['avdataend'] = $lyrics3offset;
         $this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size);
         if (!isset($info['ape'])) {
             if (isset($info['lyrics3']['tag_offset_start'])) {
                 $GETID3_ERRORARRAY =& $info['warning'];
                 $getid3_temp = new GetID3();
                 $getid3_temp->openfile($this->getid3->filename);
                 $getid3_apetag = new ApeTag($getid3_temp);
                 $getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start'];
                 $getid3_apetag->Analyze();
                 if (!empty($getid3_temp->info['ape'])) {
                     $info['ape'] = $getid3_temp->info['ape'];
                 }
                 if (!empty($getid3_temp->info['replay_gain'])) {
                     $info['replay_gain'] = $getid3_temp->info['replay_gain'];
                 }
                 unset($getid3_temp, $getid3_apetag);
             } else {
                 $info['warning'][] = 'Lyrics3 and APE tags appear to have become entangled (most likely due to updating the APE tags with a non-Lyrics3-aware tagger)';
             }
         }
     }
     return true;
 }
Beispiel #10
0
 public function ParseOptimFROGheader45()
 {
     // for fileformat of v4.50a and higher
     $info =& $this->getid3->info;
     $RIFFdata = '';
     $this->fseek($info['avdataoffset']);
     while (!feof($this->getid3->fp) && $this->ftell() < $info['avdataend']) {
         $BlockOffset = $this->ftell();
         $BlockData = $this->fread(8);
         $offset = 8;
         $BlockName = substr($BlockData, 0, 4);
         $BlockSize = Utils::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 .= $this->fread($BlockSize);
                 $thisfile_ofr_thisblock['total_samples'] = Utils::LittleEndian2Int(substr($BlockData, $offset, 6));
                 $offset += 6;
                 $thisfile_ofr_thisblock['raw']['sample_type'] = Utils::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'] = Utils::LittleEndian2Int(substr($BlockData, $offset, 1));
                 $thisfile_ofr_thisblock['channels'] = $thisfile_ofr_thisblock['channel_config'];
                 $offset += 1;
                 $thisfile_ofr_thisblock['sample_rate'] = Utils::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'] = Utils::LittleEndian2Int(substr($BlockData, $offset, 2));
                     $thisfile_ofr_thisblock['encoder'] = $this->OptimFROGencoderNameLookup($thisfile_ofr_thisblock['raw']['encoder_id']);
                     $offset += 2;
                     $thisfile_ofr_thisblock['raw']['compression'] = Utils::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(Utils::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 .= $this->fread(14);
                 $this->fseek($BlockSize - 14, SEEK_CUR);
                 $COMPdata['crc_32'] = Utils::LittleEndian2Int(substr($BlockData, $offset, 4));
                 $offset += 4;
                 $COMPdata['sample_count'] = Utils::LittleEndian2Int(substr($BlockData, $offset, 4));
                 $offset += 4;
                 $COMPdata['raw']['sample_type'] = Utils::LittleEndian2Int(substr($BlockData, $offset, 1));
                 $COMPdata['sample_type'] = $this->OptimFROGsampleTypeLookup($COMPdata['raw']['sample_type']);
                 $offset += 1;
                 $COMPdata['raw']['channel_configuration'] = Utils::LittleEndian2Int(substr($BlockData, $offset, 1));
                 $COMPdata['channel_configuration'] = $this->OptimFROGchannelConfigurationLookup($COMPdata['raw']['channel_configuration']);
                 $offset += 1;
                 $COMPdata['raw']['algorithm_id'] = Utils::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'] = Utils::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 .= $this->fread($BlockSize);
                 break;
             case 'TAIL':
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 if ($BlockSize > 0) {
                     $RIFFdata .= $this->fread($BlockSize);
                 }
                 break;
             case 'RECV':
                 // block contains no useful meta data - simply note and skip
                 $thisfile_ofr_thisblock['offset'] = $BlockOffset;
                 $thisfile_ofr_thisblock['size'] = $BlockSize;
                 $this->fseek($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 getID3()';
                 $this->fseek($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'] = $this->fread($BlockSize);
                     $thisfile_ofr_thisblock['md5_string'] = Utils::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';
                     $this->fseek($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'];
                 $this->fseek($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 GetID3();
     $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;
 }
Beispiel #11
0
 public function analyze($filename)
 {
     if (file_exists($filename)) {
         // Calc key     filename::mod_time::size    - should be unique
         $key = $filename . '::' . filemtime($filename) . '::' . filesize($filename);
         // Loopup key
         $result = dba_fetch($key, $this->dba);
         // Hit
         if ($result !== false) {
             return unserialize($result);
         }
     }
     // Miss
     $result = parent::analyze($filename);
     // Save result
     if (file_exists($filename)) {
         dba_insert($key, serialize($result), $this->dba);
     }
     return $result;
 }
Beispiel #12
0
 public function Analyze()
 {
     $info =& $this->getid3->info;
     $offset = 0;
     $this->fseek($info['avdataoffset']);
     $rawdata = $this->fread($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'] = Utils::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" (' . Utils::PrintHexBytes('WAVE') . ') at offset ' . $offset . ', found "' . $WAVEchunk . '" (' . Utils::PrintHexBytes($WAVEchunk) . ') instead.';
                 return false;
             }
             $offset += 4;
             $info['la']['fmt_size'] = 24;
             if ($info['la']['version'] >= 0.3) {
                 $info['la']['fmt_size'] = Utils::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 " (' . Utils::PrintHexBytes('fmt ') . ') at offset ' . $offset . ', found "' . $fmt_chunk . '" (' . Utils::PrintHexBytes($fmt_chunk) . ') instead.';
                 return false;
             }
             $offset += 4;
             $fmt_size = Utils::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             $info['la']['raw']['format'] = Utils::LittleEndian2Int(substr($rawdata, $offset, 2));
             $offset += 2;
             $info['la']['channels'] = Utils::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'] = Utils::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'] = Utils::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             $info['la']['bytes_per_sample'] = Utils::LittleEndian2Int(substr($rawdata, $offset, 2));
             $offset += 2;
             $info['la']['bits_per_sample'] = Utils::LittleEndian2Int(substr($rawdata, $offset, 2));
             $offset += 2;
             $info['la']['samples'] = Utils::LittleEndian2Int(substr($rawdata, $offset, 4));
             $offset += 4;
             $info['la']['raw']['flags'] = Utils::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'] = Utils::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'][] = Utils::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'] = Utils::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(Utils::getTempDirectory(), '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']) {
                             $this->fseek($info['la']['footerstart']);
                             $RIFFdata .= $this->fread($info['avdataend'] - $info['la']['footerstart']);
                         }
                         $RIFFdata = 'RIFF' . Utils::LittleEndian2String(strlen($RIFFdata), 4, false) . $RIFFdata;
                         fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata));
                         fclose($RIFF_fp);
                         $getid3_temp = new GetID3();
                         $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']['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 getID3() [' . $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;
 }
Beispiel #13
0
 public function HandleBonkTags($BonkTagName)
 {
     $info =& $this->getid3->info;
     switch ($BonkTagName) {
         case 'BONK':
             // shortcut
             $thisfile_bonk_BONK =& $info['bonk']['BONK'];
             $BonkData = "" . 'BONK' . $this->fread(17);
             $thisfile_bonk_BONK['version'] = Utils::LittleEndian2Int(substr($BonkData, 5, 1));
             $thisfile_bonk_BONK['number_samples'] = Utils::LittleEndian2Int(substr($BonkData, 6, 4));
             $thisfile_bonk_BONK['sample_rate'] = Utils::LittleEndian2Int(substr($BonkData, 10, 4));
             $thisfile_bonk_BONK['channels'] = Utils::LittleEndian2Int(substr($BonkData, 14, 1));
             $thisfile_bonk_BONK['lossless'] = (bool) Utils::LittleEndian2Int(substr($BonkData, 15, 1));
             $thisfile_bonk_BONK['joint_stereo'] = (bool) Utils::LittleEndian2Int(substr($BonkData, 16, 1));
             $thisfile_bonk_BONK['number_taps'] = Utils::LittleEndian2Int(substr($BonkData, 17, 2));
             $thisfile_bonk_BONK['downsampling_ratio'] = Utils::LittleEndian2Int(substr($BonkData, 19, 1));
             $thisfile_bonk_BONK['samples_per_packet'] = Utils::LittleEndian2Int(substr($BonkData, 20, 2));
             $info['avdataoffset'] = $thisfile_bonk_BONK['offset'] + 5 + 17;
             $info['avdataend'] = $thisfile_bonk_BONK['offset'] + $thisfile_bonk_BONK['size'];
             $info['fileformat'] = 'bonk';
             $info['audio']['dataformat'] = 'bonk';
             $info['audio']['bitrate_mode'] = 'vbr';
             // assumed
             $info['audio']['channels'] = $thisfile_bonk_BONK['channels'];
             $info['audio']['sample_rate'] = $thisfile_bonk_BONK['sample_rate'];
             $info['audio']['channelmode'] = $thisfile_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo';
             $info['audio']['lossless'] = $thisfile_bonk_BONK['lossless'];
             $info['audio']['codec'] = 'bonk';
             $info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']);
             if ($info['playtime_seconds'] > 0) {
                 $info['audio']['bitrate'] = ($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8 / $info['playtime_seconds'];
             }
             break;
         case 'INFO':
             // shortcut
             $thisfile_bonk_INFO =& $info['bonk']['INFO'];
             $thisfile_bonk_INFO['version'] = Utils::LittleEndian2Int($this->fread(1));
             $thisfile_bonk_INFO['entries_count'] = 0;
             $NextInfoDataPair = $this->fread(5);
             if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
                 while (!feof($this->getid3->fp)) {
                     //$CurrentSeekInfo['offset']  = Utils::LittleEndian2Int(substr($NextInfoDataPair, 0, 4));
                     //$CurrentSeekInfo['nextbit'] = Utils::LittleEndian2Int(substr($NextInfoDataPair, 4, 1));
                     //$thisfile_bonk_INFO[] = $CurrentSeekInfo;
                     $NextInfoDataPair = $this->fread(5);
                     if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
                         $this->fseek(-5, SEEK_CUR);
                         break;
                     }
                     $thisfile_bonk_INFO['entries_count']++;
                 }
             }
             break;
         case 'META':
             $BonkData = "" . 'META' . $this->fread($info['bonk']['META']['size'] - 5);
             $info['bonk']['META']['version'] = Utils::LittleEndian2Int(substr($BonkData, 5, 1));
             $MetaTagEntries = floor((strlen($BonkData) - 8 - 6) / 8);
             // BonkData - xxxxmeta - ØMETA
             $offset = 6;
             for ($i = 0; $i < $MetaTagEntries; $i++) {
                 $MetaEntryTagName = substr($BonkData, $offset, 4);
                 $offset += 4;
                 $MetaEntryTagOffset = Utils::LittleEndian2Int(substr($BonkData, $offset, 4));
                 $offset += 4;
                 $info['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset;
             }
             break;
         case ' ID3':
             $info['audio']['encoder'] = 'Extended BONK v0.9+';
             $getid3_temp = new GetID3();
             $getid3_temp->openfile($this->getid3->filename);
             $getid3_id3v2 = new ID3v2($getid3_temp);
             $getid3_id3v2->StartingOffset = $info['bonk'][' ID3']['offset'] + 2;
             $info['bonk'][' ID3']['valid'] = $getid3_id3v2->Analyze();
             if ($info['bonk'][' ID3']['valid']) {
                 $info['id3v2'] = $getid3_temp->info['id3v2'];
             }
             unset($getid3_temp, $getid3_id3v2);
             break;
         default:
             $info['warning'][] = 'Unexpected Bonk tag "' . $BonkTagName . '" at offset ' . $info['bonk'][$BonkTagName]['offset'];
             break;
     }
 }
Beispiel #14
0
 public function DeleteAPEtag()
 {
     $getID3 = new GetID3();
     $ThisFileInfo = $getID3->analyze($this->filename);
     if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) {
         if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) {
             flock($fp, LOCK_EX);
             $oldignoreuserabort = ignore_user_abort(true);
             fseek($fp, $ThisFileInfo['ape']['tag_offset_end']);
             $DataAfterAPE = '';
             if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) {
                 $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']);
             }
             ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']);
             fseek($fp, $ThisFileInfo['ape']['tag_offset_start']);
             if (!empty($DataAfterAPE)) {
                 fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE));
             }
             flock($fp, LOCK_UN);
             fclose($fp);
             ignore_user_abort($oldignoreuserabort);
             return true;
         }
         return false;
     }
     return true;
 }
Beispiel #15
0
 public function Analyze()
 {
     $info =& $this->getid3->info;
     // parse container
     try {
         $this->parseEBML($info);
     } catch (\Exception $e) {
         $info['error'][] = 'EBML parser: ' . $e->getMessage();
     }
     // calculate playtime
     if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
         foreach ($info['matroska']['info'] as $key => $infoarray) {
             if (isset($infoarray['Duration'])) {
                 // TimecodeScale is how many nanoseconds each Duration unit is
                 $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
                 break;
             }
         }
     }
     // extract tags
     if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
         foreach ($info['matroska']['tags'] as $key => $infoarray) {
             $this->ExtractCommentsSimpleTag($infoarray);
         }
     }
     // process tracks
     if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
         foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
             $track_info = [];
             $track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']);
             $track_info['default'] = isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true;
             if (isset($trackarray['Name'])) {
                 $track_info['name'] = $trackarray['Name'];
             }
             switch ($trackarray['TrackType']) {
                 case 1:
                     // Video
                     $track_info['resolution_x'] = $trackarray['PixelWidth'];
                     $track_info['resolution_y'] = $trackarray['PixelHeight'];
                     $track_info['display_unit'] = self::displayUnit(isset($trackarray['DisplayUnit']) ? $trackarray['DisplayUnit'] : 0);
                     $track_info['display_x'] = isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth'];
                     $track_info['display_y'] = isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight'];
                     if (isset($trackarray['PixelCropBottom'])) {
                         $track_info['crop_bottom'] = $trackarray['PixelCropBottom'];
                     }
                     if (isset($trackarray['PixelCropTop'])) {
                         $track_info['crop_top'] = $trackarray['PixelCropTop'];
                     }
                     if (isset($trackarray['PixelCropLeft'])) {
                         $track_info['crop_left'] = $trackarray['PixelCropLeft'];
                     }
                     if (isset($trackarray['PixelCropRight'])) {
                         $track_info['crop_right'] = $trackarray['PixelCropRight'];
                     }
                     if (isset($trackarray['DefaultDuration'])) {
                         $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3);
                     }
                     if (isset($trackarray['CodecName'])) {
                         $track_info['codec'] = $trackarray['CodecName'];
                     }
                     switch ($trackarray['CodecID']) {
                         case 'V_MS/VFW/FOURCC':
                             $parsed = Riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
                             $track_info['codec'] = Riff::fourccLookup($parsed['fourcc']);
                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
                             break;
                             /*case 'V_MPEG4/ISO/AVC':
                               $h264['profile']    = Utils::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1));
                               $h264['level']      = Utils::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1));
                               $rn                 = Utils::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1));
                               $h264['NALUlength'] = ($rn & 3) + 1;
                               $rn                 = Utils::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1));
                               $nsps               = ($rn & 31);
                               $offset             = 6;
                               for ($i = 0; $i < $nsps; $i ++) {
                                   $length        = Utils::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
                                   $h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
                                   $offset       += 2 + $length;
                               }
                               $npps               = Utils::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1));
                               $offset            += 1;
                               for ($i = 0; $i < $npps; $i ++) {
                                   $length        = Utils::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
                                   $h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
                                   $offset       += 2 + $length;
                               }
                               $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264;
                               break;*/
                     }
                     $info['video']['streams'][] = $track_info;
                     break;
                 case 2:
                     // Audio
                     $track_info['sample_rate'] = isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0;
                     $track_info['channels'] = isset($trackarray['Channels']) ? $trackarray['Channels'] : 1;
                     $track_info['language'] = isset($trackarray['Language']) ? $trackarray['Language'] : 'eng';
                     if (isset($trackarray['BitDepth'])) {
                         $track_info['bits_per_sample'] = $trackarray['BitDepth'];
                     }
                     if (isset($trackarray['CodecName'])) {
                         $track_info['codec'] = $trackarray['CodecName'];
                     }
                     switch ($trackarray['CodecID']) {
                         case 'A_PCM/INT/LIT':
                         case 'A_PCM/INT/BIG':
                             $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
                             break;
                         case 'A_AC3':
                         case 'A_DTS':
                         case 'A_MPEG/L3':
                         case 'A_MPEG/L2':
                         case 'A_FLAC':
                             if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because $info[matroska][track_data_offsets][' . $trackarray['TrackNumber'] . '] not set');
                                 break;
                             }
                             // create temp instance
                             $getid3_temp = new GetID3();
                             if ($track_info['dataformat'] != 'flac') {
                                 $getid3_temp->openfile($this->getid3->filename);
                             }
                             $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                             if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') {
                                 $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
                             }
                             // analyze
                             $class = ucfirst($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']);
                             $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
                             $getid3_audio = new $class($getid3_temp, __CLASS__);
                             if ($track_info['dataformat'] == 'flac') {
                                 $getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
                             } else {
                                 $getid3_audio->Analyze();
                             }
                             if (!empty($getid3_temp->info[$header_data_key])) {
                                 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
                                 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                     foreach ($getid3_temp->info['audio'] as $key => $value) {
                                         $track_info[$key] = $value;
                                     }
                                 }
                             } else {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because ' . $class . '::Analyze() failed at offset ' . $getid3_temp->info['avdataoffset']);
                             }
                             // copy errors and warnings
                             if (!empty($getid3_temp->info['error'])) {
                                 foreach ($getid3_temp->info['error'] as $newerror) {
                                     $this->warning($class . '() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['warning'])) {
                                 foreach ($getid3_temp->info['warning'] as $newerror) {
                                     $this->warning($class . '() says: [' . $newerror . ']');
                                 }
                             }
                             unset($getid3_temp, $getid3_audio);
                             break;
                         case 'A_AAC':
                         case 'A_AAC/MPEG2/LC':
                         case 'A_AAC/MPEG2/LC/SBR':
                         case 'A_AAC/MPEG4/LC':
                         case 'A_AAC/MPEG4/LC/SBR':
                             $this->warning($trackarray['CodecID'] . ' audio data contains no header, audio/video bitrates can\'t be calculated');
                             break;
                         case 'A_VORBIS':
                             if (!isset($trackarray['CodecPrivate'])) {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data not set');
                                 break;
                             }
                             $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1);
                             if ($vorbis_offset === false) {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data does not contain "vorbis" keyword');
                                 break;
                             }
                             $vorbis_offset -= 1;
                             // create temp instance
                             $getid3_temp = new GetID3();
                             // analyze
                             $getid3_ogg = new Ogg($getid3_temp);
                             $oggpageinfo['page_seqno'] = 0;
                             $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
                             if (!empty($getid3_temp->info['ogg'])) {
                                 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
                                 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                     foreach ($getid3_temp->info['audio'] as $key => $value) {
                                         $track_info[$key] = $value;
                                     }
                                 }
                             }
                             // copy errors and warnings
                             if (!empty($getid3_temp->info['error'])) {
                                 foreach ($getid3_temp->info['error'] as $newerror) {
                                     $this->warning('getid3_ogg() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['warning'])) {
                                 foreach ($getid3_temp->info['warning'] as $newerror) {
                                     $this->warning('getid3_ogg() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) {
                                 $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal'];
                             }
                             unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
                             break;
                         case 'A_MS/ACM':
                             $parsed = Riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
                             foreach ($parsed as $key => $value) {
                                 if ($key != 'raw') {
                                     $track_info[$key] = $value;
                                 }
                             }
                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
                             break;
                         default:
                             $this->warning('Unhandled audio type "' . (isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '') . '"');
                     }
                     $info['audio']['streams'][] = $track_info;
                     break;
             }
         }
         if (!empty($info['video']['streams'])) {
             $info['video'] = self::getDefaultStreamInfo($info['video']['streams']);
         }
         if (!empty($info['audio']['streams'])) {
             $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']);
         }
     }
     // process attachments
     if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== GetID3::ATTACHMENTS_NONE) {
         foreach ($info['matroska']['attachments'] as $i => $entry) {
             if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) {
                 $info['matroska']['comments']['picture'][] = ['data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']];
             }
         }
     }
     // determine mime type
     if (!empty($info['video']['streams'])) {
         $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska';
     } elseif (!empty($info['audio']['streams'])) {
         $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska';
     } elseif (isset($info['mime_type'])) {
         unset($info['mime_type']);
     }
     return true;
 }
Beispiel #16
0
 public function setRealFileSize()
 {
     if (PHP_INT_MAX > 2147483647) {
         $this->filesize = filesize($this->filename);
         return true;
     }
     // 32-bit PHP will not return correct values for filesize() if file is >=2GB
     // but getID3->analyze() has workarounds to get actual filesize
     $getID3 = new GetID3();
     $getID3->option_tag_id3v1 = false;
     $getID3->option_tag_id3v2 = false;
     $getID3->option_tag_apetag = false;
     $getID3->option_tags_html = false;
     $getID3->option_extra_info = false;
     $ThisFileInfo = $getID3->analyze($this->filename);
     $this->filesize = $ThisFileInfo['filesize'];
     return true;
 }