2 /////////////////////////////////////////////////////////////////
3 /// getID3() by James Heinrich <info@getid3.org> //
4 // available at http://getid3.sourceforge.net //
5 // or http://www.getid3.org //
6 // also https://github.com/JamesHeinrich/getID3 //
7 /////////////////////////////////////////////////////////////////
8 // See readme.txt for more details //
9 /////////////////////////////////////////////////////////////////
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
34 public function Analyze() {
35 $info = &$this->getid3
->info
;
37 // initialize these values to an empty array, otherwise they default to NULL
38 // and you can't append array values to a NULL value
39 $info['riff'] = array('raw'=>array());
42 $thisfile_riff = &$info['riff'];
43 $thisfile_riff_raw = &$thisfile_riff['raw'];
44 $thisfile_audio = &$info['audio'];
45 $thisfile_video = &$info['video'];
46 $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
47 $thisfile_riff_audio = &$thisfile_riff['audio'];
48 $thisfile_riff_video = &$thisfile_riff['video'];
50 $Original['avdataoffset'] = $info['avdataoffset'];
51 $Original['avdataend'] = $info['avdataend'];
53 $this->fseek($info['avdataoffset']);
54 $RIFFheader = $this->fread(12);
55 $offset = $this->ftell();
56 $RIFFtype = substr($RIFFheader, 0, 4);
57 $RIFFsize = substr($RIFFheader, 4, 4);
58 $RIFFsubtype = substr($RIFFheader, 8, 4);
62 case 'FORM': // AIFF, AIFC
63 //$info['fileformat'] = 'aiff';
64 $this->container
= 'aiff';
65 $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
66 $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset +
$thisfile_riff['header_size'] - 4));
69 case 'RIFF': // AVI, WAV, etc
70 case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
71 case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
72 //$info['fileformat'] = 'riff';
73 $this->container
= 'riff';
74 $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
75 if ($RIFFsubtype == 'RMP3') {
76 // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
77 $RIFFsubtype = 'WAVE';
79 if ($RIFFsubtype != 'AMV ') {
80 // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
81 // Handled separately in ParseRIFFAMV()
82 $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset +
$thisfile_riff['header_size'] - 4));
84 if (($info['avdataend'] - $info['filesize']) == 1) {
85 // LiteWave appears to incorrectly *not* pad actual output file
86 // to nearest WORD boundary so may appear to be short by one
87 // byte, in which case - skip warning
88 $info['avdataend'] = $info['filesize'];
91 $nextRIFFoffset = $Original['avdataoffset'] +
8 +
$thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset
92 while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
94 $this->fseek($nextRIFFoffset);
95 } catch (getid3_exception
$e) {
96 if ($e->getCode() == 10) {
97 //$this->warning('RIFF parser: '.$e->getMessage());
98 $this->error('AVI extends beyond '.round(PHP_INT_MAX
/ 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong');
99 $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present');
105 $nextRIFFheader = $this->fread(12);
106 if ($nextRIFFoffset == ($info['avdataend'] - 1)) {
107 if (substr($nextRIFFheader, 0, 1) == "\x00") {
108 // RIFF padded to WORD boundary, we're actually already at the end
112 $nextRIFFheaderID = substr($nextRIFFheader, 0, 4);
113 $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
114 $nextRIFFtype = substr($nextRIFFheader, 8, 4);
115 $chunkdata = array();
116 $chunkdata['offset'] = $nextRIFFoffset +
8;
117 $chunkdata['size'] = $nextRIFFsize;
118 $nextRIFFoffset = $chunkdata['offset'] +
$chunkdata['size'];
120 switch ($nextRIFFheaderID) {
122 $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] +
4, $nextRIFFoffset);
123 if (!isset($thisfile_riff[$nextRIFFtype])) {
124 $thisfile_riff[$nextRIFFtype] = array();
126 $thisfile_riff[$nextRIFFtype][] = $chunkdata;
130 unset($info['riff']);
131 $info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] +
4, $nextRIFFoffset);
136 $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
140 $info['divxtag']['comments'] = self
::ParseDIVXTAG($this->fread($chunkdata['size']));
144 if ($info['filesize'] == ($chunkdata['offset'] - 8 +
128)) {
145 $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12);
146 if (substr($DIVXTAG, -7) == 'DIVXTAG') {
147 // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file
148 $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway');
149 $info['divxtag']['comments'] = self
::ParseDIVXTAG($DIVXTAG);
153 $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib
::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
159 if ($RIFFsubtype == 'WAVE') {
160 $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
165 $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
166 //unset($info['fileformat']);
171 switch ($RIFFsubtype) {
173 // http://en.wikipedia.org/wiki/Wav
175 $info['fileformat'] = 'wav';
177 if (empty($thisfile_audio['bitrate_mode'])) {
178 $thisfile_audio['bitrate_mode'] = 'cbr';
180 if (empty($thisfile_audio_dataformat)) {
181 $thisfile_audio_dataformat = 'wav';
184 if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
185 $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] +
8;
186 $info['avdataend'] = $info['avdataoffset'] +
$thisfile_riff_WAVE['data'][0]['size'];
188 if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
190 $thisfile_riff_audio[$streamindex] = self
::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
191 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
192 if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) ||
($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
193 $this->error('Corrupt RIFF file: bitrate_audio == zero');
196 $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
197 unset($thisfile_riff_audio[$streamindex]['raw']);
198 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
200 $thisfile_audio = getid3_lib
::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
201 if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
202 $this->warning('Audio codec = '.$thisfile_audio['codec']);
204 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
206 if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
207 $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
210 $thisfile_audio['lossless'] = false;
211 if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
212 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
215 $thisfile_audio['lossless'] = true;
219 $thisfile_audio_dataformat = 'ac3';
228 $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
229 $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
230 $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
231 $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
234 if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
237 $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
238 $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array());
239 $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad'];
240 $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
241 $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
243 $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib
::LittleEndian2Float(substr($rgadData, 0, 4));
244 $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2));
245 $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2));
247 $nRadioRgAdjustBitstring = str_pad(getid3_lib
::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT
);
248 $nAudiophileRgAdjustBitstring = str_pad(getid3_lib
::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT
);
249 $thisfile_riff_raw_rgad_track['name'] = getid3_lib
::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
250 $thisfile_riff_raw_rgad_track['originator'] = getid3_lib
::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
251 $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib
::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
252 $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib
::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
253 $thisfile_riff_raw_rgad_album['name'] = getid3_lib
::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
254 $thisfile_riff_raw_rgad_album['originator'] = getid3_lib
::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
255 $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib
::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
256 $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib
::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
258 $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
259 if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) {
260 $thisfile_riff['rgad']['track']['name'] = getid3_lib
::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
261 $thisfile_riff['rgad']['track']['originator'] = getid3_lib
::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
262 $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib
::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
264 if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) {
265 $thisfile_riff['rgad']['album']['name'] = getid3_lib
::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
266 $thisfile_riff['rgad']['album']['originator'] = getid3_lib
::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
267 $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib
::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
271 if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
272 $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
274 // This should be a good way of calculating exact playtime,
275 // but some sample files have had incorrect number of samples,
276 // so cannot use this method
278 // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
279 // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
282 if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
283 $thisfile_audio['bitrate'] = getid3_lib
::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
286 if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
288 $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
290 $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
291 $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
292 $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
293 $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
294 $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
295 $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
296 $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
297 $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
298 $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
299 if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
300 if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
301 list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
302 list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
303 $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
305 $this->warning('RIFF.WAVE.BEXT.origin_time is invalid');
308 $this->warning('RIFF.WAVE.BEXT.origin_date is invalid');
310 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
311 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
314 if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
316 $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
318 $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
319 $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001);
320 if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
321 $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ?
false : true;
322 $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004);
323 $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008);
325 $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
327 $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
328 $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
329 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001);
330 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002);
331 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004);
334 if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
336 $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
338 $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
339 $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
340 $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
341 $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
342 $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
343 $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
344 $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
345 $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
346 $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
347 $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
348 $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
349 $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
350 $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
351 $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
352 $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
353 $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
354 for ($i = 0; $i < 8; $i++
) {
355 $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 +
($i * 8), 4);
356 $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 +
($i * 8) +
4, 4));
358 $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
359 $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
361 $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
362 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
365 if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
366 // SoundMiner metadata
369 $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE['SNDM'][0];
370 $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data'];
371 $SNDM_startoffset = 0;
372 $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size'];
374 while ($SNDM_startoffset < $SNDM_endoffset) {
375 $SNDM_thisTagOffset = 0;
376 $SNDM_thisTagSize = getid3_lib
::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset +
$SNDM_thisTagOffset, 4));
377 $SNDM_thisTagOffset +
= 4;
378 $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset +
$SNDM_thisTagOffset, 4);
379 $SNDM_thisTagOffset +
= 4;
380 $SNDM_thisTagDataSize = getid3_lib
::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset +
$SNDM_thisTagOffset, 2));
381 $SNDM_thisTagOffset +
= 2;
382 $SNDM_thisTagDataFlags = getid3_lib
::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset +
$SNDM_thisTagOffset, 2));
383 $SNDM_thisTagOffset +
= 2;
384 $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset +
$SNDM_thisTagOffset, $SNDM_thisTagDataSize);
385 $SNDM_thisTagOffset +
= $SNDM_thisTagDataSize;
387 if ($SNDM_thisTagSize != (4 +
4 +
2 +
2 +
$SNDM_thisTagDataSize)) {
388 $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).')');
390 } elseif ($SNDM_thisTagSize <= 0) {
391 $this->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] +
$SNDM_startoffset).')');
394 $SNDM_startoffset +
= $SNDM_thisTagSize;
396 $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
397 if ($parsedkey = self
::waveSNDMtagLookup($SNDM_thisTagKey)) {
398 $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
400 $this->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] +
$SNDM_startoffset).')');
405 'tracktitle'=>'title',
406 'category' =>'genre',
408 'tracktitle'=>'title',
410 foreach ($tagmapping as $fromkey => $tokey) {
411 if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
412 $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
417 if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
418 // requires functions simplexml_load_string and get_object_vars
419 if ($parsedXML = getid3_lib
::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
420 $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
421 if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
422 @list
($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
423 $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ?
$denominator : 1000);
425 if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
426 @list
($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
427 $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ?
$denominator : 1000);
429 if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
430 $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
431 $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
432 $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate;
433 $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
434 $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60);
435 $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
436 $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
437 $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
438 $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
439 unset($samples_since_midnight, $timestamp_sample_rate, $h, $m, $s, $f);
447 if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
448 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
449 $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
452 if (!empty($info['wavpack'])) {
453 $thisfile_audio_dataformat = 'wavpack';
454 $thisfile_audio['bitrate_mode'] = 'vbr';
455 $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version'];
457 // Reset to the way it was - RIFF parsing will have messed this up
458 $info['avdataend'] = $Original['avdataend'];
459 $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
461 $this->fseek($info['avdataoffset'] - 44);
462 $RIFFdata = $this->fread(44);
463 $OrignalRIFFheaderSize = getid3_lib
::LittleEndian2Int(substr($RIFFdata, 4, 4)) +
8;
464 $OrignalRIFFdataSize = getid3_lib
::LittleEndian2Int(substr($RIFFdata, 40, 4)) +
44;
466 if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
467 $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
468 $this->fseek($info['avdataend']);
469 $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
472 // move the data chunk after all other chunks (if any)
473 // so that the RIFF parser doesn't see EOF when trying
474 // to skip over the data chunk
475 $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
476 $getid3_riff = new getid3_riff($this->getid3
);
477 $getid3_riff->ParseRIFFdata($RIFFdata);
481 if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
482 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
484 if (!empty($info['ac3'])) {
485 // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
486 $thisfile_audio['wformattag'] = 0x2000;
487 $thisfile_audio['codec'] = self
::wFormatTagLookup($thisfile_audio['wformattag']);
488 $thisfile_audio['lossless'] = false;
489 $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
490 $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
492 if (!empty($info['dts'])) {
493 // Dolby DTS files masquerade as PCM-WAV, but they're not
494 $thisfile_audio['wformattag'] = 0x2001;
495 $thisfile_audio['codec'] = self
::wFormatTagLookup($thisfile_audio['wformattag']);
496 $thisfile_audio['lossless'] = false;
497 $thisfile_audio['bitrate'] = $info['dts']['bitrate'];
498 $thisfile_audio['sample_rate'] = $info['dts']['sample_rate'];
501 case 0x08AE: // ClearJump LiteWave
502 $thisfile_audio['bitrate_mode'] = 'vbr';
503 $thisfile_audio_dataformat = 'litewave';
505 //typedef struct tagSLwFormat {
506 // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags
507 // DWORD m_dwScale; // scale factor for lossy compression
508 // DWORD m_dwBlockSize; // number of samples in encoded blocks
509 // WORD m_wQuality; // alias for the scale factor
510 // WORD m_wMarkDistance; // distance between marks in bytes
513 // //following paramters are ignored if CF_FILESRC is not set
514 // DWORD m_dwOrgSize; // original file size in bytes
515 // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file
516 // DWORD m_dwRiffChunkSize; // riff chunk size in the original file
518 // PCMWAVEFORMAT m_OrgWf; // original wave format
519 // }SLwFormat, *PSLwFormat;
522 $thisfile_riff['litewave']['raw'] = array();
523 $riff_litewave = &$thisfile_riff['litewave'];
524 $riff_litewave_raw = &$riff_litewave['raw'];
527 'compression_method' => 1,
528 'compression_flags' => 1,
530 'm_dwBlockSize' => 4,
532 'm_wMarkDistance' => 2,
535 'm_bFactExists' => 2,
536 'm_dwRiffChunkSize' => 4,
538 $litewave_offset = 18;
539 foreach ($flags as $flag => $length) {
540 $riff_litewave_raw[$flag] = getid3_lib
::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length));
541 $litewave_offset +
= $length;
544 //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20));
545 $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality'];
547 $riff_litewave['flags']['raw_source'] = ($riff_litewave_raw['compression_flags'] & 0x01) ?
false : true;
548 $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ?
false : true;
549 $riff_litewave['flags']['seekpoints'] = (bool) ($riff_litewave_raw['compression_flags'] & 0x04);
551 $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ?
true : false);
552 $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor'];
559 if ($info['avdataend'] > $info['filesize']) {
560 switch (!empty($thisfile_audio_dataformat) ?
$thisfile_audio_dataformat : '') {
561 case 'wavpack': // WavPack
563 case 'ofr': // OptimFROG
564 case 'ofs': // OptimFROG DualStream
565 // lossless compressed audio formats that keep original RIFF headers - skip warning
569 if (($info['avdataend'] - $info['filesize']) == 1) {
570 // LiteWave appears to incorrectly *not* pad actual output file
571 // to nearest WORD boundary so may appear to be short by one
572 // byte, in which case - skip warning
574 // Short by more than one byte, throw warning
575 $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)');
576 $info['avdataend'] = $info['filesize'];
581 if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] %
2) == 0) && ((($info['filesize'] - $info['avdataoffset']) %
2) == 1)) {
582 // output file appears to be incorrectly *not* padded to nearest WORD boundary
583 // Output less severe warning
584 $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)');
585 $info['avdataend'] = $info['filesize'];
587 // Short by more than one byte, throw warning
588 $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)');
589 $info['avdataend'] = $info['filesize'];
594 if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
595 if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
596 $info['avdataend']--;
597 $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
600 if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
601 unset($thisfile_audio['bits_per_sample']);
602 if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
603 $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
608 // http://en.wikipedia.org/wiki/Audio_Video_Interleave
610 $info['fileformat'] = 'avi';
611 $info['mime_type'] = 'video/avi';
613 $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
614 $thisfile_video['dataformat'] = 'avi';
616 if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
617 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] +
8;
618 if (isset($thisfile_riff['AVIX'])) {
619 $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] +
$thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
621 $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] +
$thisfile_riff['AVI ']['movi']['size'];
623 if ($info['avdataend'] > $info['filesize']) {
624 $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)');
625 $info['avdataend'] = $info['filesize'];
629 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
630 //$bIndexType = array(
631 // 0x00 => 'AVI_INDEX_OF_INDEXES',
632 // 0x01 => 'AVI_INDEX_OF_CHUNKS',
633 // 0x80 => 'AVI_INDEX_IS_DATA',
635 //$bIndexSubtype = array(
637 // 0x01 => 'AVI_INDEX_2FIELD',
640 foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
641 $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
643 $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd, 0, 2));
644 $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($ahsisd, 2, 1));
645 $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($ahsisd, 3, 1));
646 $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($ahsisd, 4, 4));
647 $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($ahsisd, 8, 4);
648 $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($ahsisd, 12, 4));
650 //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
651 //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
656 if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
657 $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
660 $thisfile_riff_raw['avih'] = array();
661 $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
663 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L)
664 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
665 $this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero');
670 'dwMaxBytesPerSec', // max. transfer rate
671 'dwPaddingGranularity', // pad to multiples of this size; normally 2K.
672 'dwFlags', // the ever-present flags
673 'dwTotalFrames', // # frames in file
674 'dwInitialFrames', //
676 'dwSuggestedBufferSize', //
685 foreach ($flags as $flag) {
686 $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
691 'hasindex' => 0x00000010,
692 'mustuseindex' => 0x00000020,
693 'interleaved' => 0x00000100,
694 'trustcktype' => 0x00000800,
695 'capturedfile' => 0x00010000,
696 'copyrighted' => 0x00020010,
698 foreach ($flags as $flag => $value) {
699 $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
703 $thisfile_riff_video[$streamindex] = array();
704 $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
706 if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
707 $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
708 $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
710 if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
711 $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
712 $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
714 if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
715 $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
716 $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
719 $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
720 $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
722 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
723 if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
724 for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++
) {
725 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
726 $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
727 $strhfccType = substr($strhData, 0, 4);
729 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
730 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
733 $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
735 switch ($strhfccType) {
737 $thisfile_audio['bitrate_mode'] = 'cbr';
738 $thisfile_audio_dataformat = 'wav';
739 if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
740 $streamindex = count($thisfile_riff_audio);
743 $thisfile_riff_audio[$streamindex] = self
::parseWAVEFORMATex($strfData);
744 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
747 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
748 $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
750 if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
751 unset($thisfile_audio_streams_currentstream['bits_per_sample']);
753 $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
754 unset($thisfile_audio_streams_currentstream['raw']);
757 $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
759 unset($thisfile_riff_audio[$streamindex]['raw']);
760 $thisfile_audio = getid3_lib
::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
762 $thisfile_audio['lossless'] = false;
763 switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
765 $thisfile_audio_dataformat = 'wav';
766 $thisfile_audio['lossless'] = true;
769 case 0x0050: // MPEG Layer 2 or Layer 1
770 $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
773 case 0x0055: // MPEG Layer 3
774 $thisfile_audio_dataformat = 'mp3';
778 $thisfile_audio_dataformat = 'aac';
781 case 0x0161: // Windows Media v7 / v8 / v9
782 case 0x0162: // Windows Media Professional v9
783 case 0x0163: // Windows Media Lossess v9
784 $thisfile_audio_dataformat = 'wma';
788 $thisfile_audio_dataformat = 'ac3';
792 $thisfile_audio_dataformat = 'dts';
796 $thisfile_audio_dataformat = 'wav';
799 $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
800 $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
801 $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
808 $thisfile_riff_raw['strh'][$i] = array();
809 $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i];
811 $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType;
812 $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
813 $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4)); // Contains AVITF_* flags
814 $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2));
815 $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2));
816 $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4));
817 $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4));
818 $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4));
819 $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4));
820 $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4));
821 $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
822 $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4));
823 $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4));
824 $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4));
826 $thisfile_riff_video_current['codec'] = self
::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
827 $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
828 if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self
::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
829 $thisfile_riff_video_current['codec'] = self
::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
830 $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
832 $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
833 $thisfile_video['pixel_aspect_ratio'] = (float) 1;
834 switch ($thisfile_riff_raw_strh_current['fccHandler']) {
835 case 'HFYU': // Huffman Lossless Codec
836 case 'IRAW': // Intel YUV Uncompressed
837 case 'YUY2': // Uncompressed YUV 4:2:2
838 $thisfile_video['lossless'] = true;
842 $thisfile_video['lossless'] = false;
846 switch ($strhfccType) {
848 $thisfile_riff_raw_strf_strhfccType_streamindex = self
::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($this->container
== 'riff'));
849 $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
851 if ($thisfile_riff_video_current['codec'] == 'DV') {
852 $thisfile_riff_video_current['dv_type'] = 2;
857 $thisfile_riff_video_current['dv_type'] = 1;
863 $this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"');
870 if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
872 $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
873 if (self
::fourccLookup($thisfile_video['fourcc'])) {
874 $thisfile_riff_video_current['codec'] = self
::fourccLookup($thisfile_video['fourcc']);
875 $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
878 switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
879 case 'HFYU': // Huffman Lossless Codec
880 case 'IRAW': // Intel YUV Uncompressed
881 case 'YUY2': // Uncompressed YUV 4:2:2
882 $thisfile_video['lossless'] = true;
883 //$thisfile_video['bits_per_sample'] = 24;
887 $thisfile_video['lossless'] = false;
888 //$thisfile_video['bits_per_sample'] = 24;
900 $info['fileformat'] = 'amv';
901 $info['mime_type'] = 'video/amv';
903 $thisfile_video['bitrate_mode'] = 'vbr'; // it's MJPEG, presumably contant-quality encoding, thereby VBR
904 $thisfile_video['dataformat'] = 'mjpeg';
905 $thisfile_video['codec'] = 'mjpeg';
906 $thisfile_video['lossless'] = false;
907 $thisfile_video['bits_per_sample'] = 24;
909 $thisfile_audio['dataformat'] = 'adpcm';
910 $thisfile_audio['lossless'] = false;
914 // http://en.wikipedia.org/wiki/CD-DA
916 $info['fileformat'] = 'cda';
917 unset($info['mime_type']);
919 $thisfile_audio_dataformat = 'cda';
921 $info['avdataoffset'] = 44;
923 if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
925 $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
927 $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
928 $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
929 $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
930 $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
931 $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
932 $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
933 $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
935 $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
936 $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
937 $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
938 $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
940 // hardcoded data for CD-audio
941 $thisfile_audio['lossless'] = true;
942 $thisfile_audio['sample_rate'] = 44100;
943 $thisfile_audio['channels'] = 2;
944 $thisfile_audio['bits_per_sample'] = 16;
945 $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
946 $thisfile_audio['bitrate_mode'] = 'cbr';
950 // http://en.wikipedia.org/wiki/AIFF
953 $info['fileformat'] = 'aiff';
954 $info['mime_type'] = 'audio/x-aiff';
956 $thisfile_audio['bitrate_mode'] = 'cbr';
957 $thisfile_audio_dataformat = 'aiff';
958 $thisfile_audio['lossless'] = true;
960 if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
961 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] +
8;
962 $info['avdataend'] = $info['avdataoffset'] +
$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
963 if ($info['avdataend'] > $info['filesize']) {
964 if (($info['avdataend'] == ($info['filesize'] +
1)) && (($info['filesize'] %
2) == 1)) {
965 // structures rounded to 2-byte boundary, but dumb encoders
966 // forget to pad end of file to make this actually work
968 $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
970 $info['avdataend'] = $info['filesize'];
974 if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
977 $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
979 $thisfile_riff_audio['channels'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
980 $thisfile_riff_audio['total_samples'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
981 $thisfile_riff_audio['bits_per_sample'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
982 $thisfile_riff_audio['sample_rate'] = (int) getid3_lib
::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
984 if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
985 $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
986 $CodecNameSize = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
987 $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
988 switch ($thisfile_riff_audio['codec_name']) {
990 $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
991 $thisfile_audio['lossless'] = true;
995 switch ($thisfile_riff_audio['codec_fourcc']) {
996 // http://developer.apple.com/qa/snd/snd07.html
998 $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
999 $thisfile_audio['lossless'] = true;
1003 $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
1004 $thisfile_audio['lossless'] = true;
1013 $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
1014 $thisfile_audio['lossless'] = false;
1019 $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
1020 if ($thisfile_riff_audio['bits_per_sample'] > 0) {
1021 $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
1023 $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
1024 if ($thisfile_audio['sample_rate'] == 0) {
1025 $this->error('Corrupted AIFF file: sample_rate == zero');
1028 $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
1031 if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
1033 $CommentCount = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
1035 for ($i = 0; $i < $CommentCount; $i++
) {
1036 $info['comments_raw'][$i]['timestamp'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
1038 $info['comments_raw'][$i]['marker_id'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
1040 $CommentLength = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
1042 $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
1043 $offset +
= $CommentLength;
1045 $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib
::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
1046 $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
1050 $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
1051 foreach ($CommentsChunkNames as $key => $value) {
1052 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
1053 $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
1057 if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
1058 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1059 $getid3_temp = new getID3();
1060 $getid3_temp->openfile($this->getid3->filename);
1061 $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1062 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
1063 if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1064 $info['id3v2'] = $getid3_temp->info['id3v2'];
1066 unset($getid3_temp, $getid3_id3v2);
1071 // http://en.wikipedia.org/wiki/8SVX
1073 $info['fileformat'] = '8svx';
1074 $info['mime_type'] = 'audio/8svx';
1076 $thisfile_audio['bitrate_mode'] = 'cbr';
1077 $thisfile_audio_dataformat = '8svx';
1078 $thisfile_audio['bits_per_sample'] = 8;
1079 $thisfile_audio['channels'] = 1; // overridden below, if need be
1081 if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
1082 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] +
8;
1083 $info['avdataend'] = $info['avdataoffset'] +
$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
1084 if ($info['avdataend'] > $info['filesize']) {
1085 $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
1089 if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
1091 $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
1093 $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
1094 $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
1095 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
1096 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
1097 $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
1098 $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib
::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
1099 $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib
::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
1101 $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
1103 switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
1105 $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
1106 $thisfile_audio['lossless'] = true;
1107 $ActualBitsPerSample = 8;
1111 $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
1112 $thisfile_audio['lossless'] = false;
1113 $ActualBitsPerSample = 4;
1117 $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression
.'"');
1122 if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
1123 $ChannelsIndex = getid3_lib
::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
1124 switch ($ChannelsIndex) {
1126 $thisfile_audio['channels'] = 2;
1129 case 2: // Left channel only
1130 case 4: // Right channel only
1131 $thisfile_audio['channels'] = 1;
1135 $this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"');
1141 $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
1142 foreach ($CommentsChunkNames as $key => $value) {
1143 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
1144 $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
1148 $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
1149 if (!empty($thisfile_audio['bitrate'])) {
1150 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
1155 $info['fileformat'] = 'vcd'; // Asume Video CD
1156 $info['mime_type'] = 'video/mpeg';
1158 if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
1159 getid3_lib
::IncludeDependency(GETID3_INCLUDEPATH
.'module.audio-video.mpeg.php', __FILE__
, true);
1161 $getid3_temp = new getID3();
1162 $getid3_temp->openfile($this->getid3
->filename
);
1163 $getid3_mpeg = new getid3_mpeg($getid3_temp);
1164 $getid3_mpeg->Analyze();
1165 if (empty($getid3_temp->info
['error'])) {
1166 $info['audio'] = $getid3_temp->info
['audio'];
1167 $info['video'] = $getid3_temp->info
['video'];
1168 $info['mpeg'] = $getid3_temp->info
['mpeg'];
1169 $info['warning'] = $getid3_temp->info
['warning'];
1171 unset($getid3_temp, $getid3_mpeg);
1176 // https://developers.google.com/speed/webp/docs/riff_container
1177 $info['fileformat'] = 'webp';
1178 $info['mime_type'] = 'image/webp';
1180 $this->error('WebP image parsing not supported in this version of getID3()');
1184 $this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead');
1185 //unset($info['fileformat']);
1188 switch ($RIFFsubtype) {
1192 $ID3v2_key_good = 'id3 ';
1193 $ID3v2_keys_bad = array('ID3 ', 'tag ');
1194 foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
1195 if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
1196 $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
1197 $this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"');
1201 if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
1202 getid3_lib
::IncludeDependency(GETID3_INCLUDEPATH
.'module.tag.id3v2.php', __FILE__
, true);
1204 $getid3_temp = new getID3();
1205 $getid3_temp->openfile($this->getid3
->filename
);
1206 $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1207 $getid3_id3v2->StartingOffset
= $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] +
8;
1208 if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1209 $info['id3v2'] = $getid3_temp->info
['id3v2'];
1211 unset($getid3_temp, $getid3_id3v2);
1216 if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
1217 $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
1219 if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
1220 self
::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
1222 if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
1223 self
::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
1226 if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
1227 $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
1230 if (!isset($info['playtime_seconds'])) {
1231 $info['playtime_seconds'] = 0;
1233 if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
1234 // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
1235 $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
1236 } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
1237 $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
1240 if ($info['playtime_seconds'] > 0) {
1241 if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1243 if (!isset($info['bitrate'])) {
1244 $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1247 } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
1249 if (!isset($thisfile_audio['bitrate'])) {
1250 $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1253 } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1255 if (!isset($thisfile_video['bitrate'])) {
1256 $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1263 if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
1265 $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1266 $thisfile_audio['bitrate'] = 0;
1267 $thisfile_video['bitrate'] = $info['bitrate'];
1268 foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
1269 $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
1270 $thisfile_audio['bitrate'] +
= $audioinfoarray['bitrate'];
1272 if ($thisfile_video['bitrate'] <= 0) {
1273 unset($thisfile_video['bitrate']);
1275 if ($thisfile_audio['bitrate'] <= 0) {
1276 unset($thisfile_audio['bitrate']);
1280 if (isset($info['mpeg']['audio'])) {
1281 $thisfile_audio_dataformat = 'mp'.$info['mpeg']['audio']['layer'];
1282 $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
1283 $thisfile_audio['channels'] = $info['mpeg']['audio']['channels'];
1284 $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate'];
1285 $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1286 if (!empty($info['mpeg']['audio']['codec'])) {
1287 $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec'];
1289 if (!empty($thisfile_audio['streams'])) {
1290 foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
1291 if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
1292 $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
1293 $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
1294 $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
1295 $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
1296 $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
1300 $getid3_mp3 = new getid3_mp3($this->getid3
);
1301 $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
1306 if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
1307 switch ($thisfile_audio_dataformat) {
1309 // ignore bits_per_sample
1313 $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
1319 if (empty($thisfile_riff_raw)) {
1320 unset($thisfile_riff['raw']);
1322 if (empty($thisfile_riff_audio)) {
1323 unset($thisfile_riff['audio']);
1325 if (empty($thisfile_riff_video)) {
1326 unset($thisfile_riff['video']);
1332 public function ParseRIFFAMV($startoffset, $maxoffset) {
1333 // 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
1335 // https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
1336 //typedef struct _amvmainheader {
1337 //FOURCC fcc; // 'amvh'
1339 //DWORD dwMicroSecPerFrame;
1351 $info = &$this->getid3
->info
;
1356 $this->fseek($startoffset);
1357 $maxoffset = min($maxoffset, $info['avdataend']);
1358 $AMVheader = $this->fread(284);
1359 if (substr($AMVheader, 0, 8) != 'hdrlamvh') {
1360 throw new Exception('expecting "hdrlamv" at offset '.($startoffset +
0).', found "'.substr($AMVheader, 0, 8).'"');
1362 if (substr($AMVheader, 8, 4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes
1363 throw new Exception('expecting "0x38000000" at offset '.($startoffset +
8).', found "'.getid3_lib
::PrintHexBytes(substr($AMVheader, 8, 4)).'"');
1365 $RIFFchunk = array();
1366 $RIFFchunk['amvh']['us_per_frame'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 12, 4));
1367 $RIFFchunk['amvh']['reserved28'] = substr($AMVheader, 16, 28); // null? reserved?
1368 $RIFFchunk['amvh']['resolution_x'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 44, 4));
1369 $RIFFchunk['amvh']['resolution_y'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 48, 4));
1370 $RIFFchunk['amvh']['frame_rate_int'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 52, 4));
1371 $RIFFchunk['amvh']['reserved0'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 56, 4)); // 1? reserved?
1372 $RIFFchunk['amvh']['reserved1'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 60, 4)); // 0? reserved?
1373 $RIFFchunk['amvh']['runtime_sec'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 64, 1));
1374 $RIFFchunk['amvh']['runtime_min'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 65, 1));
1375 $RIFFchunk['amvh']['runtime_hrs'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 66, 2));
1377 $info['video']['frame_rate'] = 1000000 / $RIFFchunk['amvh']['us_per_frame'];
1378 $info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x'];
1379 $info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y'];
1380 $info['playtime_seconds'] = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) +
($RIFFchunk['amvh']['runtime_min'] * 60) +
$RIFFchunk['amvh']['runtime_sec'];
1382 // 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
1384 if (substr($AMVheader, 68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") {
1385 throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset +
68).', found "'.getid3_lib
::PrintHexBytes(substr($AMVheader, 68, 20)).'"');
1387 // followed by 56 bytes of null: substr($AMVheader, 88, 56) -> 144
1388 if (substr($AMVheader, 144, 8) != 'strf'."\x24\x00\x00\x00") {
1389 throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset +
144).', found "'.getid3_lib
::PrintHexBytes(substr($AMVheader, 144, 8)).'"');
1391 // followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
1393 if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") {
1394 throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset +
188).', found "'.getid3_lib
::PrintHexBytes(substr($AMVheader, 188, 20)).'"');
1396 // followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256
1397 if (substr($AMVheader, 256, 8) != 'strf'."\x14\x00\x00\x00") {
1398 throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset +
256).', found "'.getid3_lib
::PrintHexBytes(substr($AMVheader, 256, 8)).'"');
1400 // followed by 20 bytes of a modified WAVEFORMATEX:
1402 // WORD wFormatTag; //(Fixme: this is equal to PCM's 0x01 format code)
1403 // WORD nChannels; //(Fixme: this is always 1)
1404 // DWORD nSamplesPerSec; //(Fixme: for all known sample files this is equal to 22050)
1405 // DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100)
1406 // WORD nBlockAlign; //(Fixme: this seems to be 2 in AMV files, is this correct ?)
1407 // WORD wBitsPerSample; //(Fixme: this seems to be 16 in AMV files instead of the expected 4)
1408 // WORD cbSize; //(Fixme: this seems to be 0 in AMV files)
1411 $RIFFchunk['strf']['wformattag'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 264, 2));
1412 $RIFFchunk['strf']['nchannels'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 266, 2));
1413 $RIFFchunk['strf']['nsamplespersec'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 268, 4));
1414 $RIFFchunk['strf']['navgbytespersec'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 272, 4));
1415 $RIFFchunk['strf']['nblockalign'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 276, 2));
1416 $RIFFchunk['strf']['wbitspersample'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 278, 2));
1417 $RIFFchunk['strf']['cbsize'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 280, 2));
1418 $RIFFchunk['strf']['reserved'] = getid3_lib
::LittleEndian2Int(substr($AMVheader, 282, 2));
1421 $info['audio']['lossless'] = false;
1422 $info['audio']['sample_rate'] = $RIFFchunk['strf']['nsamplespersec'];
1423 $info['audio']['channels'] = $RIFFchunk['strf']['nchannels'];
1424 $info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
1425 $info['audio']['bitrate'] = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
1426 $info['audio']['bitrate_mode'] = 'cbr';
1429 } catch (getid3_exception
$e) {
1430 if ($e->getCode() == 10) {
1431 $this->warning('RIFFAMV parser: '.$e->getMessage());
1441 public function ParseRIFF($startoffset, $maxoffset) {
1442 $info = &$this->getid3
->info
;
1445 $FoundAllChunksWeNeed = false;
1448 $this->fseek($startoffset);
1449 $maxoffset = min($maxoffset, $info['avdataend']);
1450 while ($this->ftell() < $maxoffset) {
1451 $chunknamesize = $this->fread(8);
1452 //$chunkname = substr($chunknamesize, 0, 4);
1453 $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
1454 $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
1455 //if (strlen(trim($chunkname, "\x00")) < 4) {
1456 if (strlen($chunkname) < 4) {
1457 $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.');
1460 if (($chunksize == 0) && ($chunkname != 'JUNK')) {
1461 $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
1464 if (($chunksize %
2) != 0) {
1465 // all structures are packed on word boundaries
1469 switch ($chunkname) {
1471 $listname = $this->fread(4);
1472 if (preg_match('#^(movi|rec )$#i', $listname)) {
1473 $RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
1474 $RIFFchunk[$listname]['size'] = $chunksize;
1476 if (!$FoundAllChunksWeNeed) {
1477 $WhereWeWere = $this->ftell();
1478 $AudioChunkHeader = $this->fread(12);
1479 $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2);
1480 $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2);
1481 $AudioChunkSize = getid3_lib
::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
1483 if ($AudioChunkStreamType == 'wb') {
1484 $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
1485 if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
1487 if (getid3_mp3
::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
1488 $getid3_temp = new getID3();
1489 $getid3_temp->openfile($this->getid3
->filename
);
1490 $getid3_temp->info
['avdataoffset'] = $this->ftell() - 4;
1491 $getid3_temp->info
['avdataend'] = $this->ftell() +
$AudioChunkSize;
1492 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__
);
1493 $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info
['avdataoffset'], false);
1494 if (isset($getid3_temp->info
['mpeg']['audio'])) {
1495 $info['mpeg']['audio'] = $getid3_temp->info
['mpeg']['audio'];
1496 $info['audio'] = $getid3_temp->info
['audio'];
1497 $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
1498 $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
1499 $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
1500 $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
1501 $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1502 //$info['bitrate'] = $info['audio']['bitrate'];
1504 unset($getid3_temp, $getid3_mp3);
1507 } elseif (strpos($FirstFourBytes, getid3_ac3
::syncword
) === 0) {
1510 $getid3_temp = new getID3();
1511 $getid3_temp->openfile($this->getid3
->filename
);
1512 $getid3_temp->info
['avdataoffset'] = $this->ftell() - 4;
1513 $getid3_temp->info
['avdataend'] = $this->ftell() +
$AudioChunkSize;
1514 $getid3_ac3 = new getid3_ac3($getid3_temp);
1515 $getid3_ac3->Analyze();
1516 if (empty($getid3_temp->info
['error'])) {
1517 $info['audio'] = $getid3_temp->info
['audio'];
1518 $info['ac3'] = $getid3_temp->info
['ac3'];
1519 if (!empty($getid3_temp->info
['warning'])) {
1520 foreach ($getid3_temp->info
['warning'] as $key => $value) {
1521 $this->warning($value);
1525 unset($getid3_temp, $getid3_ac3);
1528 $FoundAllChunksWeNeed = true;
1529 $this->fseek($WhereWeWere);
1531 $this->fseek($chunksize - 4, SEEK_CUR
);
1535 if (!isset($RIFFchunk[$listname])) {
1536 $RIFFchunk[$listname] = array();
1538 $LISTchunkParent = $listname;
1539 $LISTchunkMaxOffset = $this->ftell() - 4 +
$chunksize;
1540 if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
1541 $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
1548 if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
1549 $this->fseek($chunksize, SEEK_CUR
);
1553 if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
1554 $thisindex = count($RIFFchunk[$chunkname]);
1556 $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
1557 $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
1558 switch ($chunkname) {
1560 $info['avdataoffset'] = $this->ftell();
1561 $info['avdataend'] = $info['avdataoffset'] +
$chunksize;
1563 $testData = $this->fread(36);
1564 if ($testData === '') {
1567 if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
1569 // Probably is MP3 data
1570 if (getid3_mp3
::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
1571 $getid3_temp = new getID3();
1572 $getid3_temp->openfile($this->getid3
->filename
);
1573 $getid3_temp->info
['avdataoffset'] = $info['avdataoffset'];
1574 $getid3_temp->info
['avdataend'] = $info['avdataend'];
1575 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__
);
1576 $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
1577 if (empty($getid3_temp->info
['error'])) {
1578 $info['audio'] = $getid3_temp->info
['audio'];
1579 $info['mpeg'] = $getid3_temp->info
['mpeg'];
1581 unset($getid3_temp, $getid3_mp3);
1584 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3
::syncword
)) ||
substr($testData, 8, 2) == strrev(getid3_ac3
::syncword
)) {
1586 // This is probably AC-3 data
1587 $getid3_temp = new getID3();
1588 if ($isRegularAC3) {
1589 $getid3_temp->openfile($this->getid3
->filename
);
1590 $getid3_temp->info
['avdataoffset'] = $info['avdataoffset'];
1591 $getid3_temp->info
['avdataend'] = $info['avdataend'];
1593 $getid3_ac3 = new getid3_ac3($getid3_temp);
1594 if ($isRegularAC3) {
1595 $getid3_ac3->Analyze();
1597 // Dolby Digital WAV
1598 // AC-3 content, but not encoded in same format as normal AC-3 file
1599 // For one thing, byte order is swapped
1601 for ($i = 0; $i < 28; $i +
= 2) {
1602 $ac3_data .= substr($testData, 8 +
$i +
1, 1);
1603 $ac3_data .= substr($testData, 8 +
$i +
0, 1);
1605 $getid3_ac3->AnalyzeString($ac3_data);
1608 if (empty($getid3_temp->info
['error'])) {
1609 $info['audio'] = $getid3_temp->info
['audio'];
1610 $info['ac3'] = $getid3_temp->info
['ac3'];
1611 if (!empty($getid3_temp->info
['warning'])) {
1612 foreach ($getid3_temp->info
['warning'] as $newerror) {
1613 $this->warning('getid3_ac3() says: ['.$newerror.']');
1617 unset($getid3_temp, $getid3_ac3);
1619 } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts
::$syncwords)).')/', $testData)) {
1621 // This is probably DTS data
1622 $getid3_temp = new getID3();
1623 $getid3_temp->openfile($this->getid3
->filename
);
1624 $getid3_temp->info
['avdataoffset'] = $info['avdataoffset'];
1625 $getid3_dts = new getid3_dts($getid3_temp);
1626 $getid3_dts->Analyze();
1627 if (empty($getid3_temp->info
['error'])) {
1628 $info['audio'] = $getid3_temp->info
['audio'];
1629 $info['dts'] = $getid3_temp->info
['dts'];
1630 $info['playtime_seconds'] = $getid3_temp->info
['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
1631 if (!empty($getid3_temp->info
['warning'])) {
1632 foreach ($getid3_temp->info
['warning'] as $newerror) {
1633 $this->warning('getid3_dts() says: ['.$newerror.']');
1638 unset($getid3_temp, $getid3_dts);
1640 } elseif (substr($testData, 0, 4) == 'wvpk') {
1642 // This is WavPack data
1643 $info['wavpack']['offset'] = $info['avdataoffset'];
1644 $info['wavpack']['size'] = getid3_lib
::LittleEndian2Int(substr($testData, 4, 4));
1645 $this->parseWavPackHeader(substr($testData, 8, 28));
1648 // This is some other kind of data (quite possibly just PCM)
1649 // do nothing special, just skip it
1651 $nextoffset = $info['avdataend'];
1652 $this->fseek($nextoffset);
1664 // always read data in
1666 // should be: never read data in
1667 // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
1668 if ($chunksize < 1048576) {
1669 if ($chunksize > 0) {
1670 $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1671 if ($chunkname == 'JUNK') {
1672 if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
1673 // only keep text characters [chr(32)-chr(127)]
1674 $info['riff']['comments']['junk'][] = trim($matches[1]);
1676 // but if nothing there, ignore
1677 // remove the key in either case
1678 unset($RIFFchunk[$chunkname][$thisindex]['data']);
1682 $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data');
1683 $this->fseek($chunksize, SEEK_CUR
);
1688 // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
1692 if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] +
$RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
1693 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1694 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
1695 unset($RIFFchunk[$chunkname][$thisindex]['offset']);
1696 unset($RIFFchunk[$chunkname][$thisindex]['size']);
1697 if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
1698 unset($RIFFchunk[$chunkname][$thisindex]);
1700 if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
1701 unset($RIFFchunk[$chunkname]);
1703 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1704 } elseif ($chunksize < 2048) {
1705 // only read data in if smaller than 2kB
1706 $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1708 $this->fseek($chunksize, SEEK_CUR
);
1716 } catch (getid3_exception
$e) {
1717 if ($e->getCode() == 10) {
1718 $this->warning('RIFF parser: '.$e->getMessage());
1727 public function ParseRIFFdata(&$RIFFdata) {
1728 $info = &$this->getid3
->info
;
1730 $tempfile = tempnam(GETID3_TEMP_DIR
, 'getID3');
1731 $fp_temp = fopen($tempfile, 'wb');
1732 $RIFFdataLength = strlen($RIFFdata);
1733 $NewLengthString = getid3_lib
::LittleEndian2String($RIFFdataLength, 4);
1734 for ($i = 0; $i < 4; $i++
) {
1735 $RIFFdata[($i +
4)] = $NewLengthString[$i];
1737 fwrite($fp_temp, $RIFFdata);
1740 $getid3_temp = new getID3();
1741 $getid3_temp->openfile($tempfile);
1742 $getid3_temp->info
['filesize'] = $RIFFdataLength;
1743 $getid3_temp->info
['filenamepath'] = $info['filenamepath'];
1744 $getid3_temp->info
['tags'] = $info['tags'];
1745 $getid3_temp->info
['warning'] = $info['warning'];
1746 $getid3_temp->info
['error'] = $info['error'];
1747 $getid3_temp->info
['comments'] = $info['comments'];
1748 $getid3_temp->info
['audio'] = (isset($info['audio']) ?
$info['audio'] : array());
1749 $getid3_temp->info
['video'] = (isset($info['video']) ?
$info['video'] : array());
1750 $getid3_riff = new getid3_riff($getid3_temp);
1751 $getid3_riff->Analyze();
1753 $info['riff'] = $getid3_temp->info
['riff'];
1754 $info['warning'] = $getid3_temp->info
['warning'];
1755 $info['error'] = $getid3_temp->info
['error'];
1756 $info['tags'] = $getid3_temp->info
['tags'];
1757 $info['comments'] = $getid3_temp->info
['comments'];
1758 unset($getid3_riff, $getid3_temp);
1764 public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
1765 $RIFFinfoKeyLookup = array(
1766 'IARL'=>'archivallocation',
1768 'ICDS'=>'costumedesigner',
1769 'ICMS'=>'commissionedby',
1772 'ICOP'=>'copyright',
1773 'ICRD'=>'creationdate',
1774 'IDIM'=>'dimensions',
1775 'IDIT'=>'digitizationdate',
1776 'IDPI'=>'resolution',
1777 'IDST'=>'distributor',
1779 'IENG'=>'engineers',
1780 'IFRM'=>'accountofparts',
1783 'ILGT'=>'lightness',
1785 'IMED'=>'orignalmedium',
1788 'IPDS'=>'productiondesigner',
1796 'ISGN'=>'secondarygenre',
1797 'ISHP'=>'sharpness',
1798 'ISRC'=>'sourcesupplier',
1799 'ISRF'=>'digitizationsource',
1800 'ISTD'=>'productionstudio',
1802 'ITCH'=>'encoded_by',
1807 foreach ($RIFFinfoKeyLookup as $key => $value) {
1808 if (isset($RIFFinfoArray[$key])) {
1809 foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
1810 if (trim($commentdata['data']) != '') {
1811 if (isset($CommentsTargetArray[$value])) {
1812 $CommentsTargetArray[$value][] = trim($commentdata['data']);
1814 $CommentsTargetArray[$value] = array(trim($commentdata['data']));
1823 public static function parseWAVEFORMATex($WaveFormatExData) {
1825 $WaveFormatEx['raw'] = array();
1826 $WaveFormatEx_raw = &$WaveFormatEx['raw'];
1828 $WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2);
1829 $WaveFormatEx_raw['nChannels'] = substr($WaveFormatExData, 2, 2);
1830 $WaveFormatEx_raw['nSamplesPerSec'] = substr($WaveFormatExData, 4, 4);
1831 $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData, 8, 4);
1832 $WaveFormatEx_raw['nBlockAlign'] = substr($WaveFormatExData, 12, 2);
1833 $WaveFormatEx_raw['wBitsPerSample'] = substr($WaveFormatExData, 14, 2);
1834 if (strlen($WaveFormatExData) > 16) {
1835 $WaveFormatEx_raw['cbSize'] = substr($WaveFormatExData, 16, 2);
1837 $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw);
1839 $WaveFormatEx['codec'] = self
::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']);
1840 $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels'];
1841 $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec'];
1842 $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8;
1843 $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample'];
1845 return $WaveFormatEx;
1848 public function parseWavPackHeader($WavPackChunkData) {
1853 // short bits; // added for version 2.00
1854 // short flags, shift; // added for version 3.00
1855 // long total_samples, crc, crc2;
1856 // char extension [4], extra_bc, extras [3];
1860 $info = &$this->getid3
->info
;
1861 $info['wavpack'] = array();
1862 $thisfile_wavpack = &$info['wavpack'];
1864 $thisfile_wavpack['version'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 0, 2));
1865 if ($thisfile_wavpack['version'] >= 2) {
1866 $thisfile_wavpack['bits'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 2, 2));
1868 if ($thisfile_wavpack['version'] >= 3) {
1869 $thisfile_wavpack['flags_raw'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 4, 2));
1870 $thisfile_wavpack['shift'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 6, 2));
1871 $thisfile_wavpack['total_samples'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 8, 4));
1872 $thisfile_wavpack['crc1'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 12, 4));
1873 $thisfile_wavpack['crc2'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 16, 4));
1874 $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4);
1875 $thisfile_wavpack['extra_bc'] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 24, 1));
1876 for ($i = 0; $i <= 2; $i++
) {
1877 $thisfile_wavpack['extras'][] = getid3_lib
::LittleEndian2Int(substr($WavPackChunkData, 25 +
$i, 1));
1881 $thisfile_wavpack['flags'] = array();
1882 $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
1884 $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
1885 $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002);
1886 $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004);
1887 $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008);
1888 $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010);
1889 $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020);
1890 $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040);
1891 $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080);
1892 $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100);
1893 $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200);
1894 $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400);
1895 $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800);
1896 $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000);
1897 $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000);
1898 $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000);
1899 $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000);
1900 $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000);
1901 $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000);
1902 $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000);
1903 $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000);
1909 public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
1911 $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
1912 $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels
1913 $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
1914 $parsed['biPlanes'] = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1
1915 $parsed['biBitCount'] = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels
1916 $parsed['biSizeImage'] = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
1917 $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device
1918 $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device
1919 $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
1920 $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
1921 $parsed = array_map('getid3_lib::'.($littleEndian ?
'Little' : 'Big').'Endian2Int', $parsed);
1923 $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier
1928 public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
1929 // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
1930 // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
1931 // 'Byte Layout: '1111111111111111
1932 // '32 for Movie - 1 '1111111111111111
1933 // '28 for Author - 6 '6666666666666666
1934 // '4 for year - 2 '6666666666662222
1935 // '3 for genre - 3 '7777777777777777
1936 // '48 for Comments - 7 '7777777777777777
1937 // '1 for Rating - 4 '7777777777777777
1938 // '5 for Future Additions - 0 '333400000DIVXTAG
1941 static $DIVXTAGgenre = array(
1943 1 => 'Action/Adventure',
1955 13 => 'Infomercial',
1956 14 => 'Interactive',
1958 16 => 'Music Video',
1965 $DIVXTAGrating = array(
1974 $parsed['title'] = trim(substr($DIVXTAG, 0, 32));
1975 $parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
1976 $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4)));
1977 $parsed['comment'] = trim(substr($DIVXTAG, 64, 48));
1978 $parsed['genre_id'] = intval(trim(substr($DIVXTAG, 112, 3)));
1979 $parsed['rating_id'] = ord(substr($DIVXTAG, 115, 1));
1980 //$parsed['padding'] = substr($DIVXTAG, 116, 5); // 5-byte null
1981 //$parsed['magic'] = substr($DIVXTAG, 121, 7); // "DIVXTAG"
1983 $parsed['genre'] = (isset($DIVXTAGgenre[$parsed['genre_id']]) ?
$DIVXTAGgenre[$parsed['genre_id']] : $parsed['genre_id']);
1984 $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ?
$DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']);
1987 unset($parsed['genre_id'], $parsed['rating_id']);
1988 foreach ($parsed as $key => $value) {
1989 if (!$value === '') {
1990 unset($parsed['key']);
1995 foreach ($parsed as $tag => $value) {
1996 $parsed[$tag] = array($value);
2002 public static function waveSNDMtagLookup($tagshortname) {
2005 /** This is not a comment!
2012 ©fin featuredinstrument
2022 return getid3_lib
::EmbeddedLookup($tagshortname, $begin, __LINE__
, __FILE__
, 'riff-sndm');
2025 public static function wFormatTagLookup($wFormatTag) {
2029 /** This is not a comment!
2031 0x0000 Microsoft Unknown Wave Format
2032 0x0001 Pulse Code Modulation (PCM)
2033 0x0002 Microsoft ADPCM
2035 0x0004 Compaq Computer VSELP
2037 0x0006 Microsoft A-Law
2038 0x0007 Microsoft mu-Law
2039 0x0008 Microsoft DTS
2041 0x0011 Intel DVI/IMA ADPCM
2042 0x0012 Videologic MediaSpace ADPCM
2043 0x0013 Sierra Semiconductor ADPCM
2044 0x0014 Antex Electronics G.723 ADPCM
2045 0x0015 DSP Solutions DigiSTD
2046 0x0016 DSP Solutions DigiFIX
2047 0x0017 Dialogic OKI ADPCM
2048 0x0018 MediaVision ADPCM
2049 0x0019 Hewlett-Packard CU
2051 0x0021 Speech Compression Sonarc
2052 0x0022 DSP Group TrueSpeech
2053 0x0023 Echo Speech EchoSC1
2054 0x0024 Audiofile AF36
2055 0x0025 Audio Processing Technology APTX
2056 0x0026 AudioFile AF10
2060 0x0031 Microsoft GSM 6.10
2062 0x0033 Antex Electronics ADPCME
2063 0x0034 Control Resources VQLPC
2064 0x0035 DSP Solutions DigiREAL
2065 0x0036 DSP Solutions DigiADPCM
2066 0x0037 Control Resources CR10
2067 0x0038 Natural MicroSystems VBXADPCM
2068 0x0039 Crystal Semiconductor IMA ADPCM
2070 0x003B Rockwell ADPCM
2071 0x003C Rockwell Digit LK
2073 0x0040 Antex Electronics G.721 ADPCM
2076 0x0050 MPEG Layer-2 or Layer-1
2084 0x0063 Canopus Atrac
2089 0x0069 Voxware Byte Aligned
2094 0x0074 Voxware MetaVoice
2095 0x0075 Voxware MetaSound
2096 0x0076 Voxware RT29HW
2110 0x0092 Dolby AC3 SPDIF
2111 0x0093 MediaSonic G.723
2112 0x0094 Aculab PLC Prosody 8kbps
2114 0x0098 Philips LPCBB
2117 0x0100 Rhetorex ADPCM
2120 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)
2123 0x0123 Digital G.723
2124 0x0125 Sanyo LD ADPCM
2125 0x0130 Sipro Lab Telecom ACELP NET
2126 0x0131 Sipro Lab Telecom ACELP 4800
2127 0x0132 Sipro Lab Telecom ACELP 8V3
2128 0x0133 Sipro Lab Telecom G.729
2129 0x0134 Sipro Lab Telecom G.729A
2130 0x0135 Sipro Lab Telecom Kelvin
2131 0x0140 Windows Media Video V8
2132 0x0150 Qualcomm PureVoice
2133 0x0151 Qualcomm HalfRate
2134 0x0155 Ring Zero Systems TUB GSM
2135 0x0160 Microsoft Audio 1
2136 0x0161 Windows Media Audio V7 / V8 / V9
2137 0x0162 Windows Media Audio Professional V9
2138 0x0163 Windows Media Audio Lossless V9
2139 0x0200 Creative Labs ADPCM
2140 0x0202 Creative Labs Fastspeech8
2141 0x0203 Creative Labs Fastspeech10
2142 0x0210 UHER Informatic GmbH ADPCM
2144 0x0230 I-link Worldwide VC
2145 0x0240 Aureal RAW Sport
2146 0x0250 Interactive Products HSX
2147 0x0251 Interactive Products RPELP
2148 0x0260 Consistent Software CS2
2150 0x0300 Fujitsu FM Towns Snd
2152 0x0401 Intel Music Coder
2153 0x0450 QDesign Music
2155 0x0681 AT&T Labs TPC
2156 0x08AE ClearJump LiteWave
2158 0x1001 Olivetti ADPCM
2159 0x1002 Olivetti CELP
2162 0x1100 Lernout & Hauspie Codec (0x1100)
2163 0x1101 Lernout & Hauspie CELP Codec (0x1101)
2164 0x1102 Lernout & Hauspie SBC Codec (0x1102)
2165 0x1103 Lernout & Hauspie SBC Codec (0x1103)
2166 0x1104 Lernout & Hauspie SBC Codec (0x1104)
2168 0x1401 AT&T ISIAudio
2169 0x1500 Soundspace Music Compression
2170 0x181C VoxWare RT24 Speech
2171 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com)
2174 0x2002 WAVE_FORMAT_14_4
2175 0x2003 WAVE_FORMAT_28_8
2176 0x2004 WAVE_FORMAT_COOK
2177 0x2005 WAVE_FORMAT_DNET
2181 0x676F Ogg Vorbis 1+
2182 0x6770 Ogg Vorbis 2+
2183 0x6771 Ogg Vorbis 3+
2184 0x7A21 GSM-AMR (CBR, no SID)
2185 0x7A22 GSM-AMR (VBR, including SID)
2186 0xFFFE WAVE_FORMAT_EXTENSIBLE
2187 0xFFFF WAVE_FORMAT_DEVELOPMENT
2191 return getid3_lib
::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT
), $begin, __LINE__
, __FILE__
, 'riff-wFormatTag');
2194 public static function fourccLookup($fourcc) {
2198 /** This is not a comment!
2200 swot http://developer.apple.com/qa/snd/snd07.html
2201 ____ No Codec (____)
2202 _BIT BI_BITFIELDS (Raw RGB)
2203 _JPG JPEG compressed
2204 _PNG PNG compressed W3C/ISO/IEC (RFC-2083)
2205 _RAW Full Frames (Uncompressed)
2212 AASC Autodesk Animator
2213 ABYR Kensington ?ABYR?
2214 AEMI Array Microsystems VideoONE MPEG1-I Capture
2215 AFLC Autodesk Animator FLC
2216 AFLI Autodesk Animator FLI
2217 AMPG Array Microsystems VideoONE MPEG
2218 ANIM Intel RDX (ANIM)
2219 AP41 AngelPotion Definitive
2222 ASVX Asus Video 2.0 (audio)
2223 AUR2 AuraVision Aura 2 Codec - YUV 4:2:2
2224 AURA AuraVision Aura 1 Codec - YUV 4:1:1
2225 AVDJ Independent JPEG Group\'s codec (AVDJ)
2226 AVRN Independent JPEG Group\'s codec (AVRN)
2227 AYUV 4:4:4 YUV (AYUV)
2228 AZPR Quicktime Apple Video (AZPR)
2230 BLZ0 Blizzard DivX MPEG-4
2231 BTVC Conexant Composite Video
2232 BINK RAD Game Tools Bink Video
2233 BT20 Conexant Prosumer Video
2234 BTCV Conexant Composite Video Codec
2235 BW10 Data Translation Broadway MPEG Capture
2238 CFCC Digital Processing Systems DPS Perception
2239 CGDI Microsoft Office 97 Camcorder Video
2240 CHAM Winnov Caviara Champagne
2241 CJPG Creative WebCam JPEG
2242 CLJR Cirrus Logic YUV 4:1:1
2243 CMYK Common Data Format in Printing (Colorgraph)
2244 CPLA Weitek 4:2:0 YUV Planar
2245 CRAM Microsoft Video 1 (CRAM)
2248 CWLT Microsoft Color WLT DIB
2249 CYUV Creative Labs YUV
2253 DIB Device Independent Bitmap
2254 DIV1 FFmpeg OpenDivX
2255 DIV2 Microsoft MPEG-4 v1/v2
2256 DIV3 DivX ;-) MPEG-4 v3.x Low-Motion
2257 DIV4 DivX ;-) MPEG-4 v3.x Fast-Motion
2258 DIV5 DivX MPEG-4 v5.x
2259 DIV6 DivX ;-) (MS MPEG-4 v3.x)
2260 DIVX DivX MPEG-4 v4 (OpenDivX / Project Mayo)
2262 DMB1 Matrox Rainbow Runner hardware MJPEG
2265 DUCK Duck TrueMotion 1.0
2266 DPS0 DPS/Leitch Reality Motion JPEG
2267 DPSC DPS/Leitch PAR Motion JPEG
2268 DV25 Matrox DVCPRO codec
2269 DV50 Matrox DVCPRO50 codec
2270 DVC IEC 61834 and SMPTE 314M (DVC/DV Video)
2271 DVCP IEC 61834 and SMPTE 314M (DVC/DV Video)
2272 DVHD IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps
2273 DVMA Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com)
2274 DVSL IEC Standard DV compressed in SD (SDL)
2276 DVE2 InSoft DVE-2 Videoconferencing
2277 dvsd IEC 61834 and SMPTE 314M DVC/DV Video
2278 DVSD IEC 61834 and SMPTE 314M DVC/DV Video
2279 DVX1 Lucent DVX1000SP Video Decoder
2280 DVX2 Lucent DVX2000S Video Decoder
2281 DVX3 Lucent DVX3000S Video Decoder
2283 DXT1 Microsoft DirectX Compressed Texture (DXT1)
2284 DXT2 Microsoft DirectX Compressed Texture (DXT2)
2285 DXT3 Microsoft DirectX Compressed Texture (DXT3)
2286 DXT4 Microsoft DirectX Compressed Texture (DXT4)
2287 DXT5 Microsoft DirectX Compressed Texture (DXT5)
2288 DXTC Microsoft DirectX Compressed Texture (DXTC)
2289 DXTn Microsoft DirectX Compressed Texture (DXTn)
2290 EM2V Etymonix MPEG-2 I-frame (www.etymonix.com)
2294 ETV1 eTreppid Video ETV1
2295 ETV2 eTreppid Video ETV2
2296 ETVC eTreppid Video ETVC
2297 FLIC Autodesk FLI/FLC Animation
2299 FLV4 On2 TrueMotion VP6
2300 FRWT Darim Vision Forward Motion JPEG (www.darvision.com)
2301 FRWU Darim Vision Forward Uncompressed (www.darvision.com)
2302 FLJP D-Vision Field Encoded Motion JPEG
2304 FRWA SoftLab-Nsk Forward Motion JPEG w/ alpha channel
2305 FRWD SoftLab-Nsk Forward Motion JPEG
2306 FVF1 Iterated Systems Fractal Video Frame
2307 GLZW Motion LZW (gabest@freemail.hu)
2308 GPEG Motion JPEG (gabest@freemail.hu)
2309 GWLT Microsoft Greyscale WLT DIB
2310 H260 Intel ITU H.260 Videoconferencing
2311 H261 Intel ITU H.261 Videoconferencing
2312 H262 Intel ITU H.262 Videoconferencing
2313 H263 Intel ITU H.263 Videoconferencing
2314 H264 Intel ITU H.264 Videoconferencing
2315 H265 Intel ITU H.265 Videoconferencing
2316 H266 Intel ITU H.266 Videoconferencing
2317 H267 Intel ITU H.267 Videoconferencing
2318 H268 Intel ITU H.268 Videoconferencing
2319 H269 Intel ITU H.269 Videoconferencing
2320 HFYU Huffman Lossless Codec
2321 HMCR Rendition Motion Compensation Format (HMCR)
2322 HMRR Rendition Motion Compensation Format (HMRR)
2323 I263 FFmpeg I263 decoder
2324 IF09 Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane")
2325 IUYV Interlaced version of UYVY (www.leadtools.com)
2326 IY41 Interlaced version of Y41P (www.leadtools.com)
2327 IYU1 12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
2328 IYU2 24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
2329 IYUV Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes)
2330 i263 Intel ITU H.263 Videoconferencing (i263)
2332 IAN Intel Indeo 4 (RDX)
2333 ICLB InSoft CellB Videoconferencing
2335 IJPG Intergraph JPEG
2336 ILVC Intel Layered Video
2338 IPDV I-O Data Device Giga AVI DV Codec
2339 IR21 Intel Indeo 2.1
2340 IRAW Intel YUV Uncompressed
2341 IV30 Intel Indeo 3.0
2342 IV31 Intel Indeo 3.1
2343 IV32 Ligos Indeo 3.2
2344 IV33 Ligos Indeo 3.3
2345 IV34 Ligos Indeo 3.4
2346 IV35 Ligos Indeo 3.5
2347 IV36 Ligos Indeo 3.6
2348 IV37 Ligos Indeo 3.7
2349 IV38 Ligos Indeo 3.8
2350 IV39 Ligos Indeo 3.9
2351 IV40 Ligos Indeo Interactive 4.0
2352 IV41 Ligos Indeo Interactive 4.1
2353 IV42 Ligos Indeo Interactive 4.2
2354 IV43 Ligos Indeo Interactive 4.3
2355 IV44 Ligos Indeo Interactive 4.4
2356 IV45 Ligos Indeo Interactive 4.5
2357 IV46 Ligos Indeo Interactive 4.6
2358 IV47 Ligos Indeo Interactive 4.7
2359 IV48 Ligos Indeo Interactive 4.8
2360 IV49 Ligos Indeo Interactive 4.9
2361 IV50 Ligos Indeo Interactive 5.0
2362 JBYR Kensington ?JBYR?
2363 JPEG Still Image JPEG DIB
2364 JPGL Pegasus Lossless Motion JPEG
2365 KMVC Team17 Software Karl Morton\'s Video Codec
2366 LSVM Vianet Lighting Strike Vmail (Streaming) (www.vianet.com)
2367 LEAD LEAD Video Codec
2368 Ljpg LEAD MJPEG Codec
2369 MDVD Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de)
2370 MJPA Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com)
2371 MJPB Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com)
2372 MMES Matrox MPEG-2 I-frame
2373 MP2v Microsoft S-Mpeg 4 version 1 (MP2v)
2374 MP42 Microsoft S-Mpeg 4 version 2 (MP42)
2375 MP43 Microsoft S-Mpeg 4 version 3 (MP43)
2376 MP4S Microsoft S-Mpeg 4 version 3 (MP4S)
2378 MPG1 FFmpeg MPEG 1/2
2379 MPG2 FFmpeg MPEG 1/2
2380 MPG3 FFmpeg DivX ;-) (MS MPEG-4 v3)
2381 MPG4 Microsoft MPEG-4
2382 MPGI Sigma Designs MPEG
2383 MPNG PNG images decoder
2384 MSS1 Microsoft Windows Screen Video
2385 MSZH LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
2386 M261 Microsoft H.261
2387 M263 Microsoft H.263
2388 M4S2 Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2)
2389 m4s2 Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2)
2390 MC12 ATI Motion Compensation Format (MC12)
2391 MCAM ATI Motion Compensation Format (MCAM)
2392 MJ2C Morgan Multimedia Motion JPEG2000
2393 mJPG IBM Motion JPEG w/ Huffman Tables
2394 MJPG Microsoft Motion JPEG DIB
2395 MP42 Microsoft MPEG-4 (low-motion)
2396 MP43 Microsoft MPEG-4 (fast-motion)
2397 MP4S Microsoft MPEG-4 (MP4S)
2398 mp4s Microsoft MPEG-4 (mp4s)
2399 MPEG Chromatic Research MPEG-1 Video I-Frame
2400 MPG4 Microsoft MPEG-4 Video High Speed Compressor
2401 MPGI Sigma Designs MPEG
2402 MRCA FAST Multimedia Martin Regen Codec
2403 MRLE Microsoft Run Length Encoding
2404 MSVC Microsoft Video 1
2414 MV12 Motion Pixels Codec (old)
2415 MWV1 Aware Motion Wavelets
2416 nAVI SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm)
2417 NT00 NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com)
2419 NTN1 Nogatech Video Compression 1
2420 NVS0 nVidia GeForce Texture (NVS0)
2421 NVS1 nVidia GeForce Texture (NVS1)
2422 NVS2 nVidia GeForce Texture (NVS2)
2423 NVS3 nVidia GeForce Texture (NVS3)
2424 NVS4 nVidia GeForce Texture (NVS4)
2425 NVS5 nVidia GeForce Texture (NVS5)
2426 NVT0 nVidia GeForce Texture (NVT0)
2427 NVT1 nVidia GeForce Texture (NVT1)
2428 NVT2 nVidia GeForce Texture (NVT2)
2429 NVT3 nVidia GeForce Texture (NVT3)
2430 NVT4 nVidia GeForce Texture (NVT4)
2431 NVT5 nVidia GeForce Texture (NVT5)
2432 PIXL MiroXL, Pinnacle PCTV
2433 PDVC I-O Data Device Digital Video Capture DV codec
2434 PGVV Radius Video Vision
2435 PHMO IBM Photomotion
2436 PIM1 MPEG Realtime (Pinnacle Cards)
2437 PIM2 Pegasus Imaging ?PIM2?
2438 PIMJ Pegasus Imaging Lossless JPEG
2439 PVEZ Horizons Technology PowerEZ
2440 PVMM PacketVideo Corporation MPEG-4
2441 PVW2 Pegasus Imaging Wavelet Compression
2442 Q1.0 Q-Team\'s QPEG 1.0 (www.q-team.de)
2443 Q1.1 Q-Team\'s QPEG 1.1 (www.q-team.de)
2444 QPEG Q-Team QPEG 1.0
2445 qpeq Q-Team QPEG 1.1
2447 RGBA Raw RGB w/ Alpha
2448 RMP4 REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com)
2449 ROQV Id RoQ File Video Decoder
2450 RPZA Quicktime Apple Video (RPZA)
2451 RUD0 Rududu video codec (http://rududu.ifrance.com/rududu/)
2452 RV10 RealVideo 1.0 (aka RealVideo 5.0)
2453 RV13 RealVideo 1.0 (RV13)
2457 RGBT Raw RGB w/ Transparency
2458 RLE Microsoft Run Length Encoder
2459 RLE4 Run Length Encoded (4bpp, 16-color)
2460 RLE8 Run Length Encoded (8bpp, 256-color)
2461 RT21 Intel Indeo RealTime Video 2.1
2464 RVX Intel RDX (RVX )
2465 SMC Apple Graphics (SMC )
2466 SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2
2468 SVQ3 Sorenson Video 3 (Apple Quicktime 5)
2469 s422 Tekram VideoCap C210 YUV 4:2:2
2470 SDCC Sun Communication Digital Camera Codec
2471 SFMC CrystalNet Surface Fitting Method
2474 smsv WorldConnect Wavelet Video
2476 SPLC Splash Studios ACM Audio Codec (www.splashstudios.net)
2477 SQZ2 Microsoft VXTreme Video Codec V2
2478 STVA ST Microelectronics CMOS Imager Data (Bayer)
2479 STVB ST Microelectronics CMOS Imager Data (Nudged Bayer)
2480 STVC ST Microelectronics CMOS Imager Data (Bunched)
2481 STVX ST Microelectronics CMOS Imager Data (Extended CODEC Data Format)
2482 STVY ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data)
2483 SV10 Sorenson Video R1
2485 T420 Toshiba YUV 4:2:0
2486 TM2A Duck TrueMotion Archiver 2.0 (www.duck.com)
2487 TVJP Pinnacle/Truevision Targa 2000 board (TVJP)
2488 TVMJ Pinnacle/Truevision Targa 2000 board (TVMJ)
2489 TY0N Tecomac Low-Bit Rate Codec (www.tecomac.com)
2490 TY2C Trident Decompression Driver
2491 TLMS TeraLogic Motion Intraframe Codec (TLMS)
2492 TLST TeraLogic Motion Intraframe Codec (TLST)
2493 TM20 Duck TrueMotion 2.0
2494 TM2X Duck TrueMotion 2X
2495 TMIC TeraLogic Motion Intraframe Codec (TMIC)
2496 TMOT Horizons Technology TrueMotion S
2497 tmot Horizons TrueMotion Video Compression
2498 TR20 Duck TrueMotion RealTime 2.0
2499 TSCC TechSmith Screen Capture Codec
2500 TV10 Tecomac Low-Bit Rate Codec
2502 U263 UB Video H.263/H.263+/H.263++ Decoder
2503 UMP4 UB Video MPEG 4 (www.ubvideo.com)
2504 UYNV Nvidia UYVY packed 4:2:2
2505 UYVP Evans & Sutherland YCbCr 4:2:2 extended precision
2506 UCOD eMajix.com ClearVideo
2508 UYVY UYVY packed 4:2:2
2510 VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/)
2511 VIV1 FFmpeg H263+ decoder
2513 VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)
2514 VTLP Alaris VideoGramPiX
2518 V422 Vitec Multimedia 24-bit YUV 4:2:2 Format
2519 V655 Vitec Multimedia 16-bit YUV 4:2:2 Format
2520 VCR1 ATI Video Codec 1
2521 VCR2 ATI Video Codec 2
2529 VDCT Vitec Multimedia Video Maker Pro DIB
2531 VDOW VDOnet VDOLive (H.263)
2532 VDTZ Darim Vison VideoTizer YUV
2533 VGPX Alaris VideoGramPiX
2534 VIDS Vitec Multimedia YUV 4:2:2 CCIR 601 for V422
2535 VIVO Vivo H.263 v2.00
2537 VIXL Miro/Pinnacle Video XL
2538 VLV1 VideoLogic/PURE Digital Videologic Capture
2541 VP6F On2 TrueMotion VP6
2542 VX1K Lucent VX1000S Video Codec
2543 VX2K Lucent VX2000S Video Codec
2544 VXSP Lucent VX1000SP Video Codec
2546 WHAM Microsoft Video 1 (WHAM)
2547 WINX Winnov Software Compression
2548 WJPG AverMedia Winbond JPEG
2549 WMV1 Windows Media Video V7
2550 WMV2 Windows Media Video V8
2551 WMV3 Windows Media Video V9
2552 WNV1 Winnov Hardware Compression
2553 XYZP Extended PAL format XYZ palette (www.riff.org)
2555 XLV0 NetXL Video Decoder
2556 XMPG Xing MPEG (I-Frame only)
2557 XVID XviD MPEG-4 (www.xvid.org)
2559 YU92 Intel YUV (YU92)
2560 YUNV Nvidia Uncompressed YUV 4:2:2
2561 YUVP Extended PAL format YUV palette (www.riff.org)
2562 Y211 YUV 2:1:1 Packed
2563 Y411 YUV 4:1:1 Packed
2564 Y41B Weitek YUV 4:1:1 Planar
2565 Y41P Brooktree PC1 YUV 4:1:1 Packed
2566 Y41T Brooktree PC1 YUV 4:1:1 with transparency
2567 Y42B Weitek YUV 4:2:2 Planar
2568 Y42T Brooktree UYUV 4:2:2 with transparency
2569 Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
2570 Y800 Simple, single Y plane for monochrome images
2572 YC12 Intel YUV 12 codec
2573 YUV8 Winnov Caviar YUV8
2575 YUY2 Uncompressed YUV 4:2:2
2578 YVU9 Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes)
2579 YVYU YVYU 4:2:2 Packed
2580 ZLIB Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
2581 ZPEG Metheus Video Zipper
2585 return getid3_lib
::EmbeddedLookup($fourcc, $begin, __LINE__
, __FILE__
, 'riff-fourcc');
2588 private function EitherEndian2Int($byteword, $signed=false) {
2589 if ($this->container
== 'riff') {
2590 return getid3_lib
::LittleEndian2Int($byteword, $signed);
2592 return getid3_lib
::BigEndian2Int($byteword, false, $signed);