| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 ///////////////////////////////////////////////////////////////// 4 /// getID3() by James Heinrich <info@getid3.org> // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 9 ///////////////////////////////////////////////////////////////// 10 // // 11 // module.audio-video.riff.php // 12 // module for analyzing RIFF files // 13 // multiple formats supported by this module: // 14 // Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX // 15 // dependencies: module.audio.mp3.php // 16 // module.audio.ac3.php // 17 // module.audio.dts.php // 18 // /// 19 ///////////////////////////////////////////////////////////////// 20 21 /** 22 * @todo Parse AC-3/DTS audio inside WAVE correctly 23 * @todo Rewrite RIFF parser totally 24 */ 25 26 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 27 exit; 28 } 29 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true); 30 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true); 31 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true); 32 33 class getid3_riff extends getid3_handler 34 { 35 protected $container = 'riff'; // default 36 37 /** 38 * @return bool 39 * 40 * @throws getid3_exception 41 */ 42 public function Analyze() { 43 $info = &$this->getid3->info; 44 45 // initialize these values to an empty array, otherwise they default to NULL 46 // and you can't append array values to a NULL value 47 $info['riff'] = array('raw'=>array()); 48 49 // Shortcuts 50 $thisfile_riff = &$info['riff']; 51 $thisfile_riff_raw = &$thisfile_riff['raw']; 52 $thisfile_audio = &$info['audio']; 53 $thisfile_video = &$info['video']; 54 $thisfile_audio_dataformat = &$thisfile_audio['dataformat']; 55 $thisfile_riff_audio = &$thisfile_riff['audio']; 56 $thisfile_riff_video = &$thisfile_riff['video']; 57 $thisfile_riff_WAVE = array(); 58 59 $Original = array(); 60 $Original['avdataoffset'] = $info['avdataoffset']; 61 $Original['avdataend'] = $info['avdataend']; 62 63 $this->fseek($info['avdataoffset']); 64 $RIFFheader = $this->fread(12); 65 $offset = $this->ftell(); 66 $RIFFtype = substr($RIFFheader, 0, 4); 67 $RIFFsize = substr($RIFFheader, 4, 4); 68 $RIFFsubtype = substr($RIFFheader, 8, 4); 69 70 if ($RIFFsize == "\x00\x00\x00\x00") { 71 // https://github.com/JamesHeinrich/getID3/issues/468 72 // may occur in streaming files where the data size is unknown 73 $thisfile_riff['header_size'] = $info['avdataend'] - 8; 74 $this->warning('RIFF size field is empty, assuming the correct value is filesize-8 ('.$thisfile_riff['header_size'].')'); 75 } else { 76 $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); 77 } 78 79 switch ($RIFFtype) { 80 case 'FORM': // AIFF, AIFC 81 //$info['fileformat'] = 'aiff'; 82 $this->container = 'aiff'; 83 $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4)); 84 break; 85 86 case 'RIFF': // AVI, WAV, etc 87 case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com) 88 case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s 89 //$info['fileformat'] = 'riff'; 90 $this->container = 'riff'; 91 if ($RIFFsubtype == 'RMP3') { 92 // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s 93 $RIFFsubtype = 'WAVE'; 94 } 95 if ($RIFFsubtype != 'AMV ') { 96 // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size 97 // Handled separately in ParseRIFFAMV() 98 $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4)); 99 } 100 if (($info['avdataend'] - $info['filesize']) == 1) { 101 // LiteWave appears to incorrectly *not* pad actual output file 102 // to nearest WORD boundary so may appear to be short by one 103 // byte, in which case - skip warning 104 $info['avdataend'] = $info['filesize']; 105 } 106 107 $nextRIFFoffset = (int) $Original['avdataoffset'] + 8 + (int) $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset 108 while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) { 109 try { 110 $this->fseek($nextRIFFoffset); 111 } catch (getid3_exception $e) { 112 if ($e->getCode() == 10) { 113 //$this->warning('RIFF parser: '.$e->getMessage()); 114 $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong'); 115 $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present'); 116 break; 117 } else { 118 throw $e; 119 } 120 } 121 $nextRIFFheader = $this->fread(12); 122 if ($nextRIFFoffset == ($info['avdataend'] - 1)) { 123 if (substr($nextRIFFheader, 0, 1) == "\x00") { 124 // RIFF padded to WORD boundary, we're actually already at the end 125 break; 126 } 127 } 128 $nextRIFFheaderID = substr($nextRIFFheader, 0, 4); 129 $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4)); 130 $nextRIFFtype = substr($nextRIFFheader, 8, 4); 131 $chunkdata = array(); 132 $chunkdata['offset'] = $nextRIFFoffset + 8; 133 $chunkdata['size'] = $nextRIFFsize; 134 $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size']; 135 136 switch ($nextRIFFheaderID) { 137 case 'RIFF': 138 $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset); 139 if (!isset($thisfile_riff[$nextRIFFtype])) { 140 $thisfile_riff[$nextRIFFtype] = array(); 141 } 142 $thisfile_riff[$nextRIFFtype][] = $chunkdata; 143 break; 144 145 case 'AMV ': 146 unset($info['riff']); 147 $info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] + 4, $nextRIFFoffset); 148 break; 149 150 case 'JUNK': 151 // ignore 152 $thisfile_riff[$nextRIFFheaderID][] = $chunkdata; 153 break; 154 155 case 'IDVX': 156 $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size'])); 157 break; 158 159 default: 160 if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) { 161 $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12); 162 if (substr($DIVXTAG, -7) == 'DIVXTAG') { 163 // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file 164 $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway'); 165 $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG); 166 break 2; 167 } 168 } 169 $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file'); 170 break 2; 171 172 } 173 174 } 175 if ($RIFFsubtype == 'WAVE') { 176 $thisfile_riff_WAVE = &$thisfile_riff['WAVE']; 177 } 178 break; 179 180 default: 181 $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead'); 182 //unset($info['fileformat']); 183 return false; 184 } 185 186 $streamindex = 0; 187 switch ($RIFFsubtype) { 188 189 // http://en.wikipedia.org/wiki/Wav 190 case 'WAVE': 191 $info['fileformat'] = 'wav'; 192 193 if (empty($thisfile_audio['bitrate_mode'])) { 194 $thisfile_audio['bitrate_mode'] = 'cbr'; 195 } 196 if (empty($thisfile_audio_dataformat)) { 197 $thisfile_audio_dataformat = 'wav'; 198 } 199 200 if (isset($thisfile_riff_WAVE['data'][0]['offset'])) { 201 $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8; 202 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size']; 203 } 204 if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) { 205 206 $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']); 207 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; 208 if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) { 209 $this->error('Corrupt RIFF file: bitrate_audio == zero'); 210 return false; 211 } 212 $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw']; 213 unset($thisfile_riff_audio[$streamindex]['raw']); 214 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; 215 216 $thisfile_audio = (array) getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]); 217 if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') { 218 $this->warning('Audio codec = '.$thisfile_audio['codec']); 219 } 220 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; 221 222 if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) 223 $info['playtime_seconds'] = (float)getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_audio['bitrate']); 224 } 225 226 $thisfile_audio['lossless'] = false; 227 if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { 228 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { 229 230 case 0x0001: // PCM 231 $thisfile_audio['lossless'] = true; 232 break; 233 234 case 0x2000: // AC-3 235 $thisfile_audio_dataformat = 'ac3'; 236 break; 237 238 default: 239 // do nothing 240 break; 241 242 } 243 } 244 $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag']; 245 $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode']; 246 $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless']; 247 $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat; 248 } 249 250 if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) { 251 252 // shortcuts 253 $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data']; 254 $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array()); 255 $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad']; 256 $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track']; 257 $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album']; 258 259 $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4)); 260 $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2)); 261 $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2)); 262 263 $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT); 264 $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT); 265 $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3)); 266 $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3)); 267 $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1)); 268 $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9)); 269 $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3)); 270 $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3)); 271 $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1)); 272 $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9)); 273 274 $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude']; 275 if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) { 276 $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']); 277 $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']); 278 $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']); 279 } 280 if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) { 281 $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']); 282 $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']); 283 $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']); 284 } 285 } 286 287 if (isset($thisfile_riff_WAVE['fact'][0]['data'])) { 288 $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4)); 289 290 // This should be a good way of calculating exact playtime, 291 // but some sample files have had incorrect number of samples, 292 // so cannot use this method 293 294 // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) { 295 // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec']; 296 // } 297 } 298 if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) { 299 $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8); 300 } 301 302 if (isset($thisfile_riff_WAVE['bext'][0]['data'])) { 303 // shortcut 304 $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0]; 305 306 $thisfile_riff_WAVE_bext_0['title'] = substr($thisfile_riff_WAVE_bext_0['data'], 0, 256); 307 $thisfile_riff_WAVE_bext_0['author'] = substr($thisfile_riff_WAVE_bext_0['data'], 256, 32); 308 $thisfile_riff_WAVE_bext_0['reference'] = substr($thisfile_riff_WAVE_bext_0['data'], 288, 32); 309 foreach (array('title','author','reference') as $bext_key) { 310 // Some software (notably Logic Pro) may not blank existing data before writing a null-terminated string to the offsets 311 // assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage 312 // Keep only string as far as first null byte, discard rest of fixed-width data 313 // https://github.com/JamesHeinrich/getID3/issues/263 314 // https://github.com/JamesHeinrich/getID3/issues/430 315 $null_terminator_rows = explode("\x00", $thisfile_riff_WAVE_bext_0[$bext_key]); 316 $thisfile_riff_WAVE_bext_0[$bext_key] = $null_terminator_rows[0]; 317 } 318 319 $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10); 320 $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8); 321 $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8)); 322 $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1)); 323 $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254); 324 $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601))); 325 if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) { 326 if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) { 327 $bext_timestamp = array(); 328 list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date; 329 list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time; 330 $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']); 331 } else { 332 $this->warning('RIFF.WAVE.BEXT.origin_time is invalid'); 333 } 334 } else { 335 $this->warning('RIFF.WAVE.BEXT.origin_date is invalid'); 336 } 337 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author']; 338 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title']; 339 } 340 341 if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) { 342 // shortcut 343 $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0]; 344 345 $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2)); 346 $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001); 347 if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) { 348 $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true; 349 $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004); 350 $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008); 351 352 $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2)); 353 } 354 $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2)); 355 $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2)); 356 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001); 357 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002); 358 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004); 359 } 360 361 if (isset($thisfile_riff_WAVE['cart'][0]['data'])) { 362 // shortcut 363 $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0]; 364 365 $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4); 366 $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64)); 367 $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64)); 368 $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64)); 369 $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64)); 370 $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64)); 371 $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64)); 372 $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64)); 373 $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10)); 374 $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8)); 375 $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10)); 376 $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8)); 377 $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64)); 378 $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64)); 379 $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64)); 380 $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true); 381 for ($i = 0; $i < 8; $i++) { 382 $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4); 383 $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8) + 4, 4)); 384 } 385 $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024)); 386 $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772))); 387 $thisfile_riff['comments']['tag_text'][] = substr($thisfile_riff_WAVE_cart_0['data'], 1772); 388 389 $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist']; 390 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title']; 391 } 392 393 if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) { 394 // SoundMiner metadata 395 396 // shortcuts 397 $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE['SNDM'][0]; 398 $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data']; 399 $SNDM_startoffset = 0; 400 $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size']; 401 402 while ($SNDM_startoffset < $SNDM_endoffset) { 403 $SNDM_thisTagOffset = 0; 404 $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4)); 405 $SNDM_thisTagOffset += 4; 406 $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4); 407 $SNDM_thisTagOffset += 4; 408 $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2)); 409 $SNDM_thisTagOffset += 2; 410 $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2)); 411 $SNDM_thisTagOffset += 2; 412 $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize); 413 $SNDM_thisTagOffset += $SNDM_thisTagDataSize; 414 415 if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) { 416 $this->warning('RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'); 417 break; 418 } elseif ($SNDM_thisTagSize <= 0) { 419 $this->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'); 420 break; 421 } 422 $SNDM_startoffset += $SNDM_thisTagSize; 423 424 $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText; 425 if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) { 426 $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText; 427 } else { 428 $this->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'); 429 } 430 } 431 432 $tagmapping = array( 433 'tracktitle'=>'title', 434 'category' =>'genre', 435 'cdtitle' =>'album', 436 ); 437 foreach ($tagmapping as $fromkey => $tokey) { 438 if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) { 439 $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey]; 440 } 441 } 442 } 443 444 if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) { 445 // requires functions simplexml_load_string and get_object_vars 446 if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) { 447 $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; 448 if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { 449 @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); 450 $thisfile_riff_WAVE['iXML'][0]['master_speed'] = (int) $numerator / ($denominator ? $denominator : 1000); 451 } 452 if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { 453 @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); 454 $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = (int) $numerator / ($denominator ? $denominator : 1000); 455 } 456 if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { 457 $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); 458 $timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105 459 $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate; 460 $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600); 461 $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60); 462 $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60)); 463 $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate']; 464 $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f); 465 $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f)); 466 unset($samples_since_midnight, $timestamp_sample_rate, $h, $m, $s, $f); 467 } 468 unset($parsedXML); 469 } 470 } 471 472 if (isset($thisfile_riff_WAVE['guan'][0]['data'])) { 473 // shortcut 474 $thisfile_riff_WAVE_guan_0 = &$thisfile_riff_WAVE['guan'][0]; 475 if (!empty($thisfile_riff_WAVE_guan_0['data']) && (substr($thisfile_riff_WAVE_guan_0['data'], 0, 14) == 'GUANO|Version:')) { 476 $thisfile_riff['guano'] = array(); 477 foreach (explode("\n", $thisfile_riff_WAVE_guan_0['data']) as $line) { 478 if ($line) { 479 @list($key, $value) = explode(':', $line, 2); 480 if (substr($value, 0, 3) == '[{"') { 481 if ($decoded = @json_decode($value, true)) { 482 if (count($decoded) === 1) { 483 $value = $decoded[0]; 484 } else { 485 $value = $decoded; 486 } 487 } 488 } 489 $thisfile_riff['guano'] = array_merge_recursive($thisfile_riff['guano'], getid3_lib::CreateDeepArray($key, '|', $value)); 490 } 491 } 492 493 // https://www.wildlifeacoustics.com/SCHEMA/GUANO.html 494 foreach ($thisfile_riff['guano'] as $key => $value) { 495 switch ($key) { 496 case 'Loc Position': 497 if (preg_match('#^([\\+\\-]?[0-9]+\\.[0-9]+) ([\\+\\-]?[0-9]+\\.[0-9]+)$#', $value, $matches)) { 498 list($dummy, $latitude, $longitude) = $matches; 499 $thisfile_riff['comments']['gps_latitude'][0] = floatval($latitude); 500 $thisfile_riff['comments']['gps_longitude'][0] = floatval($longitude); 501 $thisfile_riff['guano'][$key] = floatval($latitude).' '.floatval($longitude); 502 } 503 break; 504 case 'Loc Elevation': // Elevation/altitude above mean sea level in meters 505 $thisfile_riff['comments']['gps_altitude'][0] = floatval($value); 506 $thisfile_riff['guano'][$key] = (float) $value; 507 break; 508 case 'Filter HP': // High-pass filter frequency in kHz 509 case 'Filter LP': // Low-pass filter frequency in kHz 510 case 'Humidity': // Relative humidity as a percentage 511 case 'Length': // Recording length in seconds 512 case 'Loc Accuracy': // Estimated Position Error in meters 513 case 'Temperature Ext': // External temperature in degrees Celsius outside the recorder's housing 514 case 'Temperature Int': // Internal temperature in degrees Celsius inside the recorder's housing 515 $thisfile_riff['guano'][$key] = (float) $value; 516 break; 517 case 'Samplerate': // Recording sample rate, Hz 518 case 'TE': // Time-expansion factor. If not specified, then 1 (no time-expansion a.k.a. direct-recording) is assumed. 519 $thisfile_riff['guano'][$key] = (int) $value; 520 break; 521 } 522 } 523 524 } else { 525 $this->warning('RIFF.guan data not in expected format'); 526 } 527 } 528 529 if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { 530 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; 531 $info['playtime_seconds'] = (float)getid3_lib::SafeDiv((($info['avdataend'] - $info['avdataoffset']) * 8), $thisfile_audio['bitrate']); 532 } 533 534 if (!empty($info['wavpack'])) { 535 $thisfile_audio_dataformat = 'wavpack'; 536 $thisfile_audio['bitrate_mode'] = 'vbr'; 537 $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version']; 538 539 // Reset to the way it was - RIFF parsing will have messed this up 540 $info['avdataend'] = $Original['avdataend']; 541 $thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); 542 543 $this->fseek($info['avdataoffset'] - 44); 544 $RIFFdata = $this->fread(44); 545 $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8; 546 $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44; 547 548 if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) { 549 $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize); 550 $this->fseek($info['avdataend']); 551 $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize); 552 } 553 554 // move the data chunk after all other chunks (if any) 555 // so that the RIFF parser doesn't see EOF when trying 556 // to skip over the data chunk 557 $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8); 558 $getid3_riff = new getid3_riff($this->getid3); 559 $getid3_riff->ParseRIFFdata($RIFFdata); 560 unset($getid3_riff); 561 } 562 563 if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { 564 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { 565 case 0x0001: // PCM 566 if (!empty($info['ac3'])) { 567 // Dolby Digital WAV files masquerade as PCM-WAV, but they're not 568 $thisfile_audio['wformattag'] = 0x2000; 569 $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']); 570 $thisfile_audio['lossless'] = false; 571 $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; 572 $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate']; 573 } 574 if (!empty($info['dts'])) { 575 // Dolby DTS files masquerade as PCM-WAV, but they're not 576 $thisfile_audio['wformattag'] = 0x2001; 577 $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']); 578 $thisfile_audio['lossless'] = false; 579 $thisfile_audio['bitrate'] = $info['dts']['bitrate']; 580 $thisfile_audio['sample_rate'] = $info['dts']['sample_rate']; 581 } 582 break; 583 case 0x08AE: // ClearJump LiteWave 584 $thisfile_audio['bitrate_mode'] = 'vbr'; 585 $thisfile_audio_dataformat = 'litewave'; 586 587 //typedef struct tagSLwFormat { 588 // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags 589 // DWORD m_dwScale; // scale factor for lossy compression 590 // DWORD m_dwBlockSize; // number of samples in encoded blocks 591 // WORD m_wQuality; // alias for the scale factor 592 // WORD m_wMarkDistance; // distance between marks in bytes 593 // WORD m_wReserved; 594 // 595 // //following paramters are ignored if CF_FILESRC is not set 596 // DWORD m_dwOrgSize; // original file size in bytes 597 // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file 598 // DWORD m_dwRiffChunkSize; // riff chunk size in the original file 599 // 600 // PCMWAVEFORMAT m_OrgWf; // original wave format 601 // }SLwFormat, *PSLwFormat; 602 603 // shortcut 604 $thisfile_riff['litewave']['raw'] = array(); 605 $riff_litewave = &$thisfile_riff['litewave']; 606 $riff_litewave_raw = &$riff_litewave['raw']; 607 608 $flags = array( 609 'compression_method' => 1, 610 'compression_flags' => 1, 611 'm_dwScale' => 4, 612 'm_dwBlockSize' => 4, 613 'm_wQuality' => 2, 614 'm_wMarkDistance' => 2, 615 'm_wReserved' => 2, 616 'm_dwOrgSize' => 4, 617 'm_bFactExists' => 2, 618 'm_dwRiffChunkSize' => 4, 619 ); 620 $litewave_offset = 18; 621 foreach ($flags as $flag => $length) { 622 $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length)); 623 $litewave_offset += $length; 624 } 625 626 //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20)); 627 $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality']; 628 629 $riff_litewave['flags']['raw_source'] = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true; 630 $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true; 631 $riff_litewave['flags']['seekpoints'] = (bool) ($riff_litewave_raw['compression_flags'] & 0x04); 632 633 $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false); 634 $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor']; 635 break; 636 637 default: 638 break; 639 } 640 } 641 if ($info['avdataend'] > $info['filesize']) { 642 switch ($thisfile_audio_dataformat) { 643 case 'wavpack': // WavPack 644 case 'lpac': // LPAC 645 case 'ofr': // OptimFROG 646 case 'ofs': // OptimFROG DualStream 647 // lossless compressed audio formats that keep original RIFF headers - skip warning 648 break; 649 650 case 'litewave': 651 if (($info['avdataend'] - $info['filesize']) == 1) { 652 // LiteWave appears to incorrectly *not* pad actual output file 653 // to nearest WORD boundary so may appear to be short by one 654 // byte, in which case - skip warning 655 } else { 656 // Short by more than one byte, throw warning 657 $this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'); 658 $info['avdataend'] = $info['filesize']; 659 } 660 break; 661 662 default: 663 if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) { 664 // output file appears to be incorrectly *not* padded to nearest WORD boundary 665 // Output less severe warning 666 $this->warning('File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'); 667 $info['avdataend'] = $info['filesize']; 668 } else { 669 // Short by more than one byte, throw warning 670 $this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'); 671 $info['avdataend'] = $info['filesize']; 672 } 673 break; 674 } 675 } 676 if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) { 677 if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { 678 $info['avdataend']--; 679 $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); 680 } 681 } 682 if ($thisfile_audio_dataformat == 'ac3') { 683 unset($thisfile_audio['bits_per_sample']); 684 if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { 685 $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; 686 } 687 } 688 break; 689 690 // http://en.wikipedia.org/wiki/Audio_Video_Interleave 691 case 'AVI ': 692 $info['fileformat'] = 'avi'; 693 $info['mime_type'] = 'video/avi'; 694 695 $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably 696 $thisfile_video['dataformat'] = 'avi'; 697 698 $thisfile_riff_video_current = array(); 699 700 if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) { 701 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8; 702 if (isset($thisfile_riff['AVIX'])) { 703 $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size']; 704 } else { 705 $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size']; 706 } 707 if ($info['avdataend'] > $info['filesize']) { 708 $this->warning('Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)'); 709 $info['avdataend'] = $info['filesize']; 710 } 711 } 712 713 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) { 714 //$bIndexType = array( 715 // 0x00 => 'AVI_INDEX_OF_INDEXES', 716 // 0x01 => 'AVI_INDEX_OF_CHUNKS', 717 // 0x80 => 'AVI_INDEX_IS_DATA', 718 //); 719 //$bIndexSubtype = array( 720 // 0x01 => array( 721 // 0x01 => 'AVI_INDEX_2FIELD', 722 // ), 723 //); 724 foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) { 725 $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data']; 726 727 $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd, 0, 2)); 728 $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($ahsisd, 2, 1)); 729 $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($ahsisd, 3, 1)); 730 $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($ahsisd, 4, 4)); 731 $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($ahsisd, 8, 4); 732 $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($ahsisd, 12, 4)); 733 734 //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']]; 735 //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']]; 736 737 unset($ahsisd); 738 } 739 } 740 if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) { 741 $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data']; 742 743 // shortcut 744 $thisfile_riff_raw['avih'] = array(); 745 $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih']; 746 747 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L) 748 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) { 749 $this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero'); 750 return false; 751 } 752 753 $flags = array( 754 'dwMaxBytesPerSec', // max. transfer rate 755 'dwPaddingGranularity', // pad to multiples of this size; normally 2K. 756 'dwFlags', // the ever-present flags 757 'dwTotalFrames', // # frames in file 758 'dwInitialFrames', // 759 'dwStreams', // 760 'dwSuggestedBufferSize', // 761 'dwWidth', // 762 'dwHeight', // 763 'dwScale', // 764 'dwRate', // 765 'dwStart', // 766 'dwLength', // 767 ); 768 $avih_offset = 4; 769 foreach ($flags as $flag) { 770 $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4)); 771 $avih_offset += 4; 772 } 773 774 $flags = array( 775 'hasindex' => 0x00000010, 776 'mustuseindex' => 0x00000020, 777 'interleaved' => 0x00000100, 778 'trustcktype' => 0x00000800, 779 'capturedfile' => 0x00010000, 780 'copyrighted' => 0x00020010, 781 ); 782 foreach ($flags as $flag => $value) { 783 $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value); 784 } 785 786 // shortcut 787 $thisfile_riff_video[$streamindex] = array(); 788 /** @var array $thisfile_riff_video_current */ 789 $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; 790 791 if ($thisfile_riff_raw_avih['dwWidth'] > 0) { // @phpstan-ignore-line 792 $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; 793 $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; 794 } 795 if ($thisfile_riff_raw_avih['dwHeight'] > 0) { // @phpstan-ignore-line 796 $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; 797 $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; 798 } 799 if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { // @phpstan-ignore-line 800 $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; 801 $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; 802 } 803 804 $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3); 805 $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate']; 806 } 807 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) { 808 if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) { 809 $thisfile_riff_raw_strf_strhfccType_streamindex = null; 810 for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) { 811 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) { 812 $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data']; 813 $strhfccType = substr($strhData, 0, 4); 814 815 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) { 816 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data']; 817 818 if (!isset($thisfile_riff_raw['strf'][$strhfccType][$streamindex])) { 819 $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = null; 820 } 821 // shortcut 822 $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex]; 823 824 switch ($strhfccType) { 825 case 'auds': 826 $thisfile_audio['bitrate_mode'] = 'cbr'; 827 $thisfile_audio_dataformat = 'wav'; 828 if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) { 829 $streamindex = count($thisfile_riff_audio); 830 } 831 832 $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData); 833 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; 834 835 // shortcut 836 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; 837 $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex]; 838 839 if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) { 840 unset($thisfile_audio_streams_currentstream['bits_per_sample']); 841 } 842 $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag']; 843 unset($thisfile_audio_streams_currentstream['raw']); 844 845 // shortcut 846 $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw']; 847 848 unset($thisfile_riff_audio[$streamindex]['raw']); 849 $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]); 850 851 $thisfile_audio['lossless'] = false; 852 switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) { 853 case 0x0001: // PCM 854 $thisfile_audio_dataformat = 'wav'; 855 $thisfile_audio['lossless'] = true; 856 break; 857 858 case 0x0050: // MPEG Layer 2 or Layer 1 859 $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2 860 break; 861 862 case 0x0055: // MPEG Layer 3 863 $thisfile_audio_dataformat = 'mp3'; 864 break; 865 866 case 0x00FF: // AAC 867 $thisfile_audio_dataformat = 'aac'; 868 break; 869 870 case 0x0161: // Windows Media v7 / v8 / v9 871 case 0x0162: // Windows Media Professional v9 872 case 0x0163: // Windows Media Lossess v9 873 $thisfile_audio_dataformat = 'wma'; 874 break; 875 876 case 0x2000: // AC-3 877 $thisfile_audio_dataformat = 'ac3'; 878 break; 879 880 case 0x2001: // DTS 881 $thisfile_audio_dataformat = 'dts'; 882 break; 883 884 default: 885 $thisfile_audio_dataformat = 'wav'; 886 break; 887 } 888 $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat; 889 $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless']; 890 $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode']; 891 break; 892 893 894 case 'iavs': 895 case 'vids': 896 // shortcut 897 $thisfile_riff_raw['strh'][$i] = array(); 898 $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i]; 899 900 $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType; 901 $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4); 902 $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4)); // Contains AVITF_* flags 903 $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2)); 904 $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2)); 905 $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4)); 906 $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4)); 907 $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4)); 908 $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4)); 909 $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4)); 910 $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4)); 911 $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4)); 912 $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4)); 913 $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4)); 914 915 $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']); 916 $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler']; 917 if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) { 918 $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']); 919 $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']; 920 } 921 $thisfile_video['codec'] = $thisfile_riff_video_current['codec']; 922 $thisfile_video['pixel_aspect_ratio'] = (float) 1; 923 switch ($thisfile_riff_raw_strh_current['fccHandler']) { 924 case 'HFYU': // Huffman Lossless Codec 925 case 'IRAW': // Intel YUV Uncompressed 926 case 'YUY2': // Uncompressed YUV 4:2:2 927 $thisfile_video['lossless'] = true; 928 break; 929 930 default: 931 $thisfile_video['lossless'] = false; 932 break; 933 } 934 935 switch ($strhfccType) { 936 case 'vids': 937 $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($this->container == 'riff')); 938 $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount']; 939 940 if ($thisfile_riff_video_current['codec'] == 'DV') { 941 $thisfile_riff_video_current['dv_type'] = 2; 942 } 943 break; 944 945 case 'iavs': 946 $thisfile_riff_video_current['dv_type'] = 1; 947 break; 948 } 949 break; 950 951 default: 952 $this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"'); 953 break; 954 955 } 956 } 957 } 958 959 if (isset($thisfile_riff_raw_strf_strhfccType_streamindex) && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) { 960 961 $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']; 962 if (self::fourccLookup($thisfile_video['fourcc'])) { 963 $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']); 964 $thisfile_video['codec'] = $thisfile_riff_video_current['codec']; 965 } 966 967 switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) { 968 case 'HFYU': // Huffman Lossless Codec 969 case 'IRAW': // Intel YUV Uncompressed 970 case 'YUY2': // Uncompressed YUV 4:2:2 971 $thisfile_video['lossless'] = true; 972 //$thisfile_video['bits_per_sample'] = 24; 973 break; 974 975 default: 976 $thisfile_video['lossless'] = false; 977 //$thisfile_video['bits_per_sample'] = 24; 978 break; 979 } 980 981 } 982 } 983 } 984 } 985 break; 986 987 988 case 'AMV ': 989 $info['fileformat'] = 'amv'; 990 $info['mime_type'] = 'video/amv'; 991 992 $thisfile_video['bitrate_mode'] = 'vbr'; // it's MJPEG, presumably contant-quality encoding, thereby VBR 993 $thisfile_video['dataformat'] = 'mjpeg'; 994 $thisfile_video['codec'] = 'mjpeg'; 995 $thisfile_video['lossless'] = false; 996 $thisfile_video['bits_per_sample'] = 24; 997 998 $thisfile_audio['dataformat'] = 'adpcm'; 999 $thisfile_audio['lossless'] = false; 1000 break; 1001 1002 1003 // http://en.wikipedia.org/wiki/CD-DA 1004 case 'CDDA': 1005 $info['fileformat'] = 'cda'; 1006 unset($info['mime_type']); 1007 1008 $thisfile_audio_dataformat = 'cda'; 1009 1010 $info['avdataoffset'] = 44; 1011 1012 if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) { 1013 // shortcut 1014 $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0]; 1015 1016 $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2)); 1017 $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2)); 1018 $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4)); 1019 $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4)); 1020 $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4)); 1021 $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4)); 1022 $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4)); 1023 1024 $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75; 1025 $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75; 1026 $info['comments']['track_number'] = $thisfile_riff_CDDA_fmt_0['track_num']; 1027 $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds']; 1028 1029 // hardcoded data for CD-audio 1030 $thisfile_audio['lossless'] = true; 1031 $thisfile_audio['sample_rate'] = 44100; 1032 $thisfile_audio['channels'] = 2; 1033 $thisfile_audio['bits_per_sample'] = 16; 1034 $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample']; 1035 $thisfile_audio['bitrate_mode'] = 'cbr'; 1036 } 1037 break; 1038 1039 // http://en.wikipedia.org/wiki/AIFF 1040 case 'AIFF': 1041 case 'AIFC': 1042 $info['fileformat'] = 'aiff'; 1043 $info['mime_type'] = 'audio/x-aiff'; 1044 1045 $thisfile_audio['bitrate_mode'] = 'cbr'; 1046 $thisfile_audio_dataformat = 'aiff'; 1047 $thisfile_audio['lossless'] = true; 1048 1049 if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) { 1050 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8; 1051 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size']; 1052 if ($info['avdataend'] > $info['filesize']) { 1053 if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) { 1054 // structures rounded to 2-byte boundary, but dumb encoders 1055 // forget to pad end of file to make this actually work 1056 } else { 1057 $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'); 1058 } 1059 $info['avdataend'] = $info['filesize']; 1060 } 1061 } 1062 1063 if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) { 1064 1065 // shortcut 1066 $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data']; 1067 1068 $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true); 1069 $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false); 1070 $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true); 1071 $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10)); 1072 1073 if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) { 1074 $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4); 1075 $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false); 1076 $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize); 1077 switch ($thisfile_riff_audio['codec_name']) { 1078 case 'NONE': 1079 $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)'; 1080 $thisfile_audio['lossless'] = true; 1081 break; 1082 1083 case '': 1084 switch ($thisfile_riff_audio['codec_fourcc']) { 1085 // http://developer.apple.com/qa/snd/snd07.html 1086 case 'sowt': 1087 $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM'; 1088 $thisfile_audio['lossless'] = true; 1089 break; 1090 1091 case 'twos': 1092 $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM'; 1093 $thisfile_audio['lossless'] = true; 1094 break; 1095 1096 default: 1097 break; 1098 } 1099 break; 1100 1101 default: 1102 $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name']; 1103 $thisfile_audio['lossless'] = false; 1104 break; 1105 } 1106 } 1107 1108 $thisfile_audio['channels'] = $thisfile_riff_audio['channels']; 1109 if ($thisfile_riff_audio['bits_per_sample'] > 0) { 1110 $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample']; 1111 } 1112 $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate']; 1113 if ($thisfile_audio['sample_rate'] == 0) { 1114 $this->error('Corrupted AIFF file: sample_rate == zero'); 1115 return false; 1116 } 1117 $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate']; 1118 } 1119 1120 if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) { 1121 $offset = 0; 1122 $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false); 1123 $offset += 2; 1124 for ($i = 0; $i < $CommentCount; $i++) { 1125 $info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false); 1126 $offset += 4; 1127 $info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true); 1128 $offset += 2; 1129 $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false); 1130 $offset += 2; 1131 $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength); 1132 $offset += $CommentLength; 1133 1134 $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']); 1135 $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment']; 1136 } 1137 } 1138 1139 $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); 1140 foreach ($CommentsChunkNames as $key => $value) { 1141 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { 1142 // https://github.com/JamesHeinrich/getID3/issues/430 1143 $null_terminator_rows = explode("\x00", $thisfile_riff[$RIFFsubtype][$key][0]['data']); 1144 $thisfile_riff['comments'][$value][] = $null_terminator_rows[0]; 1145 } 1146 } 1147 /* 1148 if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) { 1149 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 1150 $getid3_temp = new getID3(); 1151 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1152 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1153 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8; 1154 if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) { 1155 $info['id3v2'] = $getid3_temp->info['id3v2']; 1156 } 1157 unset($getid3_temp, $getid3_id3v2); 1158 } 1159 */ 1160 break; 1161 1162 // http://en.wikipedia.org/wiki/8SVX 1163 case '8SVX': 1164 $info['fileformat'] = '8svx'; 1165 $info['mime_type'] = 'audio/8svx'; 1166 1167 $thisfile_audio['bitrate_mode'] = 'cbr'; 1168 $thisfile_audio_dataformat = '8svx'; 1169 $thisfile_audio['bits_per_sample'] = 8; 1170 $thisfile_audio['channels'] = 1; // overridden below, if need be 1171 $ActualBitsPerSample = 0; 1172 1173 if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) { 1174 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8; 1175 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size']; 1176 if ($info['avdataend'] > $info['filesize']) { 1177 $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'); 1178 } 1179 } 1180 1181 if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) { 1182 // shortcut 1183 $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0]; 1184 1185 $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4)); 1186 $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4)); 1187 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4)); 1188 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2)); 1189 $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1)); 1190 $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1)); 1191 $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4)); 1192 1193 $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec']; 1194 1195 switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) { 1196 case 0: 1197 $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)'; 1198 $thisfile_audio['lossless'] = true; 1199 $ActualBitsPerSample = 8; 1200 break; 1201 1202 case 1: 1203 $thisfile_audio['codec'] = 'Fibonacci-delta encoding'; 1204 $thisfile_audio['lossless'] = false; 1205 $ActualBitsPerSample = 4; 1206 break; 1207 1208 default: 1209 $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.$thisfile_riff_RIFFsubtype_VHDR_0['sCompression'].'"'); 1210 break; 1211 } 1212 } 1213 1214 if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) { 1215 $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4)); 1216 switch ($ChannelsIndex) { 1217 case 6: // Stereo 1218 $thisfile_audio['channels'] = 2; 1219 break; 1220 1221 case 2: // Left channel only 1222 case 4: // Right channel only 1223 $thisfile_audio['channels'] = 1; 1224 break; 1225 1226 default: 1227 $this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"'); 1228 break; 1229 } 1230 1231 } 1232 1233 $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); 1234 foreach ($CommentsChunkNames as $key => $value) { 1235 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { 1236 // https://github.com/JamesHeinrich/getID3/issues/430 1237 $null_terminator_rows = explode("\x00", $thisfile_riff[$RIFFsubtype][$key][0]['data']); 1238 $thisfile_riff['comments'][$value][] = $null_terminator_rows[0]; 1239 } 1240 } 1241 1242 $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels']; 1243 if (!empty($thisfile_audio['bitrate'])) { 1244 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8); 1245 } 1246 break; 1247 1248 case 'CDXA': 1249 $info['fileformat'] = 'vcd'; // Asume Video CD 1250 $info['mime_type'] = 'video/mpeg'; 1251 1252 if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) { 1253 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true); 1254 1255 $getid3_temp = new getID3(); 1256 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1257 $getid3_mpeg = new getid3_mpeg($getid3_temp); 1258 $getid3_mpeg->Analyze(); 1259 if (empty($getid3_temp->info['error'])) { 1260 $info['audio'] = $getid3_temp->info['audio']; 1261 $info['video'] = $getid3_temp->info['video']; 1262 $info['mpeg'] = $getid3_temp->info['mpeg']; 1263 $info['warning'] = $getid3_temp->info['warning']; 1264 } 1265 unset($getid3_temp, $getid3_mpeg); 1266 } 1267 break; 1268 1269 case 'WEBP': 1270 // https://developers.google.com/speed/webp/docs/riff_container 1271 // https://tools.ietf.org/html/rfc6386 1272 // https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt 1273 $info['fileformat'] = 'webp'; 1274 $info['mime_type'] = 'image/webp'; 1275 1276 if (!empty($thisfile_riff['WEBP']['VP8 '][0]['size'])) { 1277 $old_offset = $this->ftell(); 1278 $this->fseek($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8); // 4 bytes "VP8 " + 4 bytes chunk size 1279 $WEBP_VP8_header = $this->fread(10); 1280 $this->fseek($old_offset); 1281 if (substr($WEBP_VP8_header, 3, 3) == "\x9D\x01\x2A") { 1282 $thisfile_riff['WEBP']['VP8 '][0]['keyframe'] = !(getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x800000); 1283 $thisfile_riff['WEBP']['VP8 '][0]['version'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x700000) >> 20; 1284 $thisfile_riff['WEBP']['VP8 '][0]['show_frame'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x080000); 1285 $thisfile_riff['WEBP']['VP8 '][0]['data_bytes'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x07FFFF) >> 0; 1286 1287 $thisfile_riff['WEBP']['VP8 '][0]['scale_x'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0xC000) >> 14; 1288 $thisfile_riff['WEBP']['VP8 '][0]['width'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0x3FFF); 1289 $thisfile_riff['WEBP']['VP8 '][0]['scale_y'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0xC000) >> 14; 1290 $thisfile_riff['WEBP']['VP8 '][0]['height'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0x3FFF); 1291 1292 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8 '][0]['width']; 1293 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8 '][0]['height']; 1294 } else { 1295 $this->error('Expecting 9D 01 2A at offset '.($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8 + 3).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8_header, 3, 3)).'"'); 1296 } 1297 1298 } 1299 if (!empty($thisfile_riff['WEBP']['VP8L'][0]['size'])) { 1300 $old_offset = $this->ftell(); 1301 $this->fseek($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8); // 4 bytes "VP8L" + 4 bytes chunk size 1302 $WEBP_VP8L_header = $this->fread(10); 1303 $this->fseek($old_offset); 1304 if (substr($WEBP_VP8L_header, 0, 1) == "\x2F") { 1305 $width_height_flags = getid3_lib::LittleEndian2Bin(substr($WEBP_VP8L_header, 1, 4)); 1306 $thisfile_riff['WEBP']['VP8L'][0]['width'] = bindec(substr($width_height_flags, 18, 14)) + 1; 1307 $thisfile_riff['WEBP']['VP8L'][0]['height'] = bindec(substr($width_height_flags, 4, 14)) + 1; 1308 $thisfile_riff['WEBP']['VP8L'][0]['alpha_is_used'] = (bool) bindec(substr($width_height_flags, 3, 1)); 1309 $thisfile_riff['WEBP']['VP8L'][0]['version'] = bindec(substr($width_height_flags, 0, 3)); 1310 1311 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8L'][0]['width']; 1312 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8L'][0]['height']; 1313 } else { 1314 $this->error('Expecting 2F at offset '.($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8L_header, 0, 1)).'"'); 1315 } 1316 1317 } 1318 break; 1319 1320 default: 1321 $this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead'); 1322 //unset($info['fileformat']); 1323 } 1324 1325 switch ($RIFFsubtype) { 1326 case 'WAVE': 1327 case 'AIFF': 1328 case 'AIFC': 1329 $ID3v2_key_good = 'id3 '; 1330 $ID3v2_keys_bad = array('ID3 ', 'tag '); 1331 foreach ($ID3v2_keys_bad as $ID3v2_key_bad) { 1332 if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) { 1333 $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]; 1334 $this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"'); 1335 } 1336 } 1337 1338 if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) { 1339 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 1340 1341 $getid3_temp = new getID3(); 1342 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1343 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1344 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8; 1345 if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) { 1346 $info['id3v2'] = $getid3_temp->info['id3v2']; 1347 } 1348 unset($getid3_temp, $getid3_id3v2); 1349 } 1350 break; 1351 } 1352 1353 if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) { 1354 $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4)); 1355 } 1356 if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) { 1357 self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']); 1358 } 1359 if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) { 1360 self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']); 1361 } 1362 1363 if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) { 1364 $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version']; 1365 } 1366 1367 if (!isset($info['playtime_seconds'])) { 1368 $info['playtime_seconds'] = 0; 1369 } 1370 if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line 1371 // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie 1372 $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); 1373 } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line 1374 $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); 1375 } 1376 1377 if ($info['playtime_seconds'] > 0) { 1378 if ($thisfile_riff_audio !== null && $thisfile_riff_video !== null) { 1379 1380 if (!isset($info['bitrate'])) { 1381 $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); 1382 } 1383 1384 } elseif ($thisfile_riff_audio !== null && $thisfile_riff_video === null) { // @phpstan-ignore-line 1385 1386 if (!isset($thisfile_audio['bitrate'])) { 1387 $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); 1388 } 1389 1390 } elseif ($thisfile_riff_audio === null && $thisfile_riff_video !== null) { 1391 1392 if (!isset($thisfile_video['bitrate'])) { 1393 $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); 1394 } 1395 1396 } 1397 } 1398 1399 1400 if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) { 1401 $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); 1402 $thisfile_audio['bitrate'] = 0; 1403 $thisfile_video['bitrate'] = $info['bitrate']; 1404 foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) { 1405 $thisfile_video['bitrate'] -= $audioinfoarray['bitrate']; 1406 $thisfile_audio['bitrate'] += $audioinfoarray['bitrate']; 1407 } 1408 if ($thisfile_video['bitrate'] <= 0) { 1409 unset($thisfile_video['bitrate']); 1410 } 1411 if ($thisfile_audio['bitrate'] <= 0) { 1412 unset($thisfile_audio['bitrate']); 1413 } 1414 } 1415 1416 if (isset($info['mpeg']['audio'])) { 1417 $thisfile_audio_dataformat = 'mp'.$info['mpeg']['audio']['layer']; 1418 $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate']; 1419 $thisfile_audio['channels'] = $info['mpeg']['audio']['channels']; 1420 $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate']; 1421 $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); 1422 if (!empty($info['mpeg']['audio']['codec'])) { 1423 $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec']; 1424 } 1425 if (!empty($thisfile_audio['streams'])) { 1426 foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) { 1427 if ($streamdata['dataformat'] == $thisfile_audio_dataformat) { 1428 $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate']; 1429 $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels']; 1430 $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate']; 1431 $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode']; 1432 $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec']; 1433 } 1434 } 1435 } 1436 $getid3_mp3 = new getid3_mp3($this->getid3); 1437 $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions(); 1438 unset($getid3_mp3); 1439 } 1440 1441 1442 if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) { 1443 switch ($thisfile_audio_dataformat) { 1444 case 'ac3': 1445 // ignore bits_per_sample 1446 break; 1447 1448 default: 1449 $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample']; 1450 break; 1451 } 1452 } 1453 1454 1455 if (empty($thisfile_riff_raw)) { 1456 unset($thisfile_riff['raw']); 1457 } 1458 if (empty($thisfile_riff_audio)) { 1459 unset($thisfile_riff['audio']); 1460 } 1461 if (empty($thisfile_riff_video)) { 1462 unset($thisfile_riff['video']); 1463 } 1464 1465 return true; 1466 } 1467 1468 /** 1469 * @param int $startoffset 1470 * @param int $maxoffset 1471 * 1472 * @return array|false 1473 * 1474 * @throws Exception 1475 * @throws getid3_exception 1476 */ 1477 public function ParseRIFFAMV($startoffset, $maxoffset) { 1478 // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size 1479 1480 // https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation 1481 //typedef struct _amvmainheader { 1482 //FOURCC fcc; // 'amvh' 1483 //DWORD cb; 1484 //DWORD dwMicroSecPerFrame; 1485 //BYTE reserve[28]; 1486 //DWORD dwWidth; 1487 //DWORD dwHeight; 1488 //DWORD dwSpeed; 1489 //DWORD reserve0; 1490 //DWORD reserve1; 1491 //BYTE bTimeSec; 1492 //BYTE bTimeMin; 1493 //WORD wTimeHour; 1494 //} AMVMAINHEADER; 1495 1496 $info = &$this->getid3->info; 1497 $RIFFchunk = false; 1498 1499 try { 1500 1501 $this->fseek($startoffset); 1502 $maxoffset = min($maxoffset, $info['avdataend']); 1503 $AMVheader = $this->fread(284); 1504 if (substr($AMVheader, 0, 8) != 'hdrlamvh') { 1505 throw new Exception('expecting "hdrlamv" at offset '.($startoffset + 0).', found "'.substr($AMVheader, 0, 8).'"'); 1506 } 1507 if (substr($AMVheader, 8, 4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes 1508 throw new Exception('expecting "0x38000000" at offset '.($startoffset + 8).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 8, 4)).'"'); 1509 } 1510 $RIFFchunk = array(); 1511 $RIFFchunk['amvh']['us_per_frame'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 12, 4)); 1512 $RIFFchunk['amvh']['reserved28'] = substr($AMVheader, 16, 28); // null? reserved? 1513 $RIFFchunk['amvh']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 44, 4)); 1514 $RIFFchunk['amvh']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 48, 4)); 1515 $RIFFchunk['amvh']['frame_rate_int'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 52, 4)); 1516 $RIFFchunk['amvh']['reserved0'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 56, 4)); // 1? reserved? 1517 $RIFFchunk['amvh']['reserved1'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 60, 4)); // 0? reserved? 1518 $RIFFchunk['amvh']['runtime_sec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 64, 1)); 1519 $RIFFchunk['amvh']['runtime_min'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 65, 1)); 1520 $RIFFchunk['amvh']['runtime_hrs'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 66, 2)); 1521 1522 $info['video']['frame_rate'] = 1000000 / $RIFFchunk['amvh']['us_per_frame']; 1523 $info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x']; 1524 $info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y']; 1525 $info['playtime_seconds'] = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) + ($RIFFchunk['amvh']['runtime_min'] * 60) + $RIFFchunk['amvh']['runtime_sec']; 1526 1527 // the rest is all hardcoded(?) and does not appear to be useful until you get to audio info at offset 256, even then everything is probably hardcoded 1528 1529 if (substr($AMVheader, 68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") { 1530 throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset + 68).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 68, 20)).'"'); 1531 } 1532 // followed by 56 bytes of null: substr($AMVheader, 88, 56) -> 144 1533 if (substr($AMVheader, 144, 8) != 'strf'."\x24\x00\x00\x00") { 1534 throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset + 144).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 144, 8)).'"'); 1535 } 1536 // followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180 1537 1538 if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") { 1539 throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset + 188).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 188, 20)).'"'); 1540 } 1541 // followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256 1542 if (substr($AMVheader, 256, 8) != 'strf'."\x14\x00\x00\x00") { 1543 throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset + 256).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 256, 8)).'"'); 1544 } 1545 // followed by 20 bytes of a modified WAVEFORMATEX: 1546 // typedef struct { 1547 // WORD wFormatTag; //(Fixme: this is equal to PCM's 0x01 format code) 1548 // WORD nChannels; //(Fixme: this is always 1) 1549 // DWORD nSamplesPerSec; //(Fixme: for all known sample files this is equal to 22050) 1550 // DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100) 1551 // WORD nBlockAlign; //(Fixme: this seems to be 2 in AMV files, is this correct ?) 1552 // WORD wBitsPerSample; //(Fixme: this seems to be 16 in AMV files instead of the expected 4) 1553 // WORD cbSize; //(Fixme: this seems to be 0 in AMV files) 1554 // WORD reserved; 1555 // } WAVEFORMATEX; 1556 $RIFFchunk['strf']['wformattag'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 264, 2)); 1557 $RIFFchunk['strf']['nchannels'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 266, 2)); 1558 $RIFFchunk['strf']['nsamplespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 268, 4)); 1559 $RIFFchunk['strf']['navgbytespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 272, 4)); 1560 $RIFFchunk['strf']['nblockalign'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 276, 2)); 1561 $RIFFchunk['strf']['wbitspersample'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 278, 2)); 1562 $RIFFchunk['strf']['cbsize'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 280, 2)); 1563 $RIFFchunk['strf']['reserved'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 282, 2)); 1564 1565 1566 $info['audio']['lossless'] = false; 1567 $info['audio']['sample_rate'] = $RIFFchunk['strf']['nsamplespersec']; 1568 $info['audio']['channels'] = $RIFFchunk['strf']['nchannels']; 1569 $info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample']; 1570 $info['audio']['bitrate'] = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample']; 1571 $info['audio']['bitrate_mode'] = 'cbr'; 1572 1573 1574 } catch (getid3_exception $e) { 1575 if ($e->getCode() == 10) { 1576 $this->warning('RIFFAMV parser: '.$e->getMessage()); 1577 } else { 1578 throw $e; 1579 } 1580 } 1581 1582 return $RIFFchunk; 1583 } 1584 1585 /** 1586 * @param int $startoffset 1587 * @param int $maxoffset 1588 * 1589 * @return array|false 1590 * @throws getid3_exception 1591 */ 1592 public function ParseRIFF($startoffset, $maxoffset) { 1593 $info = &$this->getid3->info; 1594 1595 $RIFFchunk = array(); 1596 $FoundAllChunksWeNeed = false; 1597 $LISTchunkParent = null; 1598 $LISTchunkMaxOffset = null; 1599 $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77" 1600 1601 try { 1602 $this->fseek($startoffset); 1603 $maxoffset = min($maxoffset, $info['avdataend']); 1604 while ($this->ftell() < $maxoffset) { 1605 $chunknamesize = $this->fread(8); 1606 //$chunkname = substr($chunknamesize, 0, 4); 1607 $chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4)); // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult 1608 $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4)); 1609 //if (strlen(trim($chunkname, "\x00")) < 4) { 1610 if (strlen($chunkname) < 4) { 1611 $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.'); 1612 break; 1613 } 1614 if ($chunksize == 0) { 1615 if ($chunkname == 'JUNK') { 1616 // this is allowed 1617 } elseif ($chunkname == 'data') { 1618 // https://github.com/JamesHeinrich/getID3/issues/468 1619 // may occur in streaming files where the data size is unknown 1620 $chunksize = $info['avdataend'] - $this->ftell(); 1621 $this->warning('RIFF.data size field is empty, assuming the correct value is filesize-offset ('.$chunksize.')'); 1622 } else { 1623 $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.'); 1624 break; 1625 } 1626 } 1627 if (($chunksize % 2) != 0) { 1628 // all structures are packed on word boundaries 1629 $chunksize++; 1630 } 1631 1632 switch ($chunkname) { 1633 case 'LIST': 1634 $listname = $this->fread(4); 1635 if (preg_match('#^(movi|rec )$#i', $listname)) { 1636 $RIFFchunk[$listname]['offset'] = $this->ftell() - 4; 1637 $RIFFchunk[$listname]['size'] = $chunksize; 1638 1639 if (!$FoundAllChunksWeNeed) { 1640 $WhereWeWere = $this->ftell(); 1641 $AudioChunkHeader = $this->fread(12); 1642 $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2); 1643 $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2); 1644 $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4)); 1645 1646 if ($AudioChunkStreamType == 'wb') { 1647 $FirstFourBytes = substr($AudioChunkHeader, 8, 4); 1648 if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) { 1649 // MP3 1650 if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) { 1651 $getid3_temp = new getID3(); 1652 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1653 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1654 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; 1655 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__); 1656 $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false); 1657 if (isset($getid3_temp->info['mpeg']['audio'])) { 1658 $info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio']; 1659 $info['audio'] = $getid3_temp->info['audio']; 1660 $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer']; 1661 $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; 1662 $info['audio']['channels'] = $info['mpeg']['audio']['channels']; 1663 $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; 1664 $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); 1665 //$info['bitrate'] = $info['audio']['bitrate']; 1666 } 1667 unset($getid3_temp, $getid3_mp3); 1668 } 1669 1670 } elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) { 1671 // AC3 1672 $getid3_temp = new getID3(); 1673 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1674 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1675 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; 1676 $getid3_ac3 = new getid3_ac3($getid3_temp); 1677 $getid3_ac3->Analyze(); 1678 if (empty($getid3_temp->info['error'])) { 1679 $info['audio'] = $getid3_temp->info['audio']; 1680 $info['ac3'] = $getid3_temp->info['ac3']; 1681 if (!empty($getid3_temp->info['warning'])) { 1682 foreach ($getid3_temp->info['warning'] as $key => $value) { 1683 $this->warning($value); 1684 } 1685 } 1686 } 1687 unset($getid3_temp, $getid3_ac3); 1688 } 1689 } 1690 $FoundAllChunksWeNeed = true; 1691 $this->fseek($WhereWeWere); 1692 } 1693 $this->fseek($chunksize - 4, SEEK_CUR); 1694 1695 } else { 1696 1697 if (!isset($RIFFchunk[$listname])) { 1698 $RIFFchunk[$listname] = array(); 1699 } 1700 $LISTchunkParent = $listname; 1701 $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize; 1702 if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) { 1703 $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk); 1704 } 1705 1706 } 1707 break; 1708 1709 default: 1710 if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) { 1711 $this->fseek($chunksize, SEEK_CUR); 1712 break; 1713 } 1714 $thisindex = 0; 1715 if (isset($RIFFchunk[$chunkname])) { 1716 $thisindex = count($RIFFchunk[$chunkname]); 1717 } 1718 $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8; 1719 $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize; 1720 switch ($chunkname) { 1721 case 'data': 1722 $info['avdataoffset'] = $this->ftell(); 1723 $info['avdataend'] = $info['avdataoffset'] + $chunksize; 1724 1725 $testData = $this->fread(36); 1726 if ($testData === '') { 1727 break; 1728 } 1729 if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) { 1730 1731 // Probably is MP3 data 1732 if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) { 1733 $getid3_temp = new getID3(); 1734 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1735 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1736 $getid3_temp->info['avdataend'] = $info['avdataend']; 1737 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__); 1738 $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false); 1739 if (!empty($getid3_temp->info['mpeg']['audio']['bitrate']) && ($getid3_temp->info['mpeg']['audio']['bitrate'] != 'free')) { // if it detects as "free" bitrate then it's almost certainly a false-match MP3 sync, ignore 1740 if (empty($getid3_temp->info['error'])) { 1741 $info['audio'] = $getid3_temp->info['audio']; 1742 $info['mpeg'] = $getid3_temp->info['mpeg']; 1743 } 1744 } 1745 unset($getid3_temp, $getid3_mp3); 1746 } 1747 1748 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == $AC3syncwordBytes)) || substr($testData, 8, 2) == strrev($AC3syncwordBytes)) { 1749 1750 // This is probably AC-3 data 1751 $getid3_temp = new getID3(); 1752 if ($isRegularAC3) { 1753 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1754 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1755 $getid3_temp->info['avdataend'] = $info['avdataend']; 1756 } 1757 $getid3_ac3 = new getid3_ac3($getid3_temp); 1758 if ($isRegularAC3) { 1759 $getid3_ac3->Analyze(); 1760 } else { 1761 // Dolby Digital WAV 1762 // AC-3 content, but not encoded in same format as normal AC-3 file 1763 // For one thing, byte order is swapped 1764 $ac3_data = ''; 1765 for ($i = 0; $i < 28; $i += 2) { 1766 $ac3_data .= substr($testData, 8 + $i + 1, 1); 1767 $ac3_data .= substr($testData, 8 + $i + 0, 1); 1768 } 1769 $getid3_ac3->getid3->info['avdataoffset'] = 0; 1770 $getid3_ac3->getid3->info['avdataend'] = strlen($ac3_data); 1771 $getid3_ac3->AnalyzeString($ac3_data); 1772 } 1773 1774 if (empty($getid3_temp->info['error'])) { 1775 $info['audio'] = $getid3_temp->info['audio']; 1776 $info['ac3'] = $getid3_temp->info['ac3']; 1777 if (!empty($getid3_temp->info['warning'])) { 1778 foreach ($getid3_temp->info['warning'] as $newerror) { 1779 $this->warning('getid3_ac3() says: ['.$newerror.']'); 1780 } 1781 } 1782 } 1783 unset($getid3_temp, $getid3_ac3); 1784 1785 } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) { 1786 1787 // This is probably DTS data 1788 $getid3_temp = new getID3(); 1789 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1790 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1791 $getid3_dts = new getid3_dts($getid3_temp); 1792 $getid3_dts->Analyze(); 1793 if (empty($getid3_temp->info['error'])) { 1794 $info['audio'] = $getid3_temp->info['audio']; 1795 $info['dts'] = $getid3_temp->info['dts']; 1796 $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing 1797 if (!empty($getid3_temp->info['warning'])) { 1798 foreach ($getid3_temp->info['warning'] as $newerror) { 1799 $this->warning('getid3_dts() says: ['.$newerror.']'); 1800 } 1801 } 1802 } 1803 1804 unset($getid3_temp, $getid3_dts); 1805 1806 } elseif (substr($testData, 0, 4) == 'wvpk') { 1807 1808 // This is WavPack data 1809 $info['wavpack']['offset'] = $info['avdataoffset']; 1810 $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4)); 1811 $this->parseWavPackHeader(substr($testData, 8, 28)); 1812 1813 } else { 1814 // This is some other kind of data (quite possibly just PCM) 1815 // do nothing special, just skip it 1816 } 1817 $nextoffset = $info['avdataend']; 1818 $this->fseek($nextoffset); 1819 break; 1820 1821 case 'iXML': 1822 case 'bext': 1823 case 'cart': 1824 case 'fmt ': 1825 case 'strh': 1826 case 'strf': 1827 case 'indx': 1828 case 'MEXT': 1829 case 'DISP': 1830 case 'wamd': 1831 case 'guan': 1832 // always read data in 1833 case 'JUNK': 1834 // should be: never read data in 1835 // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc) 1836 if ($chunksize < 1048576) { 1837 if ($chunksize > 0) { 1838 $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); 1839 if ($chunkname == 'JUNK') { 1840 if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) { 1841 // only keep text characters [chr(32)-chr(127)] 1842 $info['riff']['comments']['junk'][] = trim($matches[1]); 1843 } 1844 // but if nothing there, ignore 1845 // remove the key in either case 1846 unset($RIFFchunk[$chunkname][$thisindex]['data']); 1847 } 1848 } 1849 } else { 1850 $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data'); 1851 $this->fseek($chunksize, SEEK_CUR); 1852 } 1853 break; 1854 1855 //case 'IDVX': 1856 // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize)); 1857 // break; 1858 1859 case 'scot': 1860 // https://cmsdk.com/node-js/adding-scot-chunk-to-wav-file.html 1861 $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); 1862 $RIFFchunk[$chunkname][$thisindex]['parsed']['alter'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 0, 1); 1863 $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 1, 1); 1864 $RIFFchunk[$chunkname][$thisindex]['parsed']['artnum'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 2, 2)); 1865 $RIFFchunk[$chunkname][$thisindex]['parsed']['title'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 4, 43); // "name" in other documentation 1866 $RIFFchunk[$chunkname][$thisindex]['parsed']['copy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 47, 4); 1867 $RIFFchunk[$chunkname][$thisindex]['parsed']['padd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 51, 1); 1868 $RIFFchunk[$chunkname][$thisindex]['parsed']['asclen'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 52, 5); 1869 $RIFFchunk[$chunkname][$thisindex]['parsed']['startseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 57, 2)); 1870 $RIFFchunk[$chunkname][$thisindex]['parsed']['starthundredths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 59, 2)); 1871 $RIFFchunk[$chunkname][$thisindex]['parsed']['endseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 61, 2)); 1872 $RIFFchunk[$chunkname][$thisindex]['parsed']['endhundreths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 63, 2)); 1873 $RIFFchunk[$chunkname][$thisindex]['parsed']['sdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 65, 6); 1874 $RIFFchunk[$chunkname][$thisindex]['parsed']['kdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 71, 6); 1875 $RIFFchunk[$chunkname][$thisindex]['parsed']['start_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 77, 1); 1876 $RIFFchunk[$chunkname][$thisindex]['parsed']['kill_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 78, 1); 1877 $RIFFchunk[$chunkname][$thisindex]['parsed']['digital'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 79, 1); 1878 $RIFFchunk[$chunkname][$thisindex]['parsed']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 80, 2)); 1879 $RIFFchunk[$chunkname][$thisindex]['parsed']['stereo'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 82, 1); 1880 $RIFFchunk[$chunkname][$thisindex]['parsed']['compress'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 83, 1); 1881 $RIFFchunk[$chunkname][$thisindex]['parsed']['eomstrt'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 84, 4)); 1882 $RIFFchunk[$chunkname][$thisindex]['parsed']['eomlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 88, 2)); 1883 $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib2'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 90, 4)); 1884 $RIFFchunk[$chunkname][$thisindex]['parsed']['future1'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 94, 12); 1885 $RIFFchunk[$chunkname][$thisindex]['parsed']['catfontcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 106, 4)); 1886 $RIFFchunk[$chunkname][$thisindex]['parsed']['catcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 110, 4)); 1887 $RIFFchunk[$chunkname][$thisindex]['parsed']['segeompos'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 114, 4)); 1888 $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_startsecs'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 118, 2)); 1889 $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_starthunds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 120, 2)); 1890 $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 122, 3); 1891 $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 125, 4); 1892 $RIFFchunk[$chunkname][$thisindex]['parsed']['priorpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 129, 1); 1893 $RIFFchunk[$chunkname][$thisindex]['parsed']['postcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 130, 3); 1894 $RIFFchunk[$chunkname][$thisindex]['parsed']['postcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 133, 4); 1895 $RIFFchunk[$chunkname][$thisindex]['parsed']['postpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 137, 1); 1896 $RIFFchunk[$chunkname][$thisindex]['parsed']['hrcanplay'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 138, 21); 1897 $RIFFchunk[$chunkname][$thisindex]['parsed']['future2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 159, 108); 1898 $RIFFchunk[$chunkname][$thisindex]['parsed']['artist'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 267, 34); 1899 $RIFFchunk[$chunkname][$thisindex]['parsed']['comment'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 301, 34); // "trivia" in other documentation 1900 $RIFFchunk[$chunkname][$thisindex]['parsed']['intro'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 335, 2); 1901 $RIFFchunk[$chunkname][$thisindex]['parsed']['end'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 337, 1); 1902 $RIFFchunk[$chunkname][$thisindex]['parsed']['year'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 338, 4); 1903 $RIFFchunk[$chunkname][$thisindex]['parsed']['obsolete2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 342, 1); 1904 $RIFFchunk[$chunkname][$thisindex]['parsed']['rec_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 343, 1); 1905 $RIFFchunk[$chunkname][$thisindex]['parsed']['rdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 344, 6); 1906 $RIFFchunk[$chunkname][$thisindex]['parsed']['mpeg_bitrate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 350, 2)); 1907 $RIFFchunk[$chunkname][$thisindex]['parsed']['pitch'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 352, 2)); 1908 $RIFFchunk[$chunkname][$thisindex]['parsed']['playlevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 354, 2)); 1909 $RIFFchunk[$chunkname][$thisindex]['parsed']['lenvalid'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 356, 1); 1910 $RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 357, 4)); 1911 $RIFFchunk[$chunkname][$thisindex]['parsed']['newplaylevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 361, 2)); 1912 $RIFFchunk[$chunkname][$thisindex]['parsed']['chopsize'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 363, 4)); 1913 $RIFFchunk[$chunkname][$thisindex]['parsed']['vteomovr'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 367, 4)); 1914 $RIFFchunk[$chunkname][$thisindex]['parsed']['desiredlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 371, 4)); 1915 $RIFFchunk[$chunkname][$thisindex]['parsed']['triggers'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 375, 4)); 1916 $RIFFchunk[$chunkname][$thisindex]['parsed']['fillout'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 379, 33); 1917 1918 foreach (array('title', 'artist', 'comment') as $key) { 1919 if (trim($RIFFchunk[$chunkname][$thisindex]['parsed'][$key])) { 1920 $info['riff']['comments'][$key] = array($RIFFchunk[$chunkname][$thisindex]['parsed'][$key]); 1921 } 1922 } 1923 if ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] && !empty($info['filesize']) && ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] != $info['filesize'])) { 1924 $this->warning('RIFF.WAVE.scot.filelength ('.$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'].') different from actual filesize ('.$info['filesize'].')'); 1925 } 1926 break; 1927 1928 default: 1929 if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) { 1930 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset']; 1931 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size']; 1932 unset($RIFFchunk[$chunkname][$thisindex]['offset']); 1933 unset($RIFFchunk[$chunkname][$thisindex]['size']); 1934 if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { 1935 unset($RIFFchunk[$chunkname][$thisindex]); 1936 } 1937 if (count($RIFFchunk[$chunkname]) === 0) { 1938 unset($RIFFchunk[$chunkname]); 1939 } 1940 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); 1941 } elseif ($chunksize < 2048) { 1942 // only read data in if smaller than 2kB 1943 $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); 1944 } else { 1945 $this->fseek($chunksize, SEEK_CUR); 1946 } 1947 break; 1948 } 1949 break; 1950 } 1951 } 1952 1953 } catch (getid3_exception $e) { 1954 if ($e->getCode() == 10) { 1955 $this->warning('RIFF parser: '.$e->getMessage()); 1956 } else { 1957 throw $e; 1958 } 1959 } 1960 1961 return !empty($RIFFchunk) ? $RIFFchunk : false; 1962 } 1963 1964 /** 1965 * @param string $RIFFdata 1966 * 1967 * @return bool 1968 */ 1969 public function ParseRIFFdata(&$RIFFdata) { 1970 $info = &$this->getid3->info; 1971 if ($RIFFdata) { 1972 $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3'); 1973 $fp_temp = fopen($tempfile, 'wb'); 1974 $RIFFdataLength = strlen($RIFFdata); 1975 $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4); 1976 for ($i = 0; $i < 4; $i++) { 1977 $RIFFdata[($i + 4)] = $NewLengthString[$i]; 1978 } 1979 fwrite($fp_temp, $RIFFdata); 1980 fclose($fp_temp); 1981 1982 $getid3_temp = new getID3(); 1983 $getid3_temp->openfile($tempfile); 1984 $getid3_temp->info['filesize'] = $RIFFdataLength; 1985 $getid3_temp->info['filenamepath'] = $info['filenamepath']; 1986 $getid3_temp->info['tags'] = $info['tags']; 1987 $getid3_temp->info['warning'] = $info['warning']; 1988 $getid3_temp->info['error'] = $info['error']; 1989 $getid3_temp->info['comments'] = $info['comments']; 1990 $getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array()); 1991 $getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array()); 1992 $getid3_riff = new getid3_riff($getid3_temp); 1993 $getid3_riff->Analyze(); 1994 1995 $info['riff'] = $getid3_temp->info['riff']; 1996 $info['warning'] = $getid3_temp->info['warning']; 1997 $info['error'] = $getid3_temp->info['error']; 1998 $info['tags'] = $getid3_temp->info['tags']; 1999 $info['comments'] = $getid3_temp->info['comments']; 2000 unset($getid3_riff, $getid3_temp); 2001 unlink($tempfile); 2002 } 2003 return false; 2004 } 2005 2006 /** 2007 * @param array $RIFFinfoArray 2008 * @param array $CommentsTargetArray 2009 * 2010 * @return bool 2011 */ 2012 public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) { 2013 $RIFFinfoKeyLookup = array( 2014 'IARL'=>'archivallocation', 2015 'IART'=>'artist', 2016 'ICDS'=>'costumedesigner', 2017 'ICMS'=>'commissionedby', 2018 'ICMT'=>'comment', 2019 'ICNT'=>'country', 2020 'ICOP'=>'copyright', 2021 'ICRD'=>'creationdate', 2022 'IDIM'=>'dimensions', 2023 'IDIT'=>'digitizationdate', 2024 'IDPI'=>'resolution', 2025 'IDST'=>'distributor', 2026 'IEDT'=>'editor', 2027 'IENG'=>'engineers', 2028 'IFRM'=>'accountofparts', 2029 'IGNR'=>'genre', 2030 'IKEY'=>'keywords', 2031 'ILGT'=>'lightness', 2032 'ILNG'=>'language', 2033 'IMED'=>'orignalmedium', 2034 'IMUS'=>'composer', 2035 'INAM'=>'title', 2036 'IPDS'=>'productiondesigner', 2037 'IPLT'=>'palette', 2038 'IPRD'=>'product', 2039 'IPRO'=>'producer', 2040 'IPRT'=>'part', 2041 'IRTD'=>'rating', 2042 'ISBJ'=>'subject', 2043 'ISFT'=>'software', 2044 'ISGN'=>'secondarygenre', 2045 'ISHP'=>'sharpness', 2046 'ISRC'=>'sourcesupplier', 2047 'ISRF'=>'digitizationsource', 2048 'ISTD'=>'productionstudio', 2049 'ISTR'=>'starring', 2050 'ITCH'=>'encoded_by', 2051 'IWEB'=>'url', 2052 'IWRI'=>'writer', 2053 '____'=>'comment', 2054 ); 2055 foreach ($RIFFinfoKeyLookup as $key => $value) { 2056 if (isset($RIFFinfoArray[$key])) { 2057 foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { 2058 if (!empty($commentdata['data']) && trim($commentdata['data']) != '') { 2059 if (isset($CommentsTargetArray[$value])) { 2060 $CommentsTargetArray[$value][] = trim($commentdata['data']); 2061 } else { 2062 $CommentsTargetArray[$value] = array(trim($commentdata['data'])); 2063 } 2064 } 2065 } 2066 } 2067 } 2068 return true; 2069 } 2070 2071 /** 2072 * @param string $WaveFormatExData 2073 * 2074 * @return array 2075 */ 2076 public static function parseWAVEFORMATex($WaveFormatExData) { 2077 // shortcut 2078 $WaveFormatEx = array(); 2079 $WaveFormatEx['raw'] = array(); 2080 $WaveFormatEx_raw = &$WaveFormatEx['raw']; 2081 2082 $WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2); 2083 $WaveFormatEx_raw['nChannels'] = substr($WaveFormatExData, 2, 2); 2084 $WaveFormatEx_raw['nSamplesPerSec'] = substr($WaveFormatExData, 4, 4); 2085 $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData, 8, 4); 2086 $WaveFormatEx_raw['nBlockAlign'] = substr($WaveFormatExData, 12, 2); 2087 $WaveFormatEx_raw['wBitsPerSample'] = substr($WaveFormatExData, 14, 2); 2088 if (strlen($WaveFormatExData) > 16) { 2089 $WaveFormatEx_raw['cbSize'] = substr($WaveFormatExData, 16, 2); 2090 } 2091 $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw); 2092 2093 $WaveFormatEx['codec'] = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']); 2094 $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels']; 2095 $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec']; 2096 $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8; 2097 $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample']; 2098 2099 return $WaveFormatEx; 2100 } 2101 2102 /** 2103 * @param string $WavPackChunkData 2104 * 2105 * @return bool 2106 */ 2107 public function parseWavPackHeader($WavPackChunkData) { 2108 // typedef struct { 2109 // char ckID [4]; 2110 // long ckSize; 2111 // short version; 2112 // short bits; // added for version 2.00 2113 // short flags, shift; // added for version 3.00 2114 // long total_samples, crc, crc2; 2115 // char extension [4], extra_bc, extras [3]; 2116 // } WavpackHeader; 2117 2118 // shortcut 2119 $info = &$this->getid3->info; 2120 $info['wavpack'] = array(); 2121 $thisfile_wavpack = &$info['wavpack']; 2122 2123 $thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2)); 2124 if ($thisfile_wavpack['version'] >= 2) { 2125 $thisfile_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 2, 2)); 2126 } 2127 if ($thisfile_wavpack['version'] >= 3) { 2128 $thisfile_wavpack['flags_raw'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 4, 2)); 2129 $thisfile_wavpack['shift'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 6, 2)); 2130 $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 8, 4)); 2131 $thisfile_wavpack['crc1'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4)); 2132 $thisfile_wavpack['crc2'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4)); 2133 $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4); 2134 $thisfile_wavpack['extra_bc'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1)); 2135 for ($i = 0; $i <= 2; $i++) { 2136 $thisfile_wavpack['extras'][] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1)); 2137 } 2138 2139 // shortcut 2140 $thisfile_wavpack['flags'] = array(); 2141 $thisfile_wavpack_flags = &$thisfile_wavpack['flags']; 2142 2143 $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001); 2144 $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002); 2145 $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004); 2146 $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008); 2147 $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010); 2148 $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020); 2149 $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040); 2150 $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080); 2151 $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100); 2152 $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200); 2153 $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400); 2154 $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800); 2155 $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000); 2156 $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000); 2157 $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000); 2158 $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000); 2159 $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000); 2160 $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000); 2161 $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000); 2162 $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000); 2163 } 2164 2165 return true; 2166 } 2167 2168 /** 2169 * @param string $BITMAPINFOHEADER 2170 * @param bool $littleEndian 2171 * 2172 * @return array 2173 */ 2174 public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) { 2175 2176 $parsed = array(); 2177 $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure 2178 $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels 2179 $parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner 2180 $parsed['biPlanes'] = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1 2181 $parsed['biBitCount'] = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels 2182 $parsed['biSizeImage'] = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures) 2183 $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device 2184 $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device 2185 $parsed['biClrUsed'] = substr($BITMAPINFOHEADER, 32, 4); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression 2186 $parsed['biClrImportant'] = substr($BITMAPINFOHEADER, 36, 4); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important 2187 $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed); 2188 2189 $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier 2190 2191 return $parsed; 2192 } 2193 2194 /** 2195 * @param string $DIVXTAG 2196 * @param bool $raw 2197 * 2198 * @return array 2199 */ 2200 public static function ParseDIVXTAG($DIVXTAG, $raw=false) { 2201 // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/ 2202 // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip 2203 // 'Byte Layout: '1111111111111111 2204 // '32 for Movie - 1 '1111111111111111 2205 // '28 for Author - 6 '6666666666666666 2206 // '4 for year - 2 '6666666666662222 2207 // '3 for genre - 3 '7777777777777777 2208 // '48 for Comments - 7 '7777777777777777 2209 // '1 for Rating - 4 '7777777777777777 2210 // '5 for Future Additions - 0 '333400000DIVXTAG 2211 // '128 bytes total 2212 2213 static $DIVXTAGgenre = array( 2214 0 => 'Action', 2215 1 => 'Action/Adventure', 2216 2 => 'Adventure', 2217 3 => 'Adult', 2218 4 => 'Anime', 2219 5 => 'Cartoon', 2220 6 => 'Claymation', 2221 7 => 'Comedy', 2222 8 => 'Commercial', 2223 9 => 'Documentary', 2224 10 => 'Drama', 2225 11 => 'Home Video', 2226 12 => 'Horror', 2227 13 => 'Infomercial', 2228 14 => 'Interactive', 2229 15 => 'Mystery', 2230 16 => 'Music Video', 2231 17 => 'Other', 2232 18 => 'Religion', 2233 19 => 'Sci Fi', 2234 20 => 'Thriller', 2235 21 => 'Western', 2236 ), 2237 $DIVXTAGrating = array( 2238 0 => 'Unrated', 2239 1 => 'G', 2240 2 => 'PG', 2241 3 => 'PG-13', 2242 4 => 'R', 2243 5 => 'NC-17', 2244 ); 2245 2246 $parsed = array(); 2247 $parsed['title'] = trim(substr($DIVXTAG, 0, 32)); 2248 $parsed['artist'] = trim(substr($DIVXTAG, 32, 28)); 2249 $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4))); 2250 $parsed['comment'] = trim(substr($DIVXTAG, 64, 48)); 2251 $parsed['genre_id'] = intval(trim(substr($DIVXTAG, 112, 3))); 2252 $parsed['rating_id'] = ord(substr($DIVXTAG, 115, 1)); 2253 //$parsed['padding'] = substr($DIVXTAG, 116, 5); // 5-byte null 2254 //$parsed['magic'] = substr($DIVXTAG, 121, 7); // "DIVXTAG" 2255 2256 $parsed['genre'] = (isset($DIVXTAGgenre[$parsed['genre_id']]) ? $DIVXTAGgenre[$parsed['genre_id']] : $parsed['genre_id']); 2257 $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']); 2258 2259 if (!$raw) { 2260 unset($parsed['genre_id'], $parsed['rating_id']); 2261 foreach ($parsed as $key => $value) { 2262 if (empty($value)) { 2263 unset($parsed[$key]); 2264 } 2265 } 2266 } 2267 2268 foreach ($parsed as $tag => $value) { 2269 $parsed[$tag] = array($value); 2270 } 2271 2272 return $parsed; 2273 } 2274 2275 /** 2276 * @param string $tagshortname 2277 * 2278 * @return string 2279 */ 2280 public static function waveSNDMtagLookup($tagshortname) { 2281 $begin = __LINE__; 2282 2283 /** This is not a comment! 2284 2285 ©kwd keywords 2286 ©BPM bpm 2287 ©trt tracktitle 2288 ©des description 2289 ©gen category 2290 ©fin featuredinstrument 2291 ©LID longid 2292 ©bex bwdescription 2293 ©pub publisher 2294 ©cdt cdtitle 2295 ©alb library 2296 ©com composer 2297 2298 */ 2299 2300 return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm'); 2301 } 2302 2303 /** 2304 * @param int $wFormatTag 2305 * 2306 * @return string 2307 */ 2308 public static function wFormatTagLookup($wFormatTag) { 2309 2310 $begin = __LINE__; 2311 2312 /** This is not a comment! 2313 2314 0x0000 Microsoft Unknown Wave Format 2315 0x0001 Pulse Code Modulation (PCM) 2316 0x0002 Microsoft ADPCM 2317 0x0003 IEEE Float 2318 0x0004 Compaq Computer VSELP 2319 0x0005 IBM CVSD 2320 0x0006 Microsoft A-Law 2321 0x0007 Microsoft mu-Law 2322 0x0008 Microsoft DTS 2323 0x0010 OKI ADPCM 2324 0x0011 Intel DVI/IMA ADPCM 2325 0x0012 Videologic MediaSpace ADPCM 2326 0x0013 Sierra Semiconductor ADPCM 2327 0x0014 Antex Electronics G.723 ADPCM 2328 0x0015 DSP Solutions DigiSTD 2329 0x0016 DSP Solutions DigiFIX 2330 0x0017 Dialogic OKI ADPCM 2331 0x0018 MediaVision ADPCM 2332 0x0019 Hewlett-Packard CU 2333 0x0020 Yamaha ADPCM 2334 0x0021 Speech Compression Sonarc 2335 0x0022 DSP Group TrueSpeech 2336 0x0023 Echo Speech EchoSC1 2337 0x0024 Audiofile AF36 2338 0x0025 Audio Processing Technology APTX 2339 0x0026 AudioFile AF10 2340 0x0027 Prosody 1612 2341 0x0028 LRC 2342 0x0030 Dolby AC2 2343 0x0031 Microsoft GSM 6.10 2344 0x0032 MSNAudio 2345 0x0033 Antex Electronics ADPCME 2346 0x0034 Control Resources VQLPC 2347 0x0035 DSP Solutions DigiREAL 2348 0x0036 DSP Solutions DigiADPCM 2349 0x0037 Control Resources CR10 2350 0x0038 Natural MicroSystems VBXADPCM 2351 0x0039 Crystal Semiconductor IMA ADPCM 2352 0x003A EchoSC3 2353 0x003B Rockwell ADPCM 2354 0x003C Rockwell Digit LK 2355 0x003D Xebec 2356 0x0040 Antex Electronics G.721 ADPCM 2357 0x0041 G.728 CELP 2358 0x0042 MSG723 2359 0x0050 MPEG Layer-2 or Layer-1 2360 0x0052 RT24 2361 0x0053 PAC 2362 0x0055 MPEG Layer-3 2363 0x0059 Lucent G.723 2364 0x0060 Cirrus 2365 0x0061 ESPCM 2366 0x0062 Voxware 2367 0x0063 Canopus Atrac 2368 0x0064 G.726 ADPCM 2369 0x0065 G.722 ADPCM 2370 0x0066 DSAT 2371 0x0067 DSAT Display 2372 0x0069 Voxware Byte Aligned 2373 0x0070 Voxware AC8 2374 0x0071 Voxware AC10 2375 0x0072 Voxware AC16 2376 0x0073 Voxware AC20 2377 0x0074 Voxware MetaVoice 2378 0x0075 Voxware MetaSound 2379 0x0076 Voxware RT29HW 2380 0x0077 Voxware VR12 2381 0x0078 Voxware VR18 2382 0x0079 Voxware TQ40 2383 0x0080 Softsound 2384 0x0081 Voxware TQ60 2385 0x0082 MSRT24 2386 0x0083 G.729A 2387 0x0084 MVI MV12 2388 0x0085 DF G.726 2389 0x0086 DF GSM610 2390 0x0088 ISIAudio 2391 0x0089 Onlive 2392 0x0091 SBC24 2393 0x0092 Dolby AC3 SPDIF 2394 0x0093 MediaSonic G.723 2395 0x0094 Aculab PLC Prosody 8kbps 2396 0x0097 ZyXEL ADPCM 2397 0x0098 Philips LPCBB 2398 0x0099 Packed 2399 0x00FF AAC 2400 0x0100 Rhetorex ADPCM 2401 0x0101 IBM mu-law 2402 0x0102 IBM A-law 2403 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM) 2404 0x0111 Vivo G.723 2405 0x0112 Vivo Siren 2406 0x0123 Digital G.723 2407 0x0125 Sanyo LD ADPCM 2408 0x0130 Sipro Lab Telecom ACELP NET 2409 0x0131 Sipro Lab Telecom ACELP 4800 2410 0x0132 Sipro Lab Telecom ACELP 8V3 2411 0x0133 Sipro Lab Telecom G.729 2412 0x0134 Sipro Lab Telecom G.729A 2413 0x0135 Sipro Lab Telecom Kelvin 2414 0x0140 Windows Media Video V8 2415 0x0150 Qualcomm PureVoice 2416 0x0151 Qualcomm HalfRate 2417 0x0155 Ring Zero Systems TUB GSM 2418 0x0160 Microsoft Audio 1 2419 0x0161 Windows Media Audio V7 / V8 / V9 2420 0x0162 Windows Media Audio Professional V9 2421 0x0163 Windows Media Audio Lossless V9 2422 0x0200 Creative Labs ADPCM 2423 0x0202 Creative Labs Fastspeech8 2424 0x0203 Creative Labs Fastspeech10 2425 0x0210 UHER Informatic GmbH ADPCM 2426 0x0220 Quarterdeck 2427 0x0230 I-link Worldwide VC 2428 0x0240 Aureal RAW Sport 2429 0x0250 Interactive Products HSX 2430 0x0251 Interactive Products RPELP 2431 0x0260 Consistent Software CS2 2432 0x0270 Sony SCX 2433 0x0300 Fujitsu FM Towns Snd 2434 0x0400 BTV Digital 2435 0x0401 Intel Music Coder 2436 0x0450 QDesign Music 2437 0x0680 VME VMPCM 2438 0x0681 AT&T Labs TPC 2439 0x08AE ClearJump LiteWave 2440 0x1000 Olivetti GSM 2441 0x1001 Olivetti ADPCM 2442 0x1002 Olivetti CELP 2443 0x1003 Olivetti SBC 2444 0x1004 Olivetti OPR 2445 0x1100 Lernout & Hauspie Codec (0x1100) 2446 0x1101 Lernout & Hauspie CELP Codec (0x1101) 2447 0x1102 Lernout & Hauspie SBC Codec (0x1102) 2448 0x1103 Lernout & Hauspie SBC Codec (0x1103) 2449 0x1104 Lernout & Hauspie SBC Codec (0x1104) 2450 0x1400 Norris 2451 0x1401 AT&T ISIAudio 2452 0x1500 Soundspace Music Compression 2453 0x181C VoxWare RT24 Speech 2454 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com) 2455 0x2000 Dolby AC3 2456 0x2001 Dolby DTS 2457 0x2002 WAVE_FORMAT_14_4 2458 0x2003 WAVE_FORMAT_28_8 2459 0x2004 WAVE_FORMAT_COOK 2460 0x2005 WAVE_FORMAT_DNET 2461 0x674F Ogg Vorbis 1 2462 0x6750 Ogg Vorbis 2 2463 0x6751 Ogg Vorbis 3 2464 0x676F Ogg Vorbis 1+ 2465 0x6770 Ogg Vorbis 2+ 2466 0x6771 Ogg Vorbis 3+ 2467 0x7A21 GSM-AMR (CBR, no SID) 2468 0x7A22 GSM-AMR (VBR, including SID) 2469 0xFFFE WAVE_FORMAT_EXTENSIBLE 2470 0xFFFF WAVE_FORMAT_DEVELOPMENT 2471 2472 */ 2473 2474 return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag'); 2475 } 2476 2477 /** 2478 * @param string $fourcc 2479 * 2480 * @return string 2481 */ 2482 public static function fourccLookup($fourcc) { 2483 2484 $begin = __LINE__; 2485 2486 /** This is not a comment! 2487 2488 swot http://developer.apple.com/qa/snd/snd07.html 2489 ____ No Codec (____) 2490 _BIT BI_BITFIELDS (Raw RGB) 2491 _JPG JPEG compressed 2492 _PNG PNG compressed W3C/ISO/IEC (RFC-2083) 2493 _RAW Full Frames (Uncompressed) 2494 _RGB Raw RGB Bitmap 2495 _RL4 RLE 4bpp RGB 2496 _RL8 RLE 8bpp RGB 2497 3IV1 3ivx MPEG-4 v1 2498 3IV2 3ivx MPEG-4 v2 2499 3IVX 3ivx MPEG-4 2500 AASC Autodesk Animator 2501 ABYR Kensington ?ABYR? 2502 AEMI Array Microsystems VideoONE MPEG1-I Capture 2503 AFLC Autodesk Animator FLC 2504 AFLI Autodesk Animator FLI 2505 AMPG Array Microsystems VideoONE MPEG 2506 ANIM Intel RDX (ANIM) 2507 AP41 AngelPotion Definitive 2508 ASV1 Asus Video v1 2509 ASV2 Asus Video v2 2510 ASVX Asus Video 2.0 (audio) 2511 AUR2 AuraVision Aura 2 Codec - YUV 4:2:2 2512 AURA AuraVision Aura 1 Codec - YUV 4:1:1 2513 AVDJ Independent JPEG Group\'s codec (AVDJ) 2514 AVRN Independent JPEG Group\'s codec (AVRN) 2515 AYUV 4:4:4 YUV (AYUV) 2516 AZPR Quicktime Apple Video (AZPR) 2517 BGR Raw RGB32 2518 BLZ0 Blizzard DivX MPEG-4 2519 BTVC Conexant Composite Video 2520 BINK RAD Game Tools Bink Video 2521 BT20 Conexant Prosumer Video 2522 BTCV Conexant Composite Video Codec 2523 BW10 Data Translation Broadway MPEG Capture 2524 CC12 Intel YUV12 2525 CDVC Canopus DV 2526 CFCC Digital Processing Systems DPS Perception 2527 CGDI Microsoft Office 97 Camcorder Video 2528 CHAM Winnov Caviara Champagne 2529 CJPG Creative WebCam JPEG 2530 CLJR Cirrus Logic YUV 4:1:1 2531 CMYK Common Data Format in Printing (Colorgraph) 2532 CPLA Weitek 4:2:0 YUV Planar 2533 CRAM Microsoft Video 1 (CRAM) 2534 cvid Radius Cinepak 2535 CVID Radius Cinepak 2536 CWLT Microsoft Color WLT DIB 2537 CYUV Creative Labs YUV 2538 CYUY ATI YUV 2539 D261 H.261 2540 D263 H.263 2541 DIB Device Independent Bitmap 2542 DIV1 FFmpeg OpenDivX 2543 DIV2 Microsoft MPEG-4 v1/v2 2544 DIV3 DivX ;-) MPEG-4 v3.x Low-Motion 2545 DIV4 DivX ;-) MPEG-4 v3.x Fast-Motion 2546 DIV5 DivX MPEG-4 v5.x 2547 DIV6 DivX ;-) (MS MPEG-4 v3.x) 2548 DIVX DivX MPEG-4 v4 (OpenDivX / Project Mayo) 2549 divx DivX MPEG-4 2550 DMB1 Matrox Rainbow Runner hardware MJPEG 2551 DMB2 Paradigm MJPEG 2552 DSVD ?DSVD? 2553 DUCK Duck TrueMotion 1.0 2554 DPS0 DPS/Leitch Reality Motion JPEG 2555 DPSC DPS/Leitch PAR Motion JPEG 2556 DV25 Matrox DVCPRO codec 2557 DV50 Matrox DVCPRO50 codec 2558 DVC IEC 61834 and SMPTE 314M (DVC/DV Video) 2559 DVCP IEC 61834 and SMPTE 314M (DVC/DV Video) 2560 DVHD IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps 2561 DVMA Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com) 2562 DVSL IEC Standard DV compressed in SD (SDL) 2563 DVAN ?DVAN? 2564 DVE2 InSoft DVE-2 Videoconferencing 2565 dvsd IEC 61834 and SMPTE 314M DVC/DV Video 2566 DVSD IEC 61834 and SMPTE 314M DVC/DV Video 2567 DVX1 Lucent DVX1000SP Video Decoder 2568 DVX2 Lucent DVX2000S Video Decoder 2569 DVX3 Lucent DVX3000S Video Decoder 2570 DX50 DivX v5 2571 DXT1 Microsoft DirectX Compressed Texture (DXT1) 2572 DXT2 Microsoft DirectX Compressed Texture (DXT2) 2573 DXT3 Microsoft DirectX Compressed Texture (DXT3) 2574 DXT4 Microsoft DirectX Compressed Texture (DXT4) 2575 DXT5 Microsoft DirectX Compressed Texture (DXT5) 2576 DXTC Microsoft DirectX Compressed Texture (DXTC) 2577 DXTn Microsoft DirectX Compressed Texture (DXTn) 2578 EM2V Etymonix MPEG-2 I-frame (www.etymonix.com) 2579 EKQ0 Elsa ?EKQ0? 2580 ELK0 Elsa ?ELK0? 2581 ESCP Eidos Escape 2582 ETV1 eTreppid Video ETV1 2583 ETV2 eTreppid Video ETV2 2584 ETVC eTreppid Video ETVC 2585 FLIC Autodesk FLI/FLC Animation 2586 FLV1 Sorenson Spark 2587 FLV4 On2 TrueMotion VP6 2588 FRWT Darim Vision Forward Motion JPEG (www.darvision.com) 2589 FRWU Darim Vision Forward Uncompressed (www.darvision.com) 2590 FLJP D-Vision Field Encoded Motion JPEG 2591 FPS1 FRAPS v1 2592 FRWA SoftLab-Nsk Forward Motion JPEG w/ alpha channel 2593 FRWD SoftLab-Nsk Forward Motion JPEG 2594 FVF1 Iterated Systems Fractal Video Frame 2595 GLZW Motion LZW (gabest@freemail.hu) 2596 GPEG Motion JPEG (gabest@freemail.hu) 2597 GWLT Microsoft Greyscale WLT DIB 2598 H260 Intel ITU H.260 Videoconferencing 2599 H261 Intel ITU H.261 Videoconferencing 2600 H262 Intel ITU H.262 Videoconferencing 2601 H263 Intel ITU H.263 Videoconferencing 2602 H264 Intel ITU H.264 Videoconferencing 2603 H265 Intel ITU H.265 Videoconferencing 2604 H266 Intel ITU H.266 Videoconferencing 2605 H267 Intel ITU H.267 Videoconferencing 2606 H268 Intel ITU H.268 Videoconferencing 2607 H269 Intel ITU H.269 Videoconferencing 2608 HFYU Huffman Lossless Codec 2609 HMCR Rendition Motion Compensation Format (HMCR) 2610 HMRR Rendition Motion Compensation Format (HMRR) 2611 I263 FFmpeg I263 decoder 2612 IF09 Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane") 2613 IUYV Interlaced version of UYVY (www.leadtools.com) 2614 IY41 Interlaced version of Y41P (www.leadtools.com) 2615 IYU1 12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard 2616 IYU2 24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard 2617 IYUV Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes) 2618 i263 Intel ITU H.263 Videoconferencing (i263) 2619 I420 Intel Indeo 4 2620 IAN Intel Indeo 4 (RDX) 2621 ICLB InSoft CellB Videoconferencing 2622 IGOR Power DVD 2623 IJPG Intergraph JPEG 2624 ILVC Intel Layered Video 2625 ILVR ITU-T H.263+ 2626 IPDV I-O Data Device Giga AVI DV Codec 2627 IR21 Intel Indeo 2.1 2628 IRAW Intel YUV Uncompressed 2629 IV30 Intel Indeo 3.0 2630 IV31 Intel Indeo 3.1 2631 IV32 Ligos Indeo 3.2 2632 IV33 Ligos Indeo 3.3 2633 IV34 Ligos Indeo 3.4 2634 IV35 Ligos Indeo 3.5 2635 IV36 Ligos Indeo 3.6 2636 IV37 Ligos Indeo 3.7 2637 IV38 Ligos Indeo 3.8 2638 IV39 Ligos Indeo 3.9 2639 IV40 Ligos Indeo Interactive 4.0 2640 IV41 Ligos Indeo Interactive 4.1 2641 IV42 Ligos Indeo Interactive 4.2 2642 IV43 Ligos Indeo Interactive 4.3 2643 IV44 Ligos Indeo Interactive 4.4 2644 IV45 Ligos Indeo Interactive 4.5 2645 IV46 Ligos Indeo Interactive 4.6 2646 IV47 Ligos Indeo Interactive 4.7 2647 IV48 Ligos Indeo Interactive 4.8 2648 IV49 Ligos Indeo Interactive 4.9 2649 IV50 Ligos Indeo Interactive 5.0 2650 JBYR Kensington ?JBYR? 2651 JPEG Still Image JPEG DIB 2652 JPGL Pegasus Lossless Motion JPEG 2653 KMVC Team17 Software Karl Morton\'s Video Codec 2654 LSVM Vianet Lighting Strike Vmail (Streaming) (www.vianet.com) 2655 LEAD LEAD Video Codec 2656 Ljpg LEAD MJPEG Codec 2657 MDVD Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de) 2658 MJPA Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com) 2659 MJPB Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com) 2660 MMES Matrox MPEG-2 I-frame 2661 MP2v Microsoft S-Mpeg 4 version 1 (MP2v) 2662 MP42 Microsoft S-Mpeg 4 version 2 (MP42) 2663 MP43 Microsoft S-Mpeg 4 version 3 (MP43) 2664 MP4S Microsoft S-Mpeg 4 version 3 (MP4S) 2665 MP4V FFmpeg MPEG-4 2666 MPG1 FFmpeg MPEG 1/2 2667 MPG2 FFmpeg MPEG 1/2 2668 MPG3 FFmpeg DivX ;-) (MS MPEG-4 v3) 2669 MPG4 Microsoft MPEG-4 2670 MPGI Sigma Designs MPEG 2671 MPNG PNG images decoder 2672 MSS1 Microsoft Windows Screen Video 2673 MSZH LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm) 2674 M261 Microsoft H.261 2675 M263 Microsoft H.263 2676 M4S2 Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2) 2677 m4s2 Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2) 2678 MC12 ATI Motion Compensation Format (MC12) 2679 MCAM ATI Motion Compensation Format (MCAM) 2680 MJ2C Morgan Multimedia Motion JPEG2000 2681 mJPG IBM Motion JPEG w/ Huffman Tables 2682 MJPG Microsoft Motion JPEG DIB 2683 MP42 Microsoft MPEG-4 (low-motion) 2684 MP43 Microsoft MPEG-4 (fast-motion) 2685 MP4S Microsoft MPEG-4 (MP4S) 2686 mp4s Microsoft MPEG-4 (mp4s) 2687 MPEG Chromatic Research MPEG-1 Video I-Frame 2688 MPG4 Microsoft MPEG-4 Video High Speed Compressor 2689 MPGI Sigma Designs MPEG 2690 MRCA FAST Multimedia Martin Regen Codec 2691 MRLE Microsoft Run Length Encoding 2692 MSVC Microsoft Video 1 2693 MTX1 Matrox ?MTX1? 2694 MTX2 Matrox ?MTX2? 2695 MTX3 Matrox ?MTX3? 2696 MTX4 Matrox ?MTX4? 2697 MTX5 Matrox ?MTX5? 2698 MTX6 Matrox ?MTX6? 2699 MTX7 Matrox ?MTX7? 2700 MTX8 Matrox ?MTX8? 2701 MTX9 Matrox ?MTX9? 2702 MV12 Motion Pixels Codec (old) 2703 MWV1 Aware Motion Wavelets 2704 nAVI SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm) 2705 NT00 NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com) 2706 NUV1 NuppelVideo 2707 NTN1 Nogatech Video Compression 1 2708 NVS0 nVidia GeForce Texture (NVS0) 2709 NVS1 nVidia GeForce Texture (NVS1) 2710 NVS2 nVidia GeForce Texture (NVS2) 2711 NVS3 nVidia GeForce Texture (NVS3) 2712 NVS4 nVidia GeForce Texture (NVS4) 2713 NVS5 nVidia GeForce Texture (NVS5) 2714 NVT0 nVidia GeForce Texture (NVT0) 2715 NVT1 nVidia GeForce Texture (NVT1) 2716 NVT2 nVidia GeForce Texture (NVT2) 2717 NVT3 nVidia GeForce Texture (NVT3) 2718 NVT4 nVidia GeForce Texture (NVT4) 2719 NVT5 nVidia GeForce Texture (NVT5) 2720 PIXL MiroXL, Pinnacle PCTV 2721 PDVC I-O Data Device Digital Video Capture DV codec 2722 PGVV Radius Video Vision 2723 PHMO IBM Photomotion 2724 PIM1 MPEG Realtime (Pinnacle Cards) 2725 PIM2 Pegasus Imaging ?PIM2? 2726 PIMJ Pegasus Imaging Lossless JPEG 2727 PVEZ Horizons Technology PowerEZ 2728 PVMM PacketVideo Corporation MPEG-4 2729 PVW2 Pegasus Imaging Wavelet Compression 2730 Q1.0 Q-Team\'s QPEG 1.0 (www.q-team.de) 2731 Q1.1 Q-Team\'s QPEG 1.1 (www.q-team.de) 2732 QPEG Q-Team QPEG 1.0 2733 qpeq Q-Team QPEG 1.1 2734 RGB Raw BGR32 2735 RGBA Raw RGB w/ Alpha 2736 RMP4 REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com) 2737 ROQV Id RoQ File Video Decoder 2738 RPZA Quicktime Apple Video (RPZA) 2739 RUD0 Rududu video codec (http://rududu.ifrance.com/rududu/) 2740 RV10 RealVideo 1.0 (aka RealVideo 5.0) 2741 RV13 RealVideo 1.0 (RV13) 2742 RV20 RealVideo G2 2743 RV30 RealVideo 8 2744 RV40 RealVideo 9 2745 RGBT Raw RGB w/ Transparency 2746 RLE Microsoft Run Length Encoder 2747 RLE4 Run Length Encoded (4bpp, 16-color) 2748 RLE8 Run Length Encoded (8bpp, 256-color) 2749 RT21 Intel Indeo RealTime Video 2.1 2750 rv20 RealVideo G2 2751 rv30 RealVideo 8 2752 RVX Intel RDX (RVX ) 2753 SMC Apple Graphics (SMC ) 2754 SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2 2755 SPIG Radius Spigot 2756 SVQ3 Sorenson Video 3 (Apple Quicktime 5) 2757 s422 Tekram VideoCap C210 YUV 4:2:2 2758 SDCC Sun Communication Digital Camera Codec 2759 SFMC CrystalNet Surface Fitting Method 2760 SMSC Radius SMSC 2761 SMSD Radius SMSD 2762 smsv WorldConnect Wavelet Video 2763 SPIG Radius Spigot 2764 SPLC Splash Studios ACM Audio Codec (www.splashstudios.net) 2765 SQZ2 Microsoft VXTreme Video Codec V2 2766 STVA ST Microelectronics CMOS Imager Data (Bayer) 2767 STVB ST Microelectronics CMOS Imager Data (Nudged Bayer) 2768 STVC ST Microelectronics CMOS Imager Data (Bunched) 2769 STVX ST Microelectronics CMOS Imager Data (Extended CODEC Data Format) 2770 STVY ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data) 2771 SV10 Sorenson Video R1 2772 SVQ1 Sorenson Video 2773 T420 Toshiba YUV 4:2:0 2774 TM2A Duck TrueMotion Archiver 2.0 (www.duck.com) 2775 TVJP Pinnacle/Truevision Targa 2000 board (TVJP) 2776 TVMJ Pinnacle/Truevision Targa 2000 board (TVMJ) 2777 TY0N Tecomac Low-Bit Rate Codec (www.tecomac.com) 2778 TY2C Trident Decompression Driver 2779 TLMS TeraLogic Motion Intraframe Codec (TLMS) 2780 TLST TeraLogic Motion Intraframe Codec (TLST) 2781 TM20 Duck TrueMotion 2.0 2782 TM2X Duck TrueMotion 2X 2783 TMIC TeraLogic Motion Intraframe Codec (TMIC) 2784 TMOT Horizons Technology TrueMotion S 2785 tmot Horizons TrueMotion Video Compression 2786 TR20 Duck TrueMotion RealTime 2.0 2787 TSCC TechSmith Screen Capture Codec 2788 TV10 Tecomac Low-Bit Rate Codec 2789 TY2N Trident ?TY2N? 2790 U263 UB Video H.263/H.263+/H.263++ Decoder 2791 UMP4 UB Video MPEG 4 (www.ubvideo.com) 2792 UYNV Nvidia UYVY packed 4:2:2 2793 UYVP Evans & Sutherland YCbCr 4:2:2 extended precision 2794 UCOD eMajix.com ClearVideo 2795 ULTI IBM Ultimotion 2796 UYVY UYVY packed 4:2:2 2797 V261 Lucent VX2000S 2798 VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/) 2799 VIV1 FFmpeg H263+ decoder 2800 VIV2 Vivo H.263 2801 VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf) 2802 VTLP Alaris VideoGramPiX 2803 VYU9 ATI YUV (VYU9) 2804 VYUY ATI YUV (VYUY) 2805 V261 Lucent VX2000S 2806 V422 Vitec Multimedia 24-bit YUV 4:2:2 Format 2807 V655 Vitec Multimedia 16-bit YUV 4:2:2 Format 2808 VCR1 ATI Video Codec 1 2809 VCR2 ATI Video Codec 2 2810 VCR3 ATI VCR 3.0 2811 VCR4 ATI VCR 4.0 2812 VCR5 ATI VCR 5.0 2813 VCR6 ATI VCR 6.0 2814 VCR7 ATI VCR 7.0 2815 VCR8 ATI VCR 8.0 2816 VCR9 ATI VCR 9.0 2817 VDCT Vitec Multimedia Video Maker Pro DIB 2818 VDOM VDOnet VDOWave 2819 VDOW VDOnet VDOLive (H.263) 2820 VDTZ Darim Vison VideoTizer YUV 2821 VGPX Alaris VideoGramPiX 2822 VIDS Vitec Multimedia YUV 4:2:2 CCIR 601 for V422 2823 VIVO Vivo H.263 v2.00 2824 vivo Vivo H.263 2825 VIXL Miro/Pinnacle Video XL 2826 VLV1 VideoLogic/PURE Digital Videologic Capture 2827 VP30 On2 VP3.0 2828 VP31 On2 VP3.1 2829 VP50 On2 VP5 2830 VP60 On2 VP6 2831 VP70 On2 VP7 2832 VP80 On2 VP8 2833 VP6F On2 TrueMotion VP6 2834 VX1K Lucent VX1000S Video Codec 2835 VX2K Lucent VX2000S Video Codec 2836 VXSP Lucent VX1000SP Video Codec 2837 WBVC Winbond W9960 2838 WHAM Microsoft Video 1 (WHAM) 2839 WINX Winnov Software Compression 2840 WJPG AverMedia Winbond JPEG 2841 WMV1 Windows Media Video V7 2842 WMV2 Windows Media Video V8 2843 WMV3 Windows Media Video V9 2844 WNV1 Winnov Hardware Compression 2845 XYZP Extended PAL format XYZ palette (www.riff.org) 2846 x263 Xirlink H.263 2847 XLV0 NetXL Video Decoder 2848 XMPG Xing MPEG (I-Frame only) 2849 XVID XviD MPEG-4 (www.xvid.org) 2850 XXAN ?XXAN? 2851 YU92 Intel YUV (YU92) 2852 YUNV Nvidia Uncompressed YUV 4:2:2 2853 YUVP Extended PAL format YUV palette (www.riff.org) 2854 Y211 YUV 2:1:1 Packed 2855 Y411 YUV 4:1:1 Packed 2856 Y41B Weitek YUV 4:1:1 Planar 2857 Y41P Brooktree PC1 YUV 4:1:1 Packed 2858 Y41T Brooktree PC1 YUV 4:1:1 with transparency 2859 Y42B Weitek YUV 4:2:2 Planar 2860 Y42T Brooktree UYUV 4:2:2 with transparency 2861 Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera 2862 Y800 Simple, single Y plane for monochrome images 2863 Y8 Grayscale video 2864 YC12 Intel YUV 12 codec 2865 YUV8 Winnov Caviar YUV8 2866 YUV9 Intel YUV9 2867 YUY2 Uncompressed YUV 4:2:2 2868 YUYV Canopus YUV 2869 YV12 YVU12 Planar 2870 YVU9 Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes) 2871 YVYU YVYU 4:2:2 Packed 2872 ZLIB Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm) 2873 ZPEG Metheus Video Zipper 2874 2875 */ 2876 2877 return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc'); 2878 } 2879 2880 /** 2881 * @param string $byteword 2882 * @param bool $signed 2883 * 2884 * @return int|float|false 2885 */ 2886 private function EitherEndian2Int($byteword, $signed=false) { 2887 if ($this->container == 'riff') { 2888 return getid3_lib::LittleEndian2Int($byteword, $signed); 2889 } 2890 return getid3_lib::BigEndian2Int($byteword, false, $signed); 2891 } 2892 2893 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Jun 14 08:20:09 2026 | Cross-referenced by PHPXref |