Completed
Pull Request — master (#2)
by Stephen
09:27
created

getid3_riff   D

Complexity

Total Complexity 331

Size/Duplication

Total Lines 2557
Duplicated Lines 4.81 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
dl 123
loc 2557
rs 4.4102
c 0
b 0
f 0
wmc 331
lcom 1
cbo 8

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like getid3_riff often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use getid3_riff, and based on these observations, apply Extract Interface, too.

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