balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

module.audio-video.riff.php (134454B)


      1 <?php
      2 
      3 /////////////////////////////////////////////////////////////////
      4 /// getID3() by James Heinrich <info@getid3.org>               //
      5 //  available at https://github.com/JamesHeinrich/getID3       //
      6 //            or https://www.getid3.org                        //
      7 //            or http://getid3.sourceforge.net                 //
      8 //  see readme.txt for more details                            //
      9 /////////////////////////////////////////////////////////////////
     10 //                                                             //
     11 // module.audio-video.riff.php                                 //
     12 // module for analyzing RIFF files                             //
     13 // multiple formats supported by this module:                  //
     14 //    Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX   //
     15 // dependencies: module.audio.mp3.php                          //
     16 //               module.audio.ac3.php                          //
     17 //               module.audio.dts.php                          //
     18 //                                                            ///
     19 /////////////////////////////////////////////////////////////////
     20 
     21 /**
     22 * @todo Parse AC-3/DTS audio inside WAVE correctly
     23 * @todo Rewrite RIFF parser totally
     24 */
     25 
     26 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
     27 	exit;
     28 }
     29 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
     30 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
     31 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
     32 
     33 class getid3_riff extends getid3_handler
     34 {
     35 	protected $container = 'riff'; // default
     36 
     37 	/**
     38 	 * @return bool
     39 	 *
     40 	 * @throws getid3_exception
     41 	 */
     42 	public function Analyze() {
     43 		$info = &$this->getid3->info;
     44 
     45 		// initialize these values to an empty array, otherwise they default to NULL
     46 		// and you can't append array values to a NULL value
     47 		$info['riff'] = array('raw'=>array());
     48 
     49 		// Shortcuts
     50 		$thisfile_riff             = &$info['riff'];
     51 		$thisfile_riff_raw         = &$thisfile_riff['raw'];
     52 		$thisfile_audio            = &$info['audio'];
     53 		$thisfile_video            = &$info['video'];
     54 		$thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
     55 		$thisfile_riff_audio       = &$thisfile_riff['audio'];
     56 		$thisfile_riff_video       = &$thisfile_riff['video'];
     57 		$thisfile_riff_WAVE        = array();
     58 
     59 		$Original['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 }