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 /////////////////////////////////////////////////////////////////
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 //
19 /////////////////////////////////////////////////////////////////
22 * @todo Parse AC-3/DTS audio inside WAVE correctly
23 * @todo Rewrite RIFF parser totally
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);
30 class getid3_riff
extends getid3_handler
32 protected $container = 'riff'; // default
37 * @throws getid3_exception
39 public function Analyze() {
40 $info = &$this->getid3
->info
;
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());
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();
56 $Original['avdataoffset'] = $info['avdataoffset'];
57 $Original['avdataend'] = $info['avdataend'];
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);
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));
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';
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));
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'];
97 $nextRIFFoffset = $Original['avdataoffset'] +
8 +
$thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset
98 while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
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');
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
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'];
126 switch ($nextRIFFheaderID) {
128 $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] +
4, $nextRIFFoffset);
129 if (!isset($thisfile_riff[$nextRIFFtype])) {
130 $thisfile_riff[$nextRIFFtype] = array();
132 $thisfile_riff[$nextRIFFtype][] = $chunkdata;
136 unset($info['riff']);
137 $info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] +
4, $nextRIFFoffset);
142 $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
146 $info['divxtag']['comments'] = self
::ParseDIVXTAG($this->fread($chunkdata['size']));
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);
159 $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib
::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
165 if ($RIFFsubtype == 'WAVE') {
166 $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
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']);
177 switch ($RIFFsubtype) {
179 // http://en.wikipedia.org/wiki/Wav
181 $info['fileformat'] = 'wav';
183 if (empty($thisfile_audio['bitrate_mode'])) {
184 $thisfile_audio['bitrate_mode'] = 'cbr';
186 if (empty($thisfile_audio_dataformat)) {
187 $thisfile_audio_dataformat = 'wav';
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'];
194 if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
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');
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];
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']);
210 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
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']);
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']) {
221 $thisfile_audio['lossless'] = true;
225 $thisfile_audio_dataformat = 'ac3';
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;
240 if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
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'];
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));
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));
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']);
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']);
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));
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
284 // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
285 // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
288 if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
289 $thisfile_audio['bitrate'] = getid3_lib
::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
292 if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
294 $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
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']);
311 $this->warning('RIFF.WAVE.BEXT.origin_time is invalid');
314 $this->warning('RIFF.WAVE.BEXT.origin_date is invalid');
316 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
317 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
320 if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
322 $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
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);
331 $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
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);
340 if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
342 $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
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));
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);
368 $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
369 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
372 if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
373 // SoundMiner metadata
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'];
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;
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).')');
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).')');
401 $SNDM_startoffset +
= $SNDM_thisTagSize;
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;
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).')');
412 'tracktitle'=>'title',
413 'category' =>'genre',
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];
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);
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);
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);
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']);
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'];
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'];
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;
472 if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
473 $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
474 $this->fseek($info['avdataend']);
475 $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
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);
487 if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
488 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
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'];
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'];
507 case 0x08AE: // ClearJump LiteWave
508 $thisfile_audio['bitrate_mode'] = 'vbr';
509 $thisfile_audio_dataformat = 'litewave';
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
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
524 // PCMWAVEFORMAT m_OrgWf; // original wave format
525 // }SLwFormat, *PSLwFormat;
528 $thisfile_riff['litewave']['raw'] = array();
529 $riff_litewave = &$thisfile_riff['litewave'];
530 $riff_litewave_raw = &$riff_litewave['raw'];
533 'compression_method' => 1,
534 'compression_flags' => 1,
536 'm_dwBlockSize' => 4,
538 'm_wMarkDistance' => 2,
541 'm_bFactExists' => 2,
542 'm_dwRiffChunkSize' => 4,
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;
550 //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20));
551 $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality'];
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);
557 $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ?
true : false);
558 $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor'];
565 if ($info['avdataend'] > $info['filesize']) {
566 switch (!empty($thisfile_audio_dataformat) ?
$thisfile_audio_dataformat : '') {
567 case 'wavpack': // WavPack
569 case 'ofr': // OptimFROG
570 case 'ofs': // OptimFROG DualStream
571 // lossless compressed audio formats that keep original RIFF headers - skip warning
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
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'];
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'];
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'];
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');
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'];
614 // http://en.wikipedia.org/wiki/Audio_Video_Interleave
616 $info['fileformat'] = 'avi';
617 $info['mime_type'] = 'video/avi';
619 $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
620 $thisfile_video['dataformat'] = 'avi';
622 $thisfile_riff_video_current = array();
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'];
629 $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] +
$thisfile_riff['AVI ']['movi']['size'];
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'];
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',
643 //$bIndexSubtype = array(
645 // 0x01 => 'AVI_INDEX_2FIELD',
648 foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
649 $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
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));
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']];
664 if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
665 $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
668 $thisfile_riff_raw['avih'] = array();
669 $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
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');
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', //
684 'dwSuggestedBufferSize', //
693 foreach ($flags as $flag) {
694 $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
699 'hasindex' => 0x00000010,
700 'mustuseindex' => 0x00000020,
701 'interleaved' => 0x00000100,
702 'trustcktype' => 0x00000800,
703 'capturedfile' => 0x00010000,
704 'copyrighted' => 0x00020010,
706 foreach ($flags as $flag => $value) {
707 $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
711 $thisfile_riff_video[$streamindex] = array();
712 /** @var array $thisfile_riff_video_current */
713 $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
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'];
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'];
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'];
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'];
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);
738 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
739 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
742 $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
744 switch ($strhfccType) {
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);
752 $thisfile_riff_audio[$streamindex] = self
::parseWAVEFORMATex($strfData);
753 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
756 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
757 $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
759 if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
760 unset($thisfile_audio_streams_currentstream['bits_per_sample']);
762 $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
763 unset($thisfile_audio_streams_currentstream['raw']);
766 $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
768 unset($thisfile_riff_audio[$streamindex]['raw']);
769 $thisfile_audio = getid3_lib
::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
771 $thisfile_audio['lossless'] = false;
772 switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
774 $thisfile_audio_dataformat = 'wav';
775 $thisfile_audio['lossless'] = true;
778 case 0x0050: // MPEG Layer 2 or Layer 1
779 $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
782 case 0x0055: // MPEG Layer 3
783 $thisfile_audio_dataformat = 'mp3';
787 $thisfile_audio_dataformat = 'aac';
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';
797 $thisfile_audio_dataformat = 'ac3';
801 $thisfile_audio_dataformat = 'dts';
805 $thisfile_audio_dataformat = 'wav';
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'];
817 $thisfile_riff_raw['strh'][$i] = array();
818 $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i];
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));
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'];
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;
851 $thisfile_video['lossless'] = false;
855 switch ($strhfccType) {
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'];
860 if ($thisfile_riff_video_current['codec'] == 'DV') {
861 $thisfile_riff_video_current['dv_type'] = 2;
866 $thisfile_riff_video_current['dv_type'] = 1;
872 $this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"');
879 if (isset($thisfile_riff_raw_strf_strhfccType_streamindex) && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
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'];
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;
896 $thisfile_video['lossless'] = false;
897 //$thisfile_video['bits_per_sample'] = 24;
909 $info['fileformat'] = 'amv';
910 $info['mime_type'] = 'video/amv';
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;
918 $thisfile_audio['dataformat'] = 'adpcm';
919 $thisfile_audio['lossless'] = false;
923 // http://en.wikipedia.org/wiki/CD-DA
925 $info['fileformat'] = 'cda';
926 unset($info['mime_type']);
928 $thisfile_audio_dataformat = 'cda';
930 $info['avdataoffset'] = 44;
932 if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
934 $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
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));
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'];
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';
959 // http://en.wikipedia.org/wiki/AIFF
962 $info['fileformat'] = 'aiff';
963 $info['mime_type'] = 'audio/x-aiff';
965 $thisfile_audio['bitrate_mode'] = 'cbr';
966 $thisfile_audio_dataformat = 'aiff';
967 $thisfile_audio['lossless'] = true;
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
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');
979 $info['avdataend'] = $info['filesize'];
983 if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
986 $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
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));
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']) {
999 $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
1000 $thisfile_audio['lossless'] = true;
1004 switch ($thisfile_riff_audio['codec_fourcc']) {
1005 // http://developer.apple.com/qa/snd/snd07.html
1007 $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
1008 $thisfile_audio['lossless'] = true;
1012 $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
1013 $thisfile_audio['lossless'] = true;
1022 $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
1023 $thisfile_audio['lossless'] = false;
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'];
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');
1037 $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
1040 if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
1042 $CommentCount = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
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);
1047 $info['comments_raw'][$i]['marker_id'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
1049 $CommentLength = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
1051 $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
1052 $offset +
= $CommentLength;
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'];
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'];
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'];
1075 unset($getid3_temp, $getid3_id3v2);
1080 // http://en.wikipedia.org/wiki/8SVX
1082 $info['fileformat'] = '8svx';
1083 $info['mime_type'] = 'audio/8svx';
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;
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');
1099 if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
1101 $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
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));
1111 $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
1113 switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
1115 $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
1116 $thisfile_audio['lossless'] = true;
1117 $ActualBitsPerSample = 8;
1121 $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
1122 $thisfile_audio['lossless'] = false;
1123 $ActualBitsPerSample = 4;
1127 $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.$thisfile_riff_RIFFsubtype_VHDR_0['sCompression'].'"');
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) {
1136 $thisfile_audio['channels'] = 2;
1139 case 2: // Left channel only
1140 case 4: // Right channel only
1141 $thisfile_audio['channels'] = 1;
1145 $this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"');
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'];
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);
1165 $info['fileformat'] = 'vcd'; // Asume Video CD
1166 $info['mime_type'] = 'video/mpeg';
1168 if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
1169 getid3_lib
::IncludeDependency(GETID3_INCLUDEPATH
.'module.audio-video.mpeg.php', __FILE__
, true);
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'];
1181 unset($getid3_temp, $getid3_mpeg);
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';
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;
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);
1208 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8 '][0]['width'];
1209 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8 '][0]['height'];
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)).'"');
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));
1227 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8L'][0]['width'];
1228 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8L'][0]['height'];
1230 $this->error('Expecting 2F at offset '.($thisfile_riff['WEBP']['VP8L'][0]['offset'] +
8).', found "'.getid3_lib
::PrintHexBytes(substr($WEBP_VP8L_header, 0, 1)).'"');
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']);
1241 switch ($RIFFsubtype) {
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.'"');
1254 if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
1255 getid3_lib
::IncludeDependency(GETID3_INCLUDEPATH
.'module.tag.id3v2.php', __FILE__
, true);
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'];
1264 unset($getid3_temp, $getid3_id3v2);
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));
1272 if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
1273 self
::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
1275 if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
1276 self
::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
1279 if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
1280 $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
1283 if (!isset($info['playtime_seconds'])) {
1284 $info['playtime_seconds'] = 0;
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);
1293 if ($info['playtime_seconds'] > 0) {
1294 if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1296 if (!isset($info['bitrate'])) {
1297 $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1300 } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
1302 if (!isset($thisfile_audio['bitrate'])) {
1303 $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1306 } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1308 if (!isset($thisfile_video['bitrate'])) {
1309 $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1316 if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
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'];
1325 if ($thisfile_video['bitrate'] <= 0) {
1326 unset($thisfile_video['bitrate']);
1328 if ($thisfile_audio['bitrate'] <= 0) {
1329 unset($thisfile_audio['bitrate']);
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'];
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'];
1353 $getid3_mp3 = new getid3_mp3($this->getid3
);
1354 $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
1359 if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
1360 switch ($thisfile_audio_dataformat) {
1362 // ignore bits_per_sample
1366 $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
1372 if (empty($thisfile_riff_raw)) {
1373 unset($thisfile_riff['raw']);
1375 if (empty($thisfile_riff_audio)) {
1376 unset($thisfile_riff['audio']);
1378 if (empty($thisfile_riff_video)) {
1379 unset($thisfile_riff['video']);
1386 * @param int $startoffset
1387 * @param int $maxoffset
1389 * @return array|false
1392 * @throws getid3_exception
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
1397 // https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
1398 //typedef struct _amvmainheader {
1399 //FOURCC fcc; // 'amvh'
1401 //DWORD dwMicroSecPerFrame;
1413 $info = &$this->getid3
->info
;
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).'"');
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)).'"');
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));
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'];
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
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)).'"');
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)).'"');
1453 // followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
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)).'"');
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)).'"');
1462 // followed by 20 bytes of a modified WAVEFORMATEX:
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)
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));
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';
1491 } catch (getid3_exception
$e) {
1492 if ($e->getCode() == 10) {
1493 $this->warning('RIFFAMV parser: '.$e->getMessage());
1503 * @param int $startoffset
1504 * @param int $maxoffset
1506 * @return array|false
1507 * @throws getid3_exception
1509 public function ParseRIFF($startoffset, $maxoffset) {
1510 $info = &$this->getid3
->info
;
1513 $FoundAllChunksWeNeed = false;
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.');
1528 if (($chunksize == 0) && ($chunkname != 'JUNK')) {
1529 $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
1532 if (($chunksize %
2) != 0) {
1533 // all structures are packed on word boundaries
1537 switch ($chunkname) {
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;
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));
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)) {
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'];
1572 unset($getid3_temp, $getid3_mp3);
1575 } elseif (strpos($FirstFourBytes, getid3_ac3
::syncword
) === 0) {
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);
1593 unset($getid3_temp, $getid3_ac3);
1596 $FoundAllChunksWeNeed = true;
1597 $this->fseek($WhereWeWere);
1599 $this->fseek($chunksize - 4, SEEK_CUR
);
1603 if (!isset($RIFFchunk[$listname])) {
1604 $RIFFchunk[$listname] = array();
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);
1616 if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
1617 $this->fseek($chunksize, SEEK_CUR
);
1621 if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
1622 $thisindex = count($RIFFchunk[$chunkname]);
1624 $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
1625 $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
1626 switch ($chunkname) {
1628 $info['avdataoffset'] = $this->ftell();
1629 $info['avdataend'] = $info['avdataoffset'] +
$chunksize;
1631 $testData = $this->fread(36);
1632 if ($testData === '') {
1635 if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
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'];
1649 unset($getid3_temp, $getid3_mp3);
1652 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3
::syncword
)) ||
substr($testData, 8, 2) == strrev(getid3_ac3
::syncword
)) {
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'];
1661 $getid3_ac3 = new getid3_ac3($getid3_temp);
1662 if ($isRegularAC3) {
1663 $getid3_ac3->Analyze();
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
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);
1673 $getid3_ac3->AnalyzeString($ac3_data);
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.']');
1685 unset($getid3_temp, $getid3_ac3);
1687 } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts
::$syncwords)).')/', $testData)) {
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.']');
1706 unset($getid3_temp, $getid3_dts);
1708 } elseif (substr($testData, 0, 4) == 'wvpk') {
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));
1716 // This is some other kind of data (quite possibly just PCM)
1717 // do nothing special, just skip it
1719 $nextoffset = $info['avdataend'];
1720 $this->fseek($nextoffset);
1732 // always read data in
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]);
1744 // but if nothing there, ignore
1745 // remove the key in either case
1746 unset($RIFFchunk[$chunkname][$thisindex]['data']);
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
);
1756 // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
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]);
1768 if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
1769 unset($RIFFchunk[$chunkname]);
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);
1776 $this->fseek($chunksize, SEEK_CUR
);
1784 } catch (getid3_exception
$e) {
1785 if ($e->getCode() == 10) {
1786 $this->warning('RIFF parser: '.$e->getMessage());
1796 * @param string $RIFFdata
1800 public function ParseRIFFdata(&$RIFFdata) {
1801 $info = &$this->getid3
->info
;
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];
1810 fwrite($fp_temp, $RIFFdata);
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();
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);
1838 * @param array $RIFFinfoArray
1839 * @param array $CommentsTargetArray
1843 public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
1844 $RIFFinfoKeyLookup = array(
1845 'IARL'=>'archivallocation',
1847 'ICDS'=>'costumedesigner',
1848 'ICMS'=>'commissionedby',
1851 'ICOP'=>'copyright',
1852 'ICRD'=>'creationdate',
1853 'IDIM'=>'dimensions',
1854 'IDIT'=>'digitizationdate',
1855 'IDPI'=>'resolution',
1856 'IDST'=>'distributor',
1858 'IENG'=>'engineers',
1859 'IFRM'=>'accountofparts',
1862 'ILGT'=>'lightness',
1864 'IMED'=>'orignalmedium',
1867 'IPDS'=>'productiondesigner',
1875 'ISGN'=>'secondarygenre',
1876 'ISHP'=>'sharpness',
1877 'ISRC'=>'sourcesupplier',
1878 'ISRF'=>'digitizationsource',
1879 'ISTD'=>'productionstudio',
1881 'ITCH'=>'encoded_by',
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']);
1893 $CommentsTargetArray[$value] = array(trim($commentdata['data']));
1903 * @param string $WaveFormatExData
1907 public static function parseWAVEFORMATex($WaveFormatExData) {
1909 $WaveFormatEx = array();
1910 $WaveFormatEx['raw'] = array();
1911 $WaveFormatEx_raw = &$WaveFormatEx['raw'];
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);
1922 $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw);
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'];
1930 return $WaveFormatEx;
1934 * @param string $WavPackChunkData
1938 public function parseWavPackHeader($WavPackChunkData) {
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];
1950 $info = &$this->getid3
->info
;
1951 $info['wavpack'] = array();
1952 $thisfile_wavpack = &$info['wavpack'];
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));
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));
1971 $thisfile_wavpack['flags'] = array();
1972 $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
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);
2000 * @param string $BITMAPINFOHEADER
2001 * @param bool $littleEndian
2005 public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
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);
2019 $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier
2025 * @param string $DIVXTAG
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
2043 static $DIVXTAGgenre = array(
2045 1 => 'Action/Adventure',
2057 13 => 'Infomercial',
2058 14 => 'Interactive',
2060 16 => 'Music Video',
2067 $DIVXTAGrating = 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"
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']);
2090 unset($parsed['genre_id'], $parsed['rating_id']);
2091 foreach ($parsed as $key => $value) {
2092 if (empty($value)) {
2093 unset($parsed[$key]);
2098 foreach ($parsed as $tag => $value) {
2099 $parsed[$tag] = array($value);
2106 * @param string $tagshortname
2110 public static function waveSNDMtagLookup($tagshortname) {
2113 /** This is not a comment!
2120 ©fin featuredinstrument
2130 return getid3_lib
::EmbeddedLookup($tagshortname, $begin, __LINE__
, __FILE__
, 'riff-sndm');
2134 * @param int $wFormatTag
2138 public static function wFormatTagLookup($wFormatTag) {
2142 /** This is not a comment!
2144 0x0000 Microsoft Unknown Wave Format
2145 0x0001 Pulse Code Modulation (PCM)
2146 0x0002 Microsoft ADPCM
2148 0x0004 Compaq Computer VSELP
2150 0x0006 Microsoft A-Law
2151 0x0007 Microsoft mu-Law
2152 0x0008 Microsoft DTS
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
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
2173 0x0031 Microsoft GSM 6.10
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
2183 0x003B Rockwell ADPCM
2184 0x003C Rockwell Digit LK
2186 0x0040 Antex Electronics G.721 ADPCM
2189 0x0050 MPEG Layer-2 or Layer-1
2197 0x0063 Canopus Atrac
2202 0x0069 Voxware Byte Aligned
2207 0x0074 Voxware MetaVoice
2208 0x0075 Voxware MetaSound
2209 0x0076 Voxware RT29HW
2223 0x0092 Dolby AC3 SPDIF
2224 0x0093 MediaSonic G.723
2225 0x0094 Aculab PLC Prosody 8kbps
2227 0x0098 Philips LPCBB
2230 0x0100 Rhetorex ADPCM
2233 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)
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
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
2263 0x0300 Fujitsu FM Towns Snd
2265 0x0401 Intel Music Coder
2266 0x0450 QDesign Music
2268 0x0681 AT&T Labs TPC
2269 0x08AE ClearJump LiteWave
2271 0x1001 Olivetti ADPCM
2272 0x1002 Olivetti CELP
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)
2281 0x1401 AT&T ISIAudio
2282 0x1500 Soundspace Music Compression
2283 0x181C VoxWare RT24 Speech
2284 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com)
2287 0x2002 WAVE_FORMAT_14_4
2288 0x2003 WAVE_FORMAT_28_8
2289 0x2004 WAVE_FORMAT_COOK
2290 0x2005 WAVE_FORMAT_DNET
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
2304 return getid3_lib
::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT
), $begin, __LINE__
, __FILE__
, 'riff-wFormatTag');
2308 * @param string $fourcc
2312 public static function fourccLookup($fourcc) {
2316 /** This is not a comment!
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)
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
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)
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
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)
2366 CWLT Microsoft Color WLT DIB
2367 CYUV Creative Labs YUV
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)
2380 DMB1 Matrox Rainbow Runner hardware MJPEG
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)
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
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)
2412 ETV1 eTreppid Video ETV1
2413 ETV2 eTreppid Video ETV2
2414 ETVC eTreppid Video ETVC
2415 FLIC Autodesk FLI/FLC Animation
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
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)
2450 IAN Intel Indeo 4 (RDX)
2451 ICLB InSoft CellB Videoconferencing
2453 IJPG Intergraph JPEG
2454 ILVC Intel Layered Video
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)
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
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)
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
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)
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
2582 RVX Intel RDX (RVX )
2583 SMC Apple Graphics (SMC )
2584 SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2
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
2592 smsv WorldConnect Wavelet Video
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
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
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
2626 UYVY UYVY packed 4:2:2
2628 VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/)
2629 VIV1 FFmpeg H263+ decoder
2631 VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)
2632 VTLP Alaris VideoGramPiX
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
2647 VDCT Vitec Multimedia Video Maker Pro DIB
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
2655 VIXL Miro/Pinnacle Video XL
2656 VLV1 VideoLogic/PURE Digital Videologic Capture
2659 VP6F On2 TrueMotion VP6
2660 VX1K Lucent VX1000S Video Codec
2661 VX2K Lucent VX2000S Video Codec
2662 VXSP Lucent VX1000SP Video Codec
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)
2673 XLV0 NetXL Video Decoder
2674 XMPG Xing MPEG (I-Frame only)
2675 XVID XviD MPEG-4 (www.xvid.org)
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
2690 YC12 Intel YUV 12 codec
2691 YUV8 Winnov Caviar YUV8
2693 YUY2 Uncompressed YUV 4:2:2
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
2703 return getid3_lib
::EmbeddedLookup($fourcc, $begin, __LINE__
, __FILE__
, 'riff-fourcc');
2707 * @param string $byteword
2708 * @param bool $signed
2710 * @return int|float|false
2712 private function EitherEndian2Int($byteword, $signed=false) {
2713 if ($this->container
== 'riff') {
2714 return getid3_lib
::LittleEndian2Int($byteword, $signed);
2716 return getid3_lib
::BigEndian2Int($byteword, false, $signed);