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