35 $info = &$this->getid3->info;
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'];
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);
64 $this->container =
'aiff';
66 $thisfile_riff[$RIFFsubtype] = $this->
ParseRIFF($offset, ($offset + $thisfile_riff[
'header_size'] - 4));
73 $this->container =
'riff';
75 if ($RIFFsubtype ==
'RMP3') {
77 $RIFFsubtype =
'WAVE';
79 if ($RIFFsubtype !=
'AMV ') {
82 $thisfile_riff[$RIFFsubtype] = $this->
ParseRIFF($offset, ($offset + $thisfile_riff[
'header_size'] - 4));
84 if ((
$info[
'avdataend'] -
$info[
'filesize']) == 1) {
91 $nextRIFFoffset = $Original[
'avdataoffset'] + 8 + $thisfile_riff[
'header_size'];
92 while ($nextRIFFoffset < min(
$info[
'filesize'],
$info[
'avdataend'])) {
94 $this->
fseek($nextRIFFoffset);
96 if ($e->getCode() == 10) {
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") {
112 $nextRIFFheaderID = substr($nextRIFFheader, 0, 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']);
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') {
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');
171 switch ($RIFFsubtype) {
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];
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'])) {
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'];
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)) {
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)) {
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));
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);
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);
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'])) {
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'])) {
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']);
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'];
458 $info[
'avdataend'] = $Original[
'avdataend'];
459 $thisfile_audio[
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
462 $RIFFdata = $this->
fread(44);
466 if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
467 $info[
'avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
469 $RIFFdata .= $this->
fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
475 $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
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'])) {
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'])) {
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'];
502 $thisfile_audio[
'bitrate_mode'] =
'vbr';
503 $thisfile_audio_dataformat =
'litewave';
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) {
541 $litewave_offset += $length;
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'];
560 switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat :
'') {
569 if ((
$info[
'avdataend'] -
$info[
'filesize']) == 1) {
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)');
581 if (((
$info[
'avdataend'] -
$info[
'filesize']) == 1) && (($thisfile_riff[$RIFFsubtype][
'data'][0][
'size'] % 2) == 0) && (((
$info[
'filesize'] -
$info[
'avdataoffset']) % 2) == 1)) {
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)');
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)');
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'];
610 $info[
'fileformat'] =
'avi';
611 $info[
'mime_type'] =
'video/avi';
613 $thisfile_video[
'bitrate_mode'] =
'vbr';
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'];
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)');
629 if (isset($thisfile_riff[
'AVI '][
'hdrl'][
'strl'][
'indx'])) {
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));
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));
664 if ($thisfile_riff_raw_avih[
'dwMicroSecPerFrame'] == 0) {
665 $this->
error(
'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero');
671 'dwPaddingGranularity',
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']);
762 $thisfile_audio[
'lossless'] =
false;
763 switch ($thisfile_riff_raw_strf_strhfccType_streamindex[
'wFormatTag']) {
765 $thisfile_audio_dataformat =
'wav';
766 $thisfile_audio[
'lossless'] =
true;
770 $thisfile_audio_dataformat =
'mp2';
774 $thisfile_audio_dataformat =
'mp3';
778 $thisfile_audio_dataformat =
'aac';
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);
812 $thisfile_riff_raw_strh_current[
'fccHandler'] = substr($strhData, 4, 4);
813 $thisfile_riff_raw_strh_current[
'dwFlags'] = $this->
EitherEndian2Int(substr($strhData, 8, 4));
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']) {
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']) {
882 $thisfile_video[
'lossless'] =
true;
887 $thisfile_video[
'lossless'] =
false;
900 $info[
'fileformat'] =
'amv';
901 $info[
'mime_type'] =
'video/amv';
903 $thisfile_video[
'bitrate_mode'] =
'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;
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'];
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';
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'];
964 if ((
$info[
'avdataend'] == (
$info[
'filesize'] + 1)) && ((
$info[
'filesize'] % 2) == 1)) {
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');
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);
984 if ($thisfile_riff[$RIFFsubtype][
'COMM'][0][
'size'] > 18) {
985 $thisfile_riff_audio[
'codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
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']) {
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'])) {
1035 for ($i = 0; $i < $CommentCount; $i++) {
1042 $info[
'comments_raw'][
$i][
'comment'] = substr($thisfile_riff[$RIFFsubtype][
'COMT'][0][
'data'], $offset, $CommentLength);
1043 $offset += $CommentLength;
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'];
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;
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'])) {
1124 switch ($ChannelsIndex) {
1126 $thisfile_audio[
'channels'] = 2;
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';
1156 $info[
'mime_type'] =
'video/mpeg';
1158 if (!empty($thisfile_riff[
'CDXA'][
'data'][0][
'size'])) {
1161 $getid3_temp =
new getID3();
1162 $getid3_temp->openfile($this->getid3->filename);
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);
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');
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 '])) {
1204 $getid3_temp =
new getID3();
1205 $getid3_temp->openfile($this->getid3->filename);
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'])) {
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'];
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) {
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']);
ParseRIFFAMV($startoffset, $maxoffset)
ParseRIFF($startoffset, $maxoffset)
static RGADnameLookup($namecode)
static RGADoriginatorLookup($originatorcode)
static Bin2Dec($binstring, $signed=false)
static LittleEndian2Int($byteword, $signed=false)
static IncludeDependency($filename, $sourcefile, $DieOnFailure=false)
static BigEndian2Float($byteword)
static RGADadjustmentLookup($rawadjustment, $signbit)
static XML2array($XMLstring)
EitherEndian2Int($byteword, $signed=false)
static DateMac2Unix($macdate)
static CastAsInt($floatnum)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
static LittleEndian2Float($byteword)
fseek($bytes, $whence=SEEK_SET)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
static FixedPoint16_16($rawdata)
static array_merge_noclobber($array1, $array2)