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