/** * * @return boolean */ public function Analyze() { $info =& $this->getid3->info; $info['fileformat'] = 'rar'; if ($this->option_use_rar_extension === true) { if (function_exists('rar_open')) { if ($rp = rar_open($info['filenamepath'])) { $info['rar']['files'] = array(); $entries = rar_list($rp); foreach ($entries as $entry) { $info['rar']['files'] = GetId3_Lib_Helper::array_merge_clobber($info['rar']['files'], GetId3_Lib_Helper::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize())); } rar_close($rp); return true; } else { $info['error'][] = 'failed to rar_open(' . $info['filename'] . ')'; } } else { $info['error'][] = 'RAR support does not appear to be available in this PHP installation'; } } else { $info['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)'; } return false; }
/** * * @return boolean */ 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 "' . GetId3_Lib_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; }
/** * * @return boolean */ 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 "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_Helper::PrintHexBytes(substr($EXEheader, 0, 2)) . '"'; return false; } $info['fileformat'] = 'exe'; $info['exe']['mz']['magic'] = 'MZ'; $info['exe']['mz']['raw']['last_page_size'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 2, 2)); $info['exe']['mz']['raw']['page_count'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 4, 2)); $info['exe']['mz']['raw']['relocation_count'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 6, 2)); $info['exe']['mz']['raw']['header_paragraphs'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 8, 2)); $info['exe']['mz']['raw']['min_memory_paragraphs'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 10, 2)); $info['exe']['mz']['raw']['max_memory_paragraphs'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 12, 2)); $info['exe']['mz']['raw']['initial_ss'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 14, 2)); $info['exe']['mz']['raw']['initial_sp'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 16, 2)); $info['exe']['mz']['raw']['checksum'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 18, 2)); $info['exe']['mz']['raw']['cs_ip'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 20, 4)); $info['exe']['mz']['raw']['relocation_table_offset'] = GetId3_Lib_Helper::LittleEndian2Int(substr($EXEheader, 24, 2)); $info['exe']['mz']['raw']['overlay_number'] = GetId3_Lib_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 GetId3() [' . $this->getid3->version() . ']'; return false; }
/** * * @return boolean */ 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 "' . GetId3_Lib_Helper::PrintHexBytes(substr($SZIPHeader, 0, 4)) . '"'; return false; } $info['fileformat'] = 'szip'; $info['szip']['major_version'] = GetId3_Lib_Helper::BigEndian2Int(substr($SZIPHeader, 4, 1)); $info['szip']['minor_version'] = GetId3_Lib_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 = GetId3_Lib_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'] = GetId3_Lib_Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3)); $BHheaderoffset += 3; $BHdataArray['access_flags'] = GetId3_Lib_Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2)); $BHheaderoffset += 2; $BHdataArray['creation_time'] = GetId3_Lib_Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); $BHheaderoffset += 4; $BHdataArray['modification_time'] = GetId3_Lib_Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); $BHheaderoffset += 4; $BHdataArray['access_time'] = GetId3_Lib_Helper::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); $BHheaderoffset += 4; $info['szip']['BH'][] = $BHdataArray; } break; default: break 2; } } return true; }
/** * * @return boolean */ public function ParseBink() { $info =& $this->getid3->info; $info['fileformat'] = 'bink'; $info['video']['dataformat'] = 'bink'; $fileData = 'BIK' . fread($this->getid3->fp, 13); $info['bink']['data_size'] = GetId3_Lib_Helper::LittleEndian2Int(substr($fileData, 4, 4)); $info['bink']['frame_count'] = GetId3_Lib_Helper::LittleEndian2Int(substr($fileData, 8, 2)); if ($info['avdataend'] - $info['avdataoffset'] != $info['bink']['data_size'] + 8) { $info['error'][] = 'Probably truncated file: expecting ' . $info['bink']['data_size'] . ' bytes, found ' . ($info['avdataend'] - $info['avdataoffset']); } return true; }
/** * * @return boolean */ 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 "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_Helper::PrintHexBytes(substr($RKAUHeader, 0, 3)) . '"'; return false; } $info['fileformat'] = 'rkau'; $info['audio']['dataformat'] = 'rkau'; $info['audio']['bitrate_mode'] = 'vbr'; $info['rkau']['raw']['version'] = GetId3_Lib_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 GetId3() [' . $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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($RKAUHeader, 4, 4)); $info['rkau']['sample_rate'] = GetId3_Lib_Helper::LittleEndian2Int(substr($RKAUHeader, 8, 4)); $info['rkau']['channels'] = GetId3_Lib_Helper::LittleEndian2Int(substr($RKAUHeader, 12, 1)); $info['rkau']['bits_per_sample'] = GetId3_Lib_Helper::LittleEndian2Int(substr($RKAUHeader, 13, 1)); $info['rkau']['raw']['quality'] = GetId3_Lib_Helper::LittleEndian2Int(substr($RKAUHeader, 14, 1)); $this->RKAUqualityLookup($info['rkau']); $info['rkau']['raw']['flags'] = GetId3_Lib_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'] = GetId3_Lib_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; }
/** * * @return boolean */ 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 "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" (".snd") at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_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'] = GetId3_Lib_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'] = GetId3_Lib_Helper::BigEndian2Int(substr($AUheader, 8, 4)); $thisfile_au['data_format_id'] = GetId3_Lib_Helper::BigEndian2Int(substr($AUheader, 12, 4)); $thisfile_au['sample_rate'] = GetId3_Lib_Helper::BigEndian2Int(substr($AUheader, 16, 4)); $thisfile_au['channels'] = GetId3_Lib_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; }
/** * * @staticvar type $shorten_present * @return boolean */ public function Analyze() { $info =& $this->getid3->info; fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); $ShortenHeader = fread($this->getid3->fp, 8); $magic = 'ajkg'; if (substr($ShortenHeader, 0, 4) != $magic) { $info['error'][] = 'Expecting "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_Helper::PrintHexBytes(substr($ShortenHeader, 0, 4)) . '"'; return false; } $info['fileformat'] = 'shn'; $info['audio']['dataformat'] = 'shn'; $info['audio']['lossless'] = true; $info['audio']['bitrate_mode'] = 'vbr'; $info['shn']['version'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ShortenHeader, 4, 1)); fseek($this->getid3->fp, $info['avdataend'] - 12, SEEK_SET); $SeekTableSignatureTest = fread($this->getid3->fp, 12); $info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK'); if ($info['shn']['seektable']['present']) { $info['shn']['seektable']['length'] = GetId3_Lib_Helper::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4)); $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length']; fseek($this->getid3->fp, $info['shn']['seektable']['offset'], SEEK_SET); $SeekTableMagic = fread($this->getid3->fp, 4); $magic = 'SEEK'; if ($SeekTableMagic != $magic) { $info['error'][] = 'Expecting "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['shn']['seektable']['offset'] . ', found "' . GetId3_Lib_Helper::PrintHexBytes($SeekTableMagic) . '"'; return false; } else { // typedef struct tag_TSeekEntry // { // unsigned long SampleNumber; // unsigned long SHNFileByteOffset; // unsigned long SHNLastBufferReadPosition; // unsigned short SHNByteGet; // unsigned short SHNBufferOffset; // unsigned short SHNFileBitOffset; // unsigned long SHNGBuffer; // unsigned short SHNBitShift; // long CBuf0[3]; // long CBuf1[3]; // long Offset0[4]; // long Offset1[4]; // }TSeekEntry; $SeekTableData = fread($this->getid3->fp, $info['shn']['seektable']['length'] - 16); $info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80); //$info['shn']['seektable']['entries'] = array(); //$SeekTableOffset = 0; //for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) { // $SeekTableEntry['sample_number'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_file_byte_offset'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_last_buffer_read_position'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_byte_get'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // $SeekTableEntry['shn_buffer_offset'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // $SeekTableEntry['shn_file_bit_offset'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // $SeekTableEntry['shn_gbuffer'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_bit_shift'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // for ($j = 0; $j < 3; $j++) { // $SeekTableEntry['cbuf0'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // for ($j = 0; $j < 3; $j++) { // $SeekTableEntry['cbuf1'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // for ($j = 0; $j < 4; $j++) { // $SeekTableEntry['offset0'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // for ($j = 0; $j < 4; $j++) { // $SeekTableEntry['offset1'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // // $info['shn']['seektable']['entries'][] = $SeekTableEntry; //} } } if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { $info['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files'; return false; } if (GetId3_GetId3::environmentIsWindows()) { $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe'); foreach ($RequiredFiles as $required_file) { if (!is_readable(GetId3_GetId3::getHelperAppsDir() . $required_file)) { $info['error'][] = GetId3_GetId3::getHelperAppsDir() . $required_file . ' does not exist'; return false; } } $commandline = GetId3_GetId3::getHelperAppsDir() . 'shorten.exe -x "' . $info['filenamepath'] . '" - | ' . GetId3_GetId3::getHelperAppsDir() . 'head.exe -c 64'; $commandline = str_replace('/', '\\', $commandline); } else { static $shorten_present; if (!isset($shorten_present)) { $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`; } if (!$shorten_present) { $info['error'][] = 'shorten binary was not found in path or /usr/local/bin'; return false; } $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '') . 'shorten -x ' . escapeshellarg($info['filenamepath']) . ' - | head -c 64'; } $output = `{$commandline}`; if (!empty($output) && substr($output, 12, 4) == 'fmt ') { $fmt_size = GetId3_Lib_Helper::LittleEndian2Int(substr($output, 16, 4)); $DecodedWAVFORMATEX = GetId3_Module_AudioVideo_Riff::RIFFparseWAVEFORMATex(substr($output, 20, $fmt_size)); $info['audio']['channels'] = $DecodedWAVFORMATEX['channels']; $info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample']; $info['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate']; if (substr($output, 20 + $fmt_size, 4) == 'data') { $info['playtime_seconds'] = GetId3_Lib_Helper::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']; } else { $info['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime'; return false; } $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8; } else { $info['error'][] = 'shorten failed to decode file to WAV for parsing'; return false; } return true; }
public function RemoveID3v1() { // File MUST be writeable - CHMOD(646) at least if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) { $this->setRealFileSize(); if ($this->filesize <= 0 || !GetId3_Lib_Helper::intValueSupported($this->filesize)) { $this->errors[] = 'Unable to RemoveID3v1(' . $this->filename . ') because filesize (' . $this->filesize . ') is larger than ' . round(PHP_INT_MAX / 1073741824) . 'GB'; return false; } if ($fp_source = fopen($this->filename, 'r+b')) { fseek($fp_source, -128, SEEK_END); if (fread($fp_source, 3) == 'TAG') { ftruncate($fp_source, $this->filesize - 128); } else { // no ID3v1 tag to begin with - do nothing } fclose($fp_source); return true; } else { $this->errors[] = 'Could not fopen(' . $this->filename . ', "r+b")'; } } else { $this->errors[] = $this->filename . ' is not writeable'; } return false; }
/** * * @return boolean */ public function ParseMPCsv6() { // this is SV4 - SV6 $info =& $this->getid3->info; $thisfile_mpc_header =& $info['mpc']['header']; $offset = 0; $thisfile_mpc_header['size'] = 8; fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); $MPCheaderData = fread($this->getid3->fp, $thisfile_mpc_header['size']); // add size of file header to avdataoffset - calc bitrate correctly + MD5 data $info['avdataoffset'] += $thisfile_mpc_header['size']; // Most of this code adapted from Jurgen Faul's MPEGplus source code - thanks Jurgen! :) $HeaderDWORD[0] = GetId3_Lib_Helper::LittleEndian2Int(substr($MPCheaderData, 0, 4)); $HeaderDWORD[1] = GetId3_Lib_Helper::LittleEndian2Int(substr($MPCheaderData, 4, 4)); // DDDD DDDD CCCC CCCC BBBB BBBB AAAA AAAA // aaaa aaaa abcd dddd dddd deee eeff ffff // // a = bitrate = anything // b = IS = anything // c = MS = anything // d = streamversion = 0000000004 or 0000000005 or 0000000006 // e = maxband = anything // f = blocksize = 000001 for SV5+, anything(?) for SV4 $thisfile_mpc_header['target_bitrate'] = ($HeaderDWORD[0] & 0xff800000) >> 23; $thisfile_mpc_header['intensity_stereo'] = (bool) (($HeaderDWORD[0] & 0x400000) >> 22); $thisfile_mpc_header['mid_side_stereo'] = (bool) (($HeaderDWORD[0] & 0x200000) >> 21); $thisfile_mpc_header['stream_version_major'] = ($HeaderDWORD[0] & 0x1ff800) >> 11; $thisfile_mpc_header['stream_version_minor'] = 0; // no sub-version numbers before SV7 $thisfile_mpc_header['max_band'] = ($HeaderDWORD[0] & 0x7c0) >> 6; // related to lowpass frequency, not sure how it translates exactly $thisfile_mpc_header['block_size'] = $HeaderDWORD[0] & 0x3f; switch ($thisfile_mpc_header['stream_version_major']) { case 4: $thisfile_mpc_header['frame_count'] = $HeaderDWORD[1] >> 16; break; case 5: case 6: $thisfile_mpc_header['frame_count'] = $HeaderDWORD[1]; break; default: $info['error'] = 'Expecting 4, 5 or 6 in version field, found ' . $thisfile_mpc_header['stream_version_major'] . ' instead'; unset($info['mpc']); return false; break; } if ($thisfile_mpc_header['stream_version_major'] > 4 && $thisfile_mpc_header['block_size'] != 1) { $info['warning'][] = 'Block size expected to be 1, actual value found: ' . $thisfile_mpc_header['block_size']; } $thisfile_mpc_header['sample_rate'] = 44100; // AB: used by all files up to SV7 $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate']; $thisfile_mpc_header['samples'] = $thisfile_mpc_header['frame_count'] * 1152 * $info['audio']['channels']; if ($thisfile_mpc_header['target_bitrate'] == 0) { $info['audio']['bitrate_mode'] = 'vbr'; } else { $info['audio']['bitrate_mode'] = 'cbr'; } $info['mpc']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 * 44100 / $thisfile_mpc_header['frame_count'] / 1152; $info['audio']['bitrate'] = $info['mpc']['bitrate']; $info['audio']['encoder'] = 'SV' . $thisfile_mpc_header['stream_version_major']; return true; }
/** * * @return boolean */ 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 "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($GIFheader, $offset, 2)); $offset += 2; $info['gif']['header']['raw']['height'] = GetId3_Lib_Helper::LittleEndian2Int(substr($GIFheader, $offset, 2)); $offset += 2; $info['gif']['header']['raw']['flags'] = GetId3_Lib_Helper::LittleEndian2Int(substr($GIFheader, $offset, 1)); $offset += 1; $info['gif']['header']['raw']['bg_color_index'] = GetId3_Lib_Helper::LittleEndian2Int(substr($GIFheader, $offset, 1)); $offset += 1; $info['gif']['header']['raw']['aspect_ratio'] = GetId3_Lib_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 GetId3() 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; }
/** * * @return boolean */ public function Analyze() { $info =& $this->getid3->info; fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); $LPACheader = fread($this->getid3->fp, 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'] = GetId3_Lib_Helper::BigEndian2Int(substr($LPACheader, 4, 1)); $flags['audio_type'] = GetId3_Lib_Helper::BigEndian2Int(substr($LPACheader, 5, 1)); $info['lpac']['total_samples'] = GetId3_Lib_Helper::BigEndian2Int(substr($LPACheader, 6, 4)); $flags['parameters'] = GetId3_Lib_Helper::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(); $getid3_temp->openfile($this->getid3->filename); $getid3_temp->info = $info; $getid3_riff = new GetId3_Module_AudioVideo_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; }
/** * * @return boolean */ 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'] = GetId3_Lib_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" (' . GetId3_Lib_Helper::PrintHexBytes('WAVE') . ') at offset ' . $offset . ', found "' . $WAVEchunk . '" (' . GetId3_Lib_Helper::PrintHexBytes($WAVEchunk) . ') instead.'; return false; } $offset += 4; $info['la']['fmt_size'] = 24; if ($info['la']['version'] >= 0.3) { $info['la']['fmt_size'] = GetId3_Lib_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 " (' . GetId3_Lib_Helper::PrintHexBytes('fmt ') . ') at offset ' . $offset . ', found "' . $fmt_chunk . '" (' . GetId3_Lib_Helper::PrintHexBytes($fmt_chunk) . ') instead.'; return false; } $offset += 4; $fmt_size = GetId3_Lib_Helper::LittleEndian2Int(substr($rawdata, $offset, 4)); $offset += 4; $info['la']['raw']['format'] = GetId3_Lib_Helper::LittleEndian2Int(substr($rawdata, $offset, 2)); $offset += 2; $info['la']['channels'] = GetId3_Lib_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'] = GetId3_Lib_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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($rawdata, $offset, 4)); $offset += 4; $info['la']['bytes_per_sample'] = GetId3_Lib_Helper::LittleEndian2Int(substr($rawdata, $offset, 2)); $offset += 2; $info['la']['bits_per_sample'] = GetId3_Lib_Helper::LittleEndian2Int(substr($rawdata, $offset, 2)); $offset += 2; $info['la']['samples'] = GetId3_Lib_Helper::LittleEndian2Int(substr($rawdata, $offset, 4)); $offset += 4; $info['la']['raw']['flags'] = GetId3_Lib_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'] = GetId3_Lib_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'][] = GetId3_Lib_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'] = GetId3_Lib_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(GetId3_GetId3::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' . GetId3_Lib_Helper::LittleEndian2String(strlen($RIFFdata), 4, false) . $RIFFdata; fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata)); fclose($RIFF_fp); $getid3_temp = new GetId3_GetId3(); $getid3_temp->openfile($RIFFtempfilename); $getid3_riff = new GetId3_Module_AudioVideo_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 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; }
/** * * @return boolean */ 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'] = GetId3_Lib_Helper::BigEndian2Int(substr($FLVheader, 3, 1)); $TypeFlags = GetId3_Lib_Helper::BigEndian2Int(substr($FLVheader, 4, 1)); $magic = 'FLV'; if ($info['flv']['header']['signature'] != $magic) { $info['error'][] = 'Expecting "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_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 = GetId3_Lib_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 = GetId3_Lib_Helper::BigEndian2Int(substr($ThisTagHeader, 0, 4)); $TagType = GetId3_Lib_Helper::BigEndian2Int(substr($ThisTagHeader, 4, 1)); $DataLength = GetId3_Lib_Helper::BigEndian2Int(substr($ThisTagHeader, 5, 3)); $Timestamp = GetId3_Lib_Helper::BigEndian2Int(substr($ThisTagHeader, 8, 3)); $LastHeaderByte = GetId3_Lib_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 = GetId3_Lib_Helper::BigEndian2Int(substr($FLVvideoHeader, 0, 1)); if ($AVCPacketType == GetId3_Module_AudioVideo_AVCSequenceParameterSetReader::H264_AVC_SEQUENCE_HEADER) { // read AVCDecoderConfigurationRecord $configurationVersion = GetId3_Lib_Helper::BigEndian2Int(substr($FLVvideoHeader, 4, 1)); $AVCProfileIndication = GetId3_Lib_Helper::BigEndian2Int(substr($FLVvideoHeader, 5, 1)); $profile_compatibility = GetId3_Lib_Helper::BigEndian2Int(substr($FLVvideoHeader, 6, 1)); $lengthSizeMinusOne = GetId3_Lib_Helper::BigEndian2Int(substr($FLVvideoHeader, 7, 1)); $numOfSequenceParameterSets = GetId3_Lib_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 = GetId3_Lib_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 GetId3_Module_AudioVideo_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 = GetId3_Lib_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'] = GetId3_Lib_Helper::BigEndian2Int(substr($FLVvideoHeader, 4, 2)); $PictureSizeEnc['y'] = GetId3_Lib_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'] = GetId3_Lib_Helper::BigEndian2Int(substr($FLVvideoHeader, 4, 3)); $PictureSizeEnc['y'] = GetId3_Lib_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 GetId3_Module_AudioVideo_AMFStream($datachunk); $reader = new GetId3_Module_AudioVideo_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] = GetId3_Lib_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; }
public function Analyze() { $info =& $this->getid3->info; // http://cui.unige.ch/OSG/info/AudioFormats/ap11.html // http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html // offset type length name comments // --------------------------------------------------------------------- // 0 char 4 ID format ID == "2BIT" // 4 char 8 name sample name (unused space filled with 0) // 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo // With stereo, samples are alternated, // the first voice is the left : // (LRLRLRLRLRLRLRLRLR...) // 14 short 1 resolution 8, 12 or 16 (bits) // 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed // 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on // 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127 // 0xFFFF means "no MIDI note defined" // 22 byte 1 Replay speed Frequence in the Replay software // 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz, // 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz // 6=43.885 Khz, 7=47.261 Khz // -1 (0xFF)=no defined Frequence // 23 byte 3 sample rate in Hertz // 26 long 1 size in bytes (2 * bytes in stereo) // 30 long 1 loop begin 0 for no loop // 34 long 1 loop size equal to 'size' for no loop // 38 short 2 Reserved, MIDI keyboard split */ // 40 short 2 Reserved, sample compression */ // 42 short 2 Reserved */ // 44 char 20; Additional filename space, used if (name[7] != 0) // 64 byte 64 user data // 128 bytes ? sample data (12 bits samples are coded on 16 bits: // 0000 xxxx xxxx xxxx) // --------------------------------------------------------------------- // Note that all values are in motorola (big-endian) format, and that long is // assumed to be 4 bytes, and short 2 bytes. // When reading the samples, you should handle both signed and unsigned data, // and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert // 8-bit data between signed/unsigned just add 127 to the sample values. // Simularly for 16-bit data you should add 32769 $info['fileformat'] = 'avr'; fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); $AVRheader = fread($this->getid3->fp, 128); $info['avr']['raw']['magic'] = substr($AVRheader, 0, 4); $magic = '2BIT'; if ($info['avr']['raw']['magic'] != $magic) { $info['error'][] = 'Expecting "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_Helper::PrintHexBytes($info['avr']['raw']['magic']) . '"'; unset($info['fileformat']); unset($info['avr']); return false; } $info['avdataoffset'] += 128; $info['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8)); $info['avr']['raw']['mono'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 12, 2)); $info['avr']['bits_per_sample'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 14, 2)); $info['avr']['raw']['signed'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 16, 2)); $info['avr']['raw']['loop'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 18, 2)); $info['avr']['raw']['midi'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 20, 2)); $info['avr']['raw']['replay_freq'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 22, 1)); $info['avr']['sample_rate'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 23, 3)); $info['avr']['sample_length'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 26, 4)); $info['avr']['loop_start'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 30, 4)); $info['avr']['loop_end'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 34, 4)); $info['avr']['midi_split'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 38, 2)); $info['avr']['sample_compression'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 40, 2)); $info['avr']['reserved'] = GetId3_Lib_Helper::BigEndian2Int(substr($AVRheader, 42, 2)); $info['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20)); $info['avr']['comment'] = rtrim(substr($AVRheader, 64, 64)); $info['avr']['flags']['stereo'] = $info['avr']['raw']['mono'] == 0 ? false : true; $info['avr']['flags']['signed'] = $info['avr']['raw']['signed'] == 0 ? false : true; $info['avr']['flags']['loop'] = $info['avr']['raw']['loop'] == 0 ? false : true; $info['avr']['midi_notes'] = array(); if (($info['avr']['raw']['midi'] & 0xff00) != 0xff00) { $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xff00) >> 8; } if (($info['avr']['raw']['midi'] & 0xff) != 0xff) { $info['avr']['midi_notes'][] = $info['avr']['raw']['midi'] & 0xff; } if ($info['avdataend'] - $info['avdataoffset'] != $info['avr']['sample_length'] * ($info['avr']['bits_per_sample'] == 8 ? 1 : 2)) { $info['warning'][] = 'Probable truncated file: expecting ' . $info['avr']['sample_length'] * ($info['avr']['bits_per_sample'] == 8 ? 1 : 2) . ' bytes of audio data, found ' . ($info['avdataend'] - $info['avdataoffset']); } $info['audio']['dataformat'] = 'avr'; $info['audio']['lossless'] = true; $info['audio']['bitrate_mode'] = 'cbr'; $info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample']; $info['audio']['sample_rate'] = $info['avr']['sample_rate']; $info['audio']['channels'] = $info['avr']['flags']['stereo'] ? 2 : 1; $info['playtime_seconds'] = $info['avr']['sample_length'] / $info['audio']['channels'] / $info['avr']['sample_rate']; $info['audio']['bitrate'] = $info['avr']['sample_length'] * ($info['avr']['bits_per_sample'] == 8 ? 8 : 16) / $info['playtime_seconds']; return true; }
/** * * @return string */ public function GenerateCONTchunk() { foreach ($this->tag_data as $key => $value) { // limit each value to 0xFFFF bytes $this->tag_data[$key] = substr($value, 0, 65535); } $CONTchunk = ""; // object version $CONTchunk .= GetId3_Lib_Helper::BigEndian2String(!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : 0, 2); $CONTchunk .= !empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : ''; $CONTchunk .= GetId3_Lib_Helper::BigEndian2String(!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : 0, 2); $CONTchunk .= !empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : ''; $CONTchunk .= GetId3_Lib_Helper::BigEndian2String(!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : 0, 2); $CONTchunk .= !empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : ''; $CONTchunk .= GetId3_Lib_Helper::BigEndian2String(!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : 0, 2); $CONTchunk .= !empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : ''; if ($this->paddedlength > strlen($CONTchunk) + 8) { $CONTchunk .= str_repeat("", $this->paddedlength - strlen($CONTchunk) - 8); } $CONTchunk = 'CONT' . GetId3_Lib_Helper::BigEndian2String(strlen($CONTchunk) + 8, 4) . $CONTchunk; // CONT chunk identifier + chunk length return $CONTchunk; }
/** * * @staticvar array $decbin * @param type $MaxFramesToScan * @param type $ReturnExtendedInfo * @return boolean */ public function getAACADTSheaderFilepointer($MaxFramesToScan = 1000000, $ReturnExtendedInfo = false) { $info =& $this->getid3->info; // based loosely on code from AACfile by Jurgen Faul <jfaulØgmx.de> // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html // http://faac.sourceforge.net/wiki/index.php?page=ADTS // dead link // http://wiki.multimedia.cx/index.php?title=ADTS // * ADTS Fixed Header: these don't change from frame to frame // syncword 12 always: '111111111111' // ID 1 0: MPEG-4, 1: MPEG-2 // MPEG layer 2 If you send AAC in MPEG-TS, set to 0 // protection_absent 1 0: CRC present; 1: no CRC // profile 2 0: AAC Main; 1: AAC LC (Low Complexity); 2: AAC SSR (Scalable Sample Rate); 3: AAC LTP (Long Term Prediction) // sampling_frequency_index 4 15 not allowed // private_bit 1 usually 0 // channel_configuration 3 // original/copy 1 0: original; 1: copy // home 1 usually 0 // emphasis 2 only if ID == 0 (ie MPEG-4) // not present in some documentation? // * ADTS Variable Header: these can change from frame to frame // copyright_identification_bit 1 // copyright_identification_start 1 // aac_frame_length 13 length of the frame including header (in bytes) // adts_buffer_fullness 11 0x7FF indicates VBR // no_raw_data_blocks_in_frame 2 // * ADTS Error check // crc_check 16 only if protection_absent == 0 $byteoffset = $info['avdataoffset']; $framenumber = 0; // Init bit pattern array static $decbin = array(); // Populate $bindec for ($i = 0; $i < 256; $i++) { $decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); } // used to calculate bitrate below $BitrateCache = array(); while (true) { // breaks out when end-of-file encountered, or invalid data found, // or MaxFramesToScan frames have been scanned if (!GetId3_Lib_Helper::intValueSupported($byteoffset)) { $info['warning'][] = 'Unable to parse AAC file beyond ' . ftell($this->getid3->fp) . ' (PHP does not support file operations beyond ' . round(PHP_INT_MAX / 1073741824) . 'GB)'; return false; } fseek($this->getid3->fp, $byteoffset, SEEK_SET); // First get substring $substring = fread($this->getid3->fp, 9); // header is 7 bytes (or 9 if CRC is present) $substringlength = strlen($substring); if ($substringlength != 9) { $info['error'][] = 'Failed to read 7 bytes at offset ' . (ftell($this->getid3->fp) - $substringlength) . ' (only read ' . $substringlength . ' bytes)'; return false; } // this would be easier with 64-bit math, but split it up to allow for 32-bit: $header1 = GetId3_Lib_Helper::BigEndian2Int(substr($substring, 0, 2)); $header2 = GetId3_Lib_Helper::BigEndian2Int(substr($substring, 2, 4)); $header3 = GetId3_Lib_Helper::BigEndian2Int(substr($substring, 6, 1)); $info['aac']['header']['raw']['syncword'] = ($header1 & 0xfff0) >> 4; if ($info['aac']['header']['raw']['syncword'] != 0xfff) { $info['error'][] = 'Synch pattern (0x0FFF) not found at offset ' . (ftell($this->getid3->fp) - $substringlength) . ' (found 0x0' . strtoupper(dechex($info['aac']['header']['raw']['syncword'])) . ' instead)'; //if ($info['fileformat'] == 'aac') { // return true; //} unset($info['aac']); return false; } // Gather info for first frame only - this takes time to do 1000 times! if ($framenumber == 0) { $info['aac']['header_type'] = 'ADTS'; $info['fileformat'] = 'aac'; $info['audio']['dataformat'] = 'aac'; $info['aac']['header']['raw']['mpeg_version'] = ($header1 & 0x8) >> 3; $info['aac']['header']['raw']['mpeg_layer'] = ($header1 & 0x6) >> 1; $info['aac']['header']['raw']['protection_absent'] = ($header1 & 0x1) >> 0; $info['aac']['header']['raw']['profile_code'] = ($header2 & 0xc0000000) >> 30; $info['aac']['header']['raw']['sample_rate_code'] = ($header2 & 0x3c000000) >> 26; $info['aac']['header']['raw']['private_stream'] = ($header2 & 0x2000000) >> 25; $info['aac']['header']['raw']['channels_code'] = ($header2 & 0x1c00000) >> 22; $info['aac']['header']['raw']['original'] = ($header2 & 0x200000) >> 21; $info['aac']['header']['raw']['home'] = ($header2 & 0x100000) >> 20; $info['aac']['header']['raw']['copyright_stream'] = ($header2 & 0x80000) >> 19; $info['aac']['header']['raw']['copyright_start'] = ($header2 & 0x40000) >> 18; $info['aac']['header']['raw']['frame_length'] = ($header2 & 0x3ffe0) >> 5; $info['aac']['header']['mpeg_version'] = $info['aac']['header']['raw']['mpeg_version'] ? 2 : 4; $info['aac']['header']['crc_present'] = $info['aac']['header']['raw']['protection_absent'] ? false : true; $info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['header']['raw']['profile_code'], $info['aac']['header']['mpeg_version']); $info['aac']['header']['sample_frequency'] = self::AACsampleRateLookup($info['aac']['header']['raw']['sample_rate_code']); $info['aac']['header']['private'] = (bool) $info['aac']['header']['raw']['private_stream']; $info['aac']['header']['original'] = (bool) $info['aac']['header']['raw']['original']; $info['aac']['header']['home'] = (bool) $info['aac']['header']['raw']['home']; $info['aac']['header']['channels'] = $info['aac']['header']['raw']['channels_code'] == 7 ? 8 : $info['aac']['header']['raw']['channels_code']; if ($ReturnExtendedInfo) { $info['aac'][$framenumber]['copyright_id_bit'] = (bool) $info['aac']['header']['raw']['copyright_stream']; $info['aac'][$framenumber]['copyright_id_start'] = (bool) $info['aac']['header']['raw']['copyright_start']; } if ($info['aac']['header']['raw']['mpeg_layer'] != 0) { $info['warning'][] = 'Layer error - expected "0", found "' . $info['aac']['header']['raw']['mpeg_layer'] . '" instead'; } if ($info['aac']['header']['sample_frequency'] == 0) { $info['error'][] = 'Corrupt AAC file: sample_frequency == zero'; return false; } $info['audio']['sample_rate'] = $info['aac']['header']['sample_frequency']; $info['audio']['channels'] = $info['aac']['header']['channels']; } $FrameLength = ($header2 & 0x3ffe0) >> 5; if (!isset($BitrateCache[$FrameLength])) { $BitrateCache[$FrameLength] = $info['aac']['header']['sample_frequency'] / 1024 * $FrameLength * 8; } GetId3_Lib_Helper::safe_inc($info['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]], 1); $info['aac'][$framenumber]['aac_frame_length'] = $FrameLength; $info['aac'][$framenumber]['adts_buffer_fullness'] = ($header2 & 0x1f) << 6 & ($header3 & 0xfc) >> 2; if ($info['aac'][$framenumber]['adts_buffer_fullness'] == 0x7ff) { $info['audio']['bitrate_mode'] = 'vbr'; } else { $info['audio']['bitrate_mode'] = 'cbr'; } $info['aac'][$framenumber]['num_raw_data_blocks'] = ($header3 & 0x3) >> 0; if ($info['aac']['header']['crc_present']) { //$info['aac'][$framenumber]['crc'] = GetId3_lib::BigEndian2Int(substr($substring, 7, 2); } if (!$ReturnExtendedInfo) { unset($info['aac'][$framenumber]); } /* $rounded_precision = 5000; $info['aac']['bitrate_distribution_rounded'] = array(); foreach ($info['aac']['bitrate_distribution'] as $bitrate => $count) { $rounded_bitrate = round($bitrate / $rounded_precision) * $rounded_precision; getid3_lib::safe_inc($info['aac']['bitrate_distribution_rounded'][$rounded_bitrate], $count); } ksort($info['aac']['bitrate_distribution_rounded']); */ $byteoffset += $FrameLength; if (++$framenumber < $MaxFramesToScan && $byteoffset + 10 < $info['avdataend']) { // keep scanning } else { $info['aac']['frames'] = $framenumber; $info['playtime_seconds'] = $info['avdataend'] / $byteoffset * ($framenumber * 1024 / $info['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds if ($info['playtime_seconds'] == 0) { $info['error'][] = 'Corrupt AAC file: playtime_seconds == zero'; return false; } $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds']; ksort($info['aac']['bitrate_distribution']); $info['audio']['encoder_options'] = $info['aac']['header_type'] . ' ' . $info['aac']['header']['profile']; return true; } } // should never get here. }
/** * * @return boolean */ public function ZIPparseEndOfCentralDirectory() { $EndOfCentralDirectory['offset'] = ftell($this->getid3->fp); $ZIPendOfCentralDirectory = fread($this->getid3->fp, 22); $EndOfCentralDirectory['signature'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4)); if ($EndOfCentralDirectory['signature'] != 0x6054b50) { // invalid End Of Central Directory Signature fseek($this->getid3->fp, $EndOfCentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly return false; } $EndOfCentralDirectory['disk_number_current'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 4, 2)); $EndOfCentralDirectory['disk_number_start_directory'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 6, 2)); $EndOfCentralDirectory['directory_entries_this_disk'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 8, 2)); $EndOfCentralDirectory['directory_entries_total'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 10, 2)); $EndOfCentralDirectory['directory_size'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 12, 4)); $EndOfCentralDirectory['directory_offset'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 16, 4)); $EndOfCentralDirectory['comment_length'] = GetId3_Lib_Helper::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 20, 2)); if ($EndOfCentralDirectory['comment_length'] > 0) { $EndOfCentralDirectory['comment'] = fread($this->getid3->fp, $EndOfCentralDirectory['comment_length']); } return $EndOfCentralDirectory; }
/** * * @param type $items * @param type $isheader * @return type */ public function GenerateAPEtagHeaderFooter(&$items, $isheader = false) { $tagdatalength = 0; foreach ($items as $itemdata) { $tagdatalength += strlen($itemdata); } $APEheader = 'APETAGEX'; $APEheader .= GetId3_Lib_Helper::LittleEndian2String(2000, 4); $APEheader .= GetId3_Lib_Helper::LittleEndian2String(32 + $tagdatalength, 4); $APEheader .= GetId3_Lib_Helper::LittleEndian2String(count($items), 4); $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false); $APEheader .= str_repeat("", 8); return $APEheader; }
/** * * @return boolean */ public function CalculateReplayGain() { if (isset($this->info['replay_gain'])) { if (!isset($this->info['replay_gain']['reference_volume'])) { $this->info['replay_gain']['reference_volume'] = (double) 89.0; } if (isset($this->info['replay_gain']['track']['adjustment'])) { $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; } if (isset($this->info['replay_gain']['album']['adjustment'])) { $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; } if (isset($this->info['replay_gain']['track']['peak'])) { $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - GetId3_Lib_Helper::RGADamplitude2dB($this->info['replay_gain']['track']['peak']); } if (isset($this->info['replay_gain']['album']['peak'])) { $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - GetId3_Lib_Helper::RGADamplitude2dB($this->info['replay_gain']['album']['peak']); } } return true; }
/** * * @param type $byteword * @param type $signed * @return type */ public function EitherEndian2Int($byteword, $signed = false) { if ($this->getid3->info['fileformat'] == 'riff') { return GetId3_Lib_Helper::LittleEndian2Int($byteword, $signed); } return GetId3_Lib_Helper::BigEndian2Int($byteword, false, $signed); }
/** * * @param type $EBMLstring * @return type * @link http://matroska.org/specs/ */ private static function EBML2Int($EBMLstring) { // Element ID coded with an UTF-8 like system: // 1xxx xxxx - Class A IDs (2^7 -2 possible values) (base 0x8X) // 01xx xxxx xxxx xxxx - Class B IDs (2^14-2 possible values) (base 0x4X 0xXX) // 001x xxxx xxxx xxxx xxxx xxxx - Class C IDs (2^21-2 possible values) (base 0x2X 0xXX 0xXX) // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - Class D IDs (2^28-2 possible values) (base 0x1X 0xXX 0xXX 0xXX) // Values with all x at 0 and 1 are reserved (hence the -2). // Data size, in octets, is also coded with an UTF-8 like system : // 1xxx xxxx - value 0 to 2^7-2 // 01xx xxxx xxxx xxxx - value 0 to 2^14-2 // 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2 // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2 // 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2 // 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2 // 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2 // 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2 $first_byte_int = ord($EBMLstring[0]); if (0x80 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0x7f); } elseif (0x40 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0x3f); } elseif (0x20 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0x1f); } elseif (0x10 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0xf); } elseif (0x8 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0x7); } elseif (0x4 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0x3); } elseif (0x2 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0x1); } elseif (0x1 & $first_byte_int) { $EBMLstring[0] = chr($first_byte_int & 0x0); } return GetId3_Lib_Helper::BigEndian2Int($EBMLstring); }
/** * * @return type */ public function readDouble() { return GetId3_Lib_Helper::BigEndian2Float($this->read(8)); }
/** * * @param type $endoffset * @param type $version * @param type $length * @return boolean * @link http://www.volweb.cz/str/tags.htm */ public function getLyrics3Data($endoffset, $version, $length) { $info =& $this->getid3->info; if (!GetId3_Lib_Helper::intValueSupported($endoffset)) { $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than ' . round(PHP_INT_MAX / 1073741824) . 'GB'; return false; } fseek($this->getid3->fp, $endoffset, SEEK_SET); if ($length <= 0) { return false; } $rawdata = fread($this->getid3->fp, $length); $ParsedLyrics3['raw']['lyrics3version'] = $version; $ParsedLyrics3['raw']['lyrics3tagsize'] = $length; $ParsedLyrics3['tag_offset_start'] = $endoffset; $ParsedLyrics3['tag_offset_end'] = $endoffset + $length - 1; if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') { if (strpos($rawdata, 'LYRICSBEGIN') !== false) { $info['warning'][] = '"LYRICSBEGIN" expected at ' . $endoffset . ' but actually found at ' . ($endoffset + strpos($rawdata, 'LYRICSBEGIN')) . ' - this is invalid for Lyrics3 v' . $version; $info['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN'); $rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN')); $length = strlen($rawdata); $ParsedLyrics3['tag_offset_start'] = $info['avdataend']; $ParsedLyrics3['raw']['lyrics3tagsize'] = $length; } else { $info['error'][] = '"LYRICSBEGIN" expected at ' . $endoffset . ' but found "' . substr($rawdata, 0, 11) . '" instead'; return false; } } switch ($version) { case 1: if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') { $ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9)); $this->Lyrics3LyricsTimestampParse($ParsedLyrics3); } else { $info['error'][] = '"LYRICSEND" expected at ' . (ftell($this->getid3->fp) - 11 + $length - 9) . ' but found "' . substr($rawdata, strlen($rawdata) - 9, 9) . '" instead'; return false; } break; case 2: if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICS200') { $ParsedLyrics3['raw']['unparsed'] = substr($rawdata, 11, strlen($rawdata) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ $rawdata = $ParsedLyrics3['raw']['unparsed']; while (strlen($rawdata) > 0) { $fieldname = substr($rawdata, 0, 3); $fieldsize = (int) substr($rawdata, 3, 5); $ParsedLyrics3['raw'][$fieldname] = substr($rawdata, 8, $fieldsize); $rawdata = substr($rawdata, 3 + 5 + $fieldsize); } if (isset($ParsedLyrics3['raw']['IND'])) { $i = 0; $flagnames = array('lyrics', 'timestamps', 'inhibitrandom'); foreach ($flagnames as $flagname) { if (strlen($ParsedLyrics3['raw']['IND']) > $i++) { $ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1)); } } } $fieldnametranslation = array('ETT' => 'title', 'EAR' => 'artist', 'EAL' => 'album', 'INF' => 'comment', 'AUT' => 'author'); foreach ($fieldnametranslation as $key => $value) { if (isset($ParsedLyrics3['raw'][$key])) { $ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]); } } if (isset($ParsedLyrics3['raw']['IMG'])) { $imagestrings = explode("\r\n", $ParsedLyrics3['raw']['IMG']); foreach ($imagestrings as $key => $imagestring) { if (strpos($imagestring, '||') !== false) { $imagearray = explode('||', $imagestring); $ParsedLyrics3['images'][$key]['filename'] = isset($imagearray[0]) ? $imagearray[0] : ''; $ParsedLyrics3['images'][$key]['description'] = isset($imagearray[1]) ? $imagearray[1] : ''; $ParsedLyrics3['images'][$key]['timestamp'] = $this->Lyrics3Timestamp2Seconds(isset($imagearray[2]) ? $imagearray[2] : ''); } } } if (isset($ParsedLyrics3['raw']['LYR'])) { $this->Lyrics3LyricsTimestampParse($ParsedLyrics3); } } else { $info['error'][] = '"LYRICS200" expected at ' . (ftell($this->getid3->fp) - 11 + $length - 9) . ' but found "' . substr($rawdata, strlen($rawdata) - 9, 9) . '" instead'; return false; } break; default: $info['error'][] = 'Cannot process Lyrics3 version ' . $version . ' (only v1 and v2)'; return false; break; } if (isset($info['id3v1']['tag_offset_start']) && $info['id3v1']['tag_offset_start'] <= $ParsedLyrics3['tag_offset_end']) { $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data'; unset($info['id3v1']); foreach ($info['warning'] as $key => $value) { if ($value == 'Some ID3v1 fields do not use NULL characters for padding') { unset($info['warning'][$key]); sort($info['warning']); break; } } } $info['lyrics3'] = $ParsedLyrics3; return true; }
/** * * @param type $bytestring * @param type $byteorder * @return boolean */ public function TIFFendian2Int($bytestring, $byteorder) { if ($byteorder == 'Intel') { return GetId3_Lib_Helper::LittleEndian2Int($bytestring); } elseif ($byteorder == 'Motorola') { return GetId3_Lib_Helper::BigEndian2Int($bytestring); } return false; }
/** * * @return boolean */ public function Analyze() { $info =& $this->getid3->info; $info['fileformat'] = 'tar'; $info['tar']['files'] = array(); $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix'; $null_512k = str_repeat("", 512); // end-of-file marker fseek($this->getid3->fp, 0); while (!feof($this->getid3->fp)) { $buffer = fread($this->getid3->fp, 512); if (strlen($buffer) < 512) { break; } // check the block $checksum = 0; for ($i = 0; $i < 148; $i++) { $checksum += ord($buffer[$i]); } for ($i = 148; $i < 156; $i++) { $checksum += ord(' '); } for ($i = 156; $i < 512; $i++) { $checksum += ord($buffer[$i]); } $attr = unpack($unpack_header, $buffer); $name = isset($attr['fname']) ? trim($attr['fname']) : ''; $mode = octdec(isset($attr['mode']) ? trim($attr['mode']) : ''); $uid = octdec(isset($attr['uid']) ? trim($attr['uid']) : ''); $gid = octdec(isset($attr['gid']) ? trim($attr['gid']) : ''); $size = octdec(isset($attr['size']) ? trim($attr['size']) : ''); $mtime = octdec(isset($attr['mtime']) ? trim($attr['mtime']) : ''); $chksum = octdec(isset($attr['chksum']) ? trim($attr['chksum']) : ''); $typflag = isset($attr['typflag']) ? trim($attr['typflag']) : ''; $lnkname = isset($attr['lnkname']) ? trim($attr['lnkname']) : ''; $magic = isset($attr['magic']) ? trim($attr['magic']) : ''; $ver = isset($attr['ver']) ? trim($attr['ver']) : ''; $uname = isset($attr['uname']) ? trim($attr['uname']) : ''; $gname = isset($attr['gname']) ? trim($attr['gname']) : ''; $devmaj = octdec(isset($attr['devmaj']) ? trim($attr['devmaj']) : ''); $devmin = octdec(isset($attr['devmin']) ? trim($attr['devmin']) : ''); $prefix = isset($attr['prefix']) ? trim($attr['prefix']) : ''; if ($checksum == 256 && $chksum == 0) { // EOF Found break; } if ($prefix) { $name = $prefix . '/' . $name; } if (preg_match('#/$#', $name) && !$name) { $typeflag = 5; } if ($buffer == $null_512k) { // it's the end of the tar-file... break; } // Read to the next chunk fseek($this->getid3->fp, $size, SEEK_CUR); $diff = $size % 512; if ($diff != 0) { // Padding, throw away fseek($this->getid3->fp, 512 - $diff, SEEK_CUR); } // Protect against tar-files with garbage at the end if ($name == '') { break; } $info['tar']['file_details'][$name] = array('name' => $name, 'mode_raw' => $mode, 'mode' => self::display_perms($mode), 'uid' => $uid, 'gid' => $gid, 'size' => $size, 'mtime' => $mtime, 'chksum' => $chksum, 'typeflag' => self::get_flag_type($typflag), 'linkname' => $lnkname, 'magic' => $magic, 'version' => $ver, 'uname' => $uname, 'gname' => $gname, 'devmajor' => $devmaj, 'devminor' => $devmin); $info['tar']['files'] = GetId3_Lib_Helper::array_merge_clobber($info['tar']['files'], GetId3_Lib_Helper::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size)); } return true; }
/** * * @return boolean */ 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 "' . GetId3_Lib_Helper::PrintHexBytes($info['swf']['header']['signature']) . '"'; unset($info['swf']); unset($info['fileformat']); return false; break; } $info['swf']['header']['version'] = GetId3_Lib_Helper::LittleEndian2Int(substr($SWFfileData, 3, 1)); $info['swf']['header']['length'] = GetId3_Lib_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'] = GetId3_Lib_Helper::Bin2Dec($X2); $info['swf']['header']['frame_height'] = GetId3_Lib_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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1)); $info['swf']['header']['frame_count'] = GetId3_Lib_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 = GetId3_Lib_Helper::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2)); $TagID = ($TagIDTagLength & 0xfffc) >> 6; $TagLength = $TagIDTagLength & 0x3f; $CurrentOffset += 2; if ($TagLength == 0x3f) { $TagLength = GetId3_Lib_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(GetId3_Lib_Helper::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT)); break; default: if ($this->ReturnAllTagData) { $info['swf']['tags'][] = $TagData; } break; } $CurrentOffset += $TagLength; } return true; }
/** * * @return boolean */ 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 "' . GetId3_Lib_Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . GetId3_Lib_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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($VOCheader, 20, 2)); $thisfile_voc['header']['minor_version'] = GetId3_Lib_Helper::LittleEndian2Int(substr($VOCheader, 22, 1)); $thisfile_voc['header']['major_version'] = GetId3_Lib_Helper::LittleEndian2Int(substr($VOCheader, 23, 1)); do { $BlockOffset = ftell($this->getid3->fp); $BlockData = fread($this->getid3->fp, 4); $BlockType = ord($BlockData[0]); $BlockSize = GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 1, 3)); $ThisBlock = array(); GetId3_Lib_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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 4, 1)); $ThisBlock['compression_type'] = GetId3_Lib_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'] = GetId3_Lib_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'] = GetId3_Lib_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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 4, 2)); $ThisBlock['pack_method'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 6, 1)); $ThisBlock['stereo'] = (bool) GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 7, 1)); $thisfile_audio['channels'] = $ThisBlock['stereo'] ? 2 : 1; $thisfile_audio['sample_rate'] = GetId3_Lib_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'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 4, 4)); $ThisBlock['bits_per_sample'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 8, 1)); $ThisBlock['channels'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BlockData, 9, 1)); $ThisBlock['wFormat'] = GetId3_Lib_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; }
/** * * @param type $compre * @return type */ public static function heavyCompression($compre) { // The first four bits indicate gain changes in 6.02dB increments which can be // implemented with an arithmetic shift operation. The following four bits // indicate linear gain changes, and require a 5-bit multiply. // We will represent the two 4-bit fields of compr as follows: // X0 X1 X2 X3 . Y4 Y5 Y6 Y7 // The meaning of the X values is most simply described by considering X to represent a 4-bit // signed integer with values from –8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The // following table shows this in detail. // Meaning of 4 msb of compr // 7 +48.16 dB // 6 +42.14 dB // 5 +36.12 dB // 4 +30.10 dB // 3 +24.08 dB // 2 +18.06 dB // 1 +12.04 dB // 0 +6.02 dB // -1 0 dB // -2 –6.02 dB // -3 –12.04 dB // -4 –18.06 dB // -5 –24.08 dB // -6 –30.10 dB // -7 –36.12 dB // -8 –42.14 dB $fourbit = str_pad(decbin(($compre & 0xf0) >> 4), 4, '0', STR_PAD_LEFT); if ($fourbit[0] == '1') { $log_gain = -8 + bindec(substr($fourbit, 1)); } else { $log_gain = bindec(substr($fourbit, 1)); } $log_gain = ($log_gain + 1) * GetId3_Lib_Helper::RGADamplitude2dB(2); // The value of Y is a linear representation of a gain change of up to –6 dB. Y is considered to // be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can // represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain // changes from –0.28 dB to –6.02 dB. $lin_gain = (16 + ($compre & 0xf)) / 32; // The combination of X and Y values allows compr to indicate gain changes from // 48.16 – 0.28 = +47.89 dB, to // –42.14 – 6.02 = –48.16 dB. return $log_gain - $lin_gain; }
/** * * @param type $BonkTagName */ public function HandleBonkTags($BonkTagName) { $info =& $this->getid3->info; switch ($BonkTagName) { case 'BONK': // shortcut $thisfile_bonk_BONK =& $info['bonk']['BONK']; $BonkData = "" . 'BONK' . fread($this->getid3->fp, 17); $thisfile_bonk_BONK['version'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 5, 1)); $thisfile_bonk_BONK['number_samples'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 6, 4)); $thisfile_bonk_BONK['sample_rate'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 10, 4)); $thisfile_bonk_BONK['channels'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 14, 1)); $thisfile_bonk_BONK['lossless'] = (bool) GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 15, 1)); $thisfile_bonk_BONK['joint_stereo'] = (bool) GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 16, 1)); $thisfile_bonk_BONK['number_taps'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 17, 2)); $thisfile_bonk_BONK['downsampling_ratio'] = GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, 19, 1)); $thisfile_bonk_BONK['samples_per_packet'] = GetId3_Lib_Helper::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'] = GetId3_Lib_Helper::LittleEndian2Int(fread($this->getid3->fp, 1)); $thisfile_bonk_INFO['entries_count'] = 0; $NextInfoDataPair = fread($this->getid3->fp, 5); if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) { while (!feof($this->getid3->fp)) { //$CurrentSeekInfo['offset'] = GetId3_lib::LittleEndian2Int(substr($NextInfoDataPair, 0, 4)); //$CurrentSeekInfo['nextbit'] = GetId3_lib::LittleEndian2Int(substr($NextInfoDataPair, 4, 1)); //$thisfile_bonk_INFO[] = $CurrentSeekInfo; $NextInfoDataPair = fread($this->getid3->fp, 5); if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) { fseek($this->getid3->fp, -5, SEEK_CUR); break; } $thisfile_bonk_INFO['entries_count']++; } } break; case 'META': $BonkData = "" . 'META' . fread($this->getid3->fp, $info['bonk']['META']['size'] - 5); $info['bonk']['META']['version'] = GetId3_Lib_Helper::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 = GetId3_Lib_Helper::LittleEndian2Int(substr($BonkData, $offset, 4)); $offset += 4; $info['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset; } break; case ' ID3': $info['audio']['encoder'] = 'Extended BONK v0.9+'; // ID3v2 checking is optional if (class_exists('GetId3_Module_Tag_Id3v2')) { $getid3_temp = new GetId3_GetId3(); $getid3_temp->openfile($this->getid3->filename); $getid3_id3v2 = new GetId3_Module_Tag_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; } }