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