]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/ID3/module.audio-video.riff.php
WordPress 4.6.3-scripts
[autoinstalls/wordpress.git] / wp-includes / ID3 / module.audio-video.riff.php
1 <?php
2 /////////////////////////////////////////////////////////////////
3 /// getID3() by James Heinrich <info@getid3.org>               //
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: gfrazier@icestorm.net, 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 (gabest@freemail.hu)
2299                         GPEG    Motion JPEG (gabest@freemail.hu)
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 }