212 $this->warning('Audio codec = '.$thisfile_audio['codec']); |
212 $this->warning('Audio codec = '.$thisfile_audio['codec']); |
213 } |
213 } |
214 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; |
214 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; |
215 |
215 |
216 if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) |
216 if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) |
217 $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); |
217 $info['playtime_seconds'] = (float)getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_audio['bitrate']); |
218 } |
218 } |
219 |
219 |
220 $thisfile_audio['lossless'] = false; |
220 $thisfile_audio['lossless'] = false; |
221 if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { |
221 if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { |
222 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { |
222 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { |
438 // requires functions simplexml_load_string and get_object_vars |
438 // requires functions simplexml_load_string and get_object_vars |
439 if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) { |
439 if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) { |
440 $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; |
440 $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; |
441 if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { |
441 if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { |
442 @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); |
442 @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); |
443 $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000); |
443 $thisfile_riff_WAVE['iXML'][0]['master_speed'] = (int) $numerator / ($denominator ? $denominator : 1000); |
444 } |
444 } |
445 if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { |
445 if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { |
446 @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); |
446 @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); |
447 $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000); |
447 $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = (int) $numerator / ($denominator ? $denominator : 1000); |
448 } |
448 } |
449 if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { |
449 if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { |
450 $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); |
450 $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); |
451 $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 |
451 $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 |
452 $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate; |
452 $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate; |
519 } |
519 } |
520 } |
520 } |
521 |
521 |
522 if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { |
522 if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { |
523 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; |
523 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; |
524 $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); |
524 $info['playtime_seconds'] = (float)getid3_lib::SafeDiv((($info['avdataend'] - $info['avdataoffset']) * 8), $thisfile_audio['bitrate']); |
525 } |
525 } |
526 |
526 |
527 if (!empty($info['wavpack'])) { |
527 if (!empty($info['wavpack'])) { |
528 $thisfile_audio_dataformat = 'wavpack'; |
528 $thisfile_audio_dataformat = 'wavpack'; |
529 $thisfile_audio['bitrate_mode'] = 'vbr'; |
529 $thisfile_audio['bitrate_mode'] = 'vbr'; |
530 $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version']; |
530 $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version']; |
531 |
531 |
532 // Reset to the way it was - RIFF parsing will have messed this up |
532 // Reset to the way it was - RIFF parsing will have messed this up |
533 $info['avdataend'] = $Original['avdataend']; |
533 $info['avdataend'] = $Original['avdataend']; |
534 $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; |
534 $thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); |
535 |
535 |
536 $this->fseek($info['avdataoffset'] - 44); |
536 $this->fseek($info['avdataoffset'] - 44); |
537 $RIFFdata = $this->fread(44); |
537 $RIFFdata = $this->fread(44); |
538 $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8; |
538 $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8; |
539 $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44; |
539 $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44; |
630 default: |
630 default: |
631 break; |
631 break; |
632 } |
632 } |
633 } |
633 } |
634 if ($info['avdataend'] > $info['filesize']) { |
634 if ($info['avdataend'] > $info['filesize']) { |
635 switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') { |
635 switch ($thisfile_audio_dataformat) { |
636 case 'wavpack': // WavPack |
636 case 'wavpack': // WavPack |
637 case 'lpac': // LPAC |
637 case 'lpac': // LPAC |
638 case 'ofr': // OptimFROG |
638 case 'ofr': // OptimFROG |
639 case 'ofs': // OptimFROG DualStream |
639 case 'ofs': // OptimFROG DualStream |
640 // lossless compressed audio formats that keep original RIFF headers - skip warning |
640 // lossless compressed audio formats that keep original RIFF headers - skip warning |
670 if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { |
670 if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { |
671 $info['avdataend']--; |
671 $info['avdataend']--; |
672 $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); |
672 $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); |
673 } |
673 } |
674 } |
674 } |
675 if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { |
675 if ($thisfile_audio_dataformat == 'ac3') { |
676 unset($thisfile_audio['bits_per_sample']); |
676 unset($thisfile_audio['bits_per_sample']); |
677 if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { |
677 if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { |
678 $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; |
678 $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; |
679 } |
679 } |
680 } |
680 } |
779 // shortcut |
779 // shortcut |
780 $thisfile_riff_video[$streamindex] = array(); |
780 $thisfile_riff_video[$streamindex] = array(); |
781 /** @var array $thisfile_riff_video_current */ |
781 /** @var array $thisfile_riff_video_current */ |
782 $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; |
782 $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; |
783 |
783 |
784 if ($thisfile_riff_raw_avih['dwWidth'] > 0) { |
784 if ($thisfile_riff_raw_avih['dwWidth'] > 0) { // @phpstan-ignore-line |
785 $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; |
785 $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; |
786 $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; |
786 $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; |
787 } |
787 } |
788 if ($thisfile_riff_raw_avih['dwHeight'] > 0) { |
788 if ($thisfile_riff_raw_avih['dwHeight'] > 0) { // @phpstan-ignore-line |
789 $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; |
789 $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; |
790 $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; |
790 $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; |
791 } |
791 } |
792 if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { |
792 if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { // @phpstan-ignore-line |
793 $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; |
793 $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; |
794 $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; |
794 $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; |
795 } |
795 } |
796 |
796 |
797 $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3); |
797 $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3); |
806 $strhfccType = substr($strhData, 0, 4); |
806 $strhfccType = substr($strhData, 0, 4); |
807 |
807 |
808 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) { |
808 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) { |
809 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data']; |
809 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data']; |
810 |
810 |
|
811 if (!isset($thisfile_riff_raw['strf'][$strhfccType][$streamindex])) { |
|
812 $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = null; |
|
813 } |
811 // shortcut |
814 // shortcut |
812 $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex]; |
815 $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex]; |
813 |
816 |
814 switch ($strhfccType) { |
817 switch ($strhfccType) { |
815 case 'auds': |
818 case 'auds': |
1351 } |
1354 } |
1352 |
1355 |
1353 if (!isset($info['playtime_seconds'])) { |
1356 if (!isset($info['playtime_seconds'])) { |
1354 $info['playtime_seconds'] = 0; |
1357 $info['playtime_seconds'] = 0; |
1355 } |
1358 } |
1356 if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { |
1359 if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line |
1357 // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie |
1360 // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie |
1358 $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); |
1361 $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); |
1359 } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { |
1362 } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line |
1360 $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); |
1363 $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); |
1361 } |
1364 } |
1362 |
1365 |
1363 if ($info['playtime_seconds'] > 0) { |
1366 if ($info['playtime_seconds'] > 0) { |
1364 if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { |
1367 if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { |
1577 * @throws getid3_exception |
1580 * @throws getid3_exception |
1578 */ |
1581 */ |
1579 public function ParseRIFF($startoffset, $maxoffset) { |
1582 public function ParseRIFF($startoffset, $maxoffset) { |
1580 $info = &$this->getid3->info; |
1583 $info = &$this->getid3->info; |
1581 |
1584 |
1582 $RIFFchunk = false; |
1585 $RIFFchunk = array(); |
1583 $FoundAllChunksWeNeed = false; |
1586 $FoundAllChunksWeNeed = false; |
1584 $LISTchunkParent = null; |
1587 $LISTchunkParent = null; |
1585 $LISTchunkMaxOffset = null; |
1588 $LISTchunkMaxOffset = null; |
1586 $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77" |
1589 $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77" |
1587 |
1590 |
1908 unset($RIFFchunk[$chunkname][$thisindex]['offset']); |
1911 unset($RIFFchunk[$chunkname][$thisindex]['offset']); |
1909 unset($RIFFchunk[$chunkname][$thisindex]['size']); |
1912 unset($RIFFchunk[$chunkname][$thisindex]['size']); |
1910 if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { |
1913 if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { |
1911 unset($RIFFchunk[$chunkname][$thisindex]); |
1914 unset($RIFFchunk[$chunkname][$thisindex]); |
1912 } |
1915 } |
1913 if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) { |
1916 if (count($RIFFchunk[$chunkname]) === 0) { |
1914 unset($RIFFchunk[$chunkname]); |
1917 unset($RIFFchunk[$chunkname]); |
1915 } |
1918 } |
1916 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); |
1919 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); |
1917 } elseif ($chunksize < 2048) { |
1920 } elseif ($chunksize < 2048) { |
1918 // only read data in if smaller than 2kB |
1921 // only read data in if smaller than 2kB |
2029 '____'=>'comment', |
2032 '____'=>'comment', |
2030 ); |
2033 ); |
2031 foreach ($RIFFinfoKeyLookup as $key => $value) { |
2034 foreach ($RIFFinfoKeyLookup as $key => $value) { |
2032 if (isset($RIFFinfoArray[$key])) { |
2035 if (isset($RIFFinfoArray[$key])) { |
2033 foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { |
2036 foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { |
2034 if (trim($commentdata['data']) != '') { |
2037 if (!empty($commentdata['data']) && trim($commentdata['data']) != '') { |
2035 if (isset($CommentsTargetArray[$value])) { |
2038 if (isset($CommentsTargetArray[$value])) { |
2036 $CommentsTargetArray[$value][] = trim($commentdata['data']); |
2039 $CommentsTargetArray[$value][] = trim($commentdata['data']); |
2037 } else { |
2040 } else { |
2038 $CommentsTargetArray[$value] = array(trim($commentdata['data'])); |
2041 $CommentsTargetArray[$value] = array(trim($commentdata['data'])); |
2039 } |
2042 } |