188 if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) { |
188 if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) { |
189 |
189 |
190 $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($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']; |
191 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; |
192 if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) { |
192 if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) { |
193 $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero'; |
193 $this->error('Corrupt RIFF file: bitrate_audio == zero'); |
194 return false; |
194 return false; |
195 } |
195 } |
196 $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw']; |
196 $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw']; |
197 unset($thisfile_riff_audio[$streamindex]['raw']); |
197 unset($thisfile_riff_audio[$streamindex]['raw']); |
198 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; |
198 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; |
199 |
199 |
200 $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $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') { |
201 if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') { |
202 $info['warning'][] = 'Audio codec = '.$thisfile_audio['codec']; |
202 $this->warning('Audio codec = '.$thisfile_audio['codec']); |
203 } |
203 } |
204 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; |
204 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; |
205 |
205 |
206 if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) |
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']); |
207 $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); |
300 if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) { |
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; |
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; |
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']); |
303 $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']); |
304 } else { |
304 } else { |
305 $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid'; |
305 $this->warning('RIFF.WAVE.BEXT.origin_time is invalid'); |
306 } |
306 } |
307 } else { |
307 } else { |
308 $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid'; |
308 $this->warning('RIFF.WAVE.BEXT.origin_date is invalid'); |
309 } |
309 } |
310 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author']; |
310 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author']; |
311 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title']; |
311 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title']; |
312 } |
312 } |
313 |
313 |
383 $SNDM_thisTagOffset += 2; |
383 $SNDM_thisTagOffset += 2; |
384 $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize); |
384 $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize); |
385 $SNDM_thisTagOffset += $SNDM_thisTagDataSize; |
385 $SNDM_thisTagOffset += $SNDM_thisTagDataSize; |
386 |
386 |
387 if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) { |
387 if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) { |
388 $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; |
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).')'); |
389 break; |
389 break; |
390 } elseif ($SNDM_thisTagSize <= 0) { |
390 } elseif ($SNDM_thisTagSize <= 0) { |
391 $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; |
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).')'); |
392 break; |
392 break; |
393 } |
393 } |
394 $SNDM_startoffset += $SNDM_thisTagSize; |
394 $SNDM_startoffset += $SNDM_thisTagSize; |
395 |
395 |
396 $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText; |
396 $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText; |
397 if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) { |
397 if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) { |
398 $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText; |
398 $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText; |
399 } else { |
399 } else { |
400 $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; |
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).')'); |
401 } |
401 } |
402 } |
402 } |
403 |
403 |
404 $tagmapping = array( |
404 $tagmapping = array( |
405 'tracktitle'=>'title', |
405 'tracktitle'=>'title', |
426 @list($numerator, $denominator) = explode('/', $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); |
427 $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000); |
428 } |
428 } |
429 if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { |
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')); |
430 $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); |
431 $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']; |
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; |
432 $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600); |
433 $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600); |
433 $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60); |
434 $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60); |
434 $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60)); |
435 $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60)); |
435 $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate']; |
436 $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate']; |
436 $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f); |
437 $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f); |
437 $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f)); |
438 $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); |
438 } |
440 } |
439 unset($parsedXML); |
441 unset($parsedXML); |
440 } |
442 } |
441 } |
443 } |
442 |
444 |
568 // LiteWave appears to incorrectly *not* pad actual output file |
570 // LiteWave appears to incorrectly *not* pad actual output file |
569 // to nearest WORD boundary so may appear to be short by one |
571 // to nearest WORD boundary so may appear to be short by one |
570 // byte, in which case - skip warning |
572 // byte, in which case - skip warning |
571 } else { |
573 } else { |
572 // Short by more than one byte, throw warning |
574 // Short by more than one byte, throw warning |
573 $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; |
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)'); |
574 $info['avdataend'] = $info['filesize']; |
576 $info['avdataend'] = $info['filesize']; |
575 } |
577 } |
576 break; |
578 break; |
577 |
579 |
578 default: |
580 default: |
579 if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) { |
581 if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) { |
580 // output file appears to be incorrectly *not* padded to nearest WORD boundary |
582 // output file appears to be incorrectly *not* padded to nearest WORD boundary |
581 // Output less severe warning |
583 // Output less severe warning |
582 $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; |
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)'); |
583 $info['avdataend'] = $info['filesize']; |
585 $info['avdataend'] = $info['filesize']; |
584 } else { |
586 } else { |
585 // Short by more than one byte, throw warning |
587 // Short by more than one byte, throw warning |
586 $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; |
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)'); |
587 $info['avdataend'] = $info['filesize']; |
589 $info['avdataend'] = $info['filesize']; |
588 } |
590 } |
589 break; |
591 break; |
590 } |
592 } |
591 } |
593 } |
592 if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) { |
594 if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) { |
593 if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { |
595 if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { |
594 $info['avdataend']--; |
596 $info['avdataend']--; |
595 $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'; |
597 $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); |
596 } |
598 } |
597 } |
599 } |
598 if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { |
600 if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { |
599 unset($thisfile_audio['bits_per_sample']); |
601 unset($thisfile_audio['bits_per_sample']); |
600 if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { |
602 if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { |
617 $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size']; |
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']; |
618 } else { |
620 } else { |
619 $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size']; |
621 $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size']; |
620 } |
622 } |
621 if ($info['avdataend'] > $info['filesize']) { |
623 if ($info['avdataend'] > $info['filesize']) { |
622 $info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)'; |
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)'); |
623 $info['avdataend'] = $info['filesize']; |
625 $info['avdataend'] = $info['filesize']; |
624 } |
626 } |
625 } |
627 } |
626 |
628 |
627 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) { |
629 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) { |
658 $thisfile_riff_raw['avih'] = array(); |
660 $thisfile_riff_raw['avih'] = array(); |
659 $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih']; |
661 $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih']; |
660 |
662 |
661 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L) |
663 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L) |
662 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) { |
664 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) { |
663 $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero'; |
665 $this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero'); |
664 return false; |
666 return false; |
665 } |
667 } |
666 |
668 |
667 $flags = array( |
669 $flags = array( |
668 'dwMaxBytesPerSec', // max. transfer rate |
670 'dwMaxBytesPerSec', // max. transfer rate |
961 if ($info['avdataend'] > $info['filesize']) { |
963 if ($info['avdataend'] > $info['filesize']) { |
962 if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) { |
964 if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) { |
963 // structures rounded to 2-byte boundary, but dumb encoders |
965 // structures rounded to 2-byte boundary, but dumb encoders |
964 // forget to pad end of file to make this actually work |
966 // forget to pad end of file to make this actually work |
965 } else { |
967 } else { |
966 $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'; |
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'); |
967 } |
969 } |
968 $info['avdataend'] = $info['filesize']; |
970 $info['avdataend'] = $info['filesize']; |
969 } |
971 } |
970 } |
972 } |
971 |
973 |
1078 |
1080 |
1079 if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) { |
1081 if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) { |
1080 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8; |
1082 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8; |
1081 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size']; |
1083 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size']; |
1082 if ($info['avdataend'] > $info['filesize']) { |
1084 if ($info['avdataend'] > $info['filesize']) { |
1083 $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'; |
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'); |
1084 } |
1086 } |
1085 } |
1087 } |
1086 |
1088 |
1087 if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) { |
1089 if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) { |
1088 // shortcut |
1090 // shortcut |
1168 } |
1170 } |
1169 unset($getid3_temp, $getid3_mpeg); |
1171 unset($getid3_temp, $getid3_mpeg); |
1170 } |
1172 } |
1171 break; |
1173 break; |
1172 |
1174 |
|
1175 case 'WEBP': |
|
1176 // https://developers.google.com/speed/webp/docs/riff_container |
|
1177 // https://tools.ietf.org/html/rfc6386 |
|
1178 // https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt |
|
1179 $info['fileformat'] = 'webp'; |
|
1180 $info['mime_type'] = 'image/webp'; |
|
1181 |
|
1182 if (!empty($thisfile_riff['WEBP']['VP8 '][0]['size'])) { |
|
1183 $old_offset = $this->ftell(); |
|
1184 $this->fseek($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8); // 4 bytes "VP8 " + 4 bytes chunk size |
|
1185 $WEBP_VP8_header = $this->fread(10); |
|
1186 $this->fseek($old_offset); |
|
1187 if (substr($WEBP_VP8_header, 3, 3) == "\x9D\x01\x2A") { |
|
1188 $thisfile_riff['WEBP']['VP8 '][0]['keyframe'] = !(getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x800000); |
|
1189 $thisfile_riff['WEBP']['VP8 '][0]['version'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x700000) >> 20; |
|
1190 $thisfile_riff['WEBP']['VP8 '][0]['show_frame'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x080000); |
|
1191 $thisfile_riff['WEBP']['VP8 '][0]['data_bytes'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x07FFFF) >> 0; |
|
1192 |
|
1193 $thisfile_riff['WEBP']['VP8 '][0]['scale_x'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0xC000) >> 14; |
|
1194 $thisfile_riff['WEBP']['VP8 '][0]['width'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0x3FFF); |
|
1195 $thisfile_riff['WEBP']['VP8 '][0]['scale_y'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0xC000) >> 14; |
|
1196 $thisfile_riff['WEBP']['VP8 '][0]['height'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0x3FFF); |
|
1197 |
|
1198 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8 '][0]['width']; |
|
1199 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8 '][0]['height']; |
|
1200 } else { |
|
1201 $this->error('Expecting 9D 01 2A at offset '.($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8 + 3).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8_header, 3, 3)).'"'); |
|
1202 } |
|
1203 |
|
1204 } |
|
1205 if (!empty($thisfile_riff['WEBP']['VP8L'][0]['size'])) { |
|
1206 $old_offset = $this->ftell(); |
|
1207 $this->fseek($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8); // 4 bytes "VP8L" + 4 bytes chunk size |
|
1208 $WEBP_VP8L_header = $this->fread(10); |
|
1209 $this->fseek($old_offset); |
|
1210 if (substr($WEBP_VP8L_header, 0, 1) == "\x2F") { |
|
1211 $width_height_flags = getid3_lib::LittleEndian2Bin(substr($WEBP_VP8L_header, 1, 4)); |
|
1212 $thisfile_riff['WEBP']['VP8L'][0]['width'] = bindec(substr($width_height_flags, 18, 14)) + 1; |
|
1213 $thisfile_riff['WEBP']['VP8L'][0]['height'] = bindec(substr($width_height_flags, 4, 14)) + 1; |
|
1214 $thisfile_riff['WEBP']['VP8L'][0]['alpha_is_used'] = (bool) bindec(substr($width_height_flags, 3, 1)); |
|
1215 $thisfile_riff['WEBP']['VP8L'][0]['version'] = bindec(substr($width_height_flags, 0, 3)); |
|
1216 |
|
1217 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8L'][0]['width']; |
|
1218 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8L'][0]['height']; |
|
1219 } else { |
|
1220 $this->error('Expecting 2F at offset '.($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8L_header, 0, 1)).'"'); |
|
1221 } |
|
1222 |
|
1223 } |
|
1224 break; |
1173 |
1225 |
1174 default: |
1226 default: |
1175 $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead'; |
1227 $this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead'); |
1176 //unset($info['fileformat']); |
1228 //unset($info['fileformat']); |
1177 } |
1229 } |
1178 |
1230 |
1179 switch ($RIFFsubtype) { |
1231 switch ($RIFFsubtype) { |
1180 case 'WAVE': |
1232 case 'WAVE': |
1183 $ID3v2_key_good = 'id3 '; |
1235 $ID3v2_key_good = 'id3 '; |
1184 $ID3v2_keys_bad = array('ID3 ', 'tag '); |
1236 $ID3v2_keys_bad = array('ID3 ', 'tag '); |
1185 foreach ($ID3v2_keys_bad as $ID3v2_key_bad) { |
1237 foreach ($ID3v2_keys_bad as $ID3v2_key_bad) { |
1186 if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) { |
1238 if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) { |
1187 $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]; |
1239 $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]; |
1188 $info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"'; |
1240 $this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"'); |
1189 } |
1241 } |
1190 } |
1242 } |
1191 |
1243 |
1192 if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) { |
1244 if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) { |
1193 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); |
1245 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); |
1507 if (empty($getid3_temp->info['error'])) { |
1559 if (empty($getid3_temp->info['error'])) { |
1508 $info['audio'] = $getid3_temp->info['audio']; |
1560 $info['audio'] = $getid3_temp->info['audio']; |
1509 $info['ac3'] = $getid3_temp->info['ac3']; |
1561 $info['ac3'] = $getid3_temp->info['ac3']; |
1510 if (!empty($getid3_temp->info['warning'])) { |
1562 if (!empty($getid3_temp->info['warning'])) { |
1511 foreach ($getid3_temp->info['warning'] as $key => $value) { |
1563 foreach ($getid3_temp->info['warning'] as $key => $value) { |
1512 $info['warning'][] = $value; |
1564 $this->warning($value); |
1513 } |
1565 } |
1514 } |
1566 } |
1515 } |
1567 } |
1516 unset($getid3_temp, $getid3_ac3); |
1568 unset($getid3_temp, $getid3_ac3); |
1517 } |
1569 } |