313 } |
313 } |
314 if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) { |
314 if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) { |
315 $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min']; |
315 $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min']; |
316 } |
316 } |
317 |
317 |
|
318 if (isset($thisfile_mpeg_audio['bitrate']) && $thisfile_mpeg_audio['bitrate'] === 'free') { |
|
319 $encoder_options .= ' --freeformat'; |
|
320 } |
|
321 |
318 if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) { |
322 if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) { |
319 $encoder_options .= ' --nogap'; |
323 $encoder_options .= ' --nogap'; |
320 } |
324 } |
321 |
325 |
322 if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) { |
326 if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) { |
748 |
752 |
749 // extra 11 chars are not part of version string when LAMEtag present |
753 // extra 11 chars are not part of version string when LAMEtag present |
750 unset($thisfile_mpeg_audio_lame['long_version']); |
754 unset($thisfile_mpeg_audio_lame['long_version']); |
751 |
755 |
752 // It the LAME tag was only introduced in LAME v3.90 |
756 // It the LAME tag was only introduced in LAME v3.90 |
753 // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933 |
757 // https://wiki.hydrogenaud.io/index.php/LAME#VBR_header_and_LAME_tag |
|
758 // https://hydrogenaud.io/index.php?topic=9933 |
754 |
759 |
755 // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html |
760 // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html |
756 // are assuming a 'Xing' identifier offset of 0x24, which is the case for |
761 // are assuming a 'Xing' identifier offset of 0x24, which is the case for |
757 // MPEG-1 non-mono, but not for other combinations |
762 // MPEG-1 non-mono, but not for other combinations |
758 $LAMEtagOffsetContant = $VBRidOffset - 0x24; |
763 $LAMEtagOffsetContant = $VBRidOffset - 0x24; |
784 |
789 |
785 // byte $A6 Lowpass filter value |
790 // byte $A6 Lowpass filter value |
786 $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100; |
791 $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100; |
787 |
792 |
788 // bytes $A7-$AE Replay Gain |
793 // bytes $A7-$AE Replay Gain |
789 // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html |
794 // https://web.archive.org/web/20021015212753/http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html |
790 // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude" |
795 // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude" |
791 if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') { |
796 if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') { |
792 // LAME 3.94a16 and later - 9.23 fixed point |
797 // LAME 3.94a16 and later - 9.23 fixed point |
793 // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375 |
798 // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375 |
794 $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608); |
799 $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608); |
912 // bytes $BE-$BF CRC-16 of Info Tag |
917 // bytes $BE-$BF CRC-16 of Info Tag |
913 $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2)); |
918 $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2)); |
914 |
919 |
915 |
920 |
916 // LAME CBR |
921 // LAME CBR |
917 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { |
922 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1 && $thisfile_mpeg_audio['bitrate'] !== 'free') { |
918 |
923 |
919 $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; |
924 $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; |
920 $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']); |
925 $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']); |
921 $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; |
926 $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; |
922 //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) { |
927 //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) { |
1167 return true; |
1172 return true; |
1168 } |
1173 } |
1169 |
1174 |
1170 $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); |
1175 $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); |
1171 if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { |
1176 if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { |
|
1177 /** @phpstan-ignore-next-line */ |
1172 getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]); |
1178 getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]); |
1173 if ($ScanAsCBR) { |
1179 if ($ScanAsCBR) { |
1174 // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header |
1180 // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header |
1175 if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) { |
1181 if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) { |
1176 return false; |
1182 return false; |
1372 $Distribution['layer'][$LongMPEGlayerLookup[$head4]] = isset($Distribution['layer'][$LongMPEGlayerLookup[$head4]]) ? ++$Distribution['layer'][$LongMPEGlayerLookup[$head4]] : 1; |
1378 $Distribution['layer'][$LongMPEGlayerLookup[$head4]] = isset($Distribution['layer'][$LongMPEGlayerLookup[$head4]]) ? ++$Distribution['layer'][$LongMPEGlayerLookup[$head4]] : 1; |
1373 $Distribution['version'][$LongMPEGversionLookup[$head4]] = isset($Distribution['version'][$LongMPEGversionLookup[$head4]]) ? ++$Distribution['version'][$LongMPEGversionLookup[$head4]] : 1; |
1379 $Distribution['version'][$LongMPEGversionLookup[$head4]] = isset($Distribution['version'][$LongMPEGversionLookup[$head4]]) ? ++$Distribution['version'][$LongMPEGversionLookup[$head4]] : 1; |
1374 $Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] = isset($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]) ? ++$Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] : 1; |
1380 $Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] = isset($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]) ? ++$Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] : 1; |
1375 $Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] = isset($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]) ? ++$Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] : 1; |
1381 $Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] = isset($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]) ? ++$Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] : 1; |
1376 if (++$frames_scanned >= $max_frames_scan) { |
1382 if (++$frames_scanned >= $max_frames_scan) { |
1377 $pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']); |
1383 $pct_data_scanned = getid3_lib::SafeDiv($this->ftell() - $info['avdataoffset'], $info['avdataend'] - $info['avdataoffset']); |
1378 $this->warning('too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'); |
1384 $this->warning('too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'); |
1379 foreach ($Distribution as $key1 => $value1) { |
1385 foreach ($Distribution as $key1 => $value1) { |
1380 foreach ($value1 as $key2 => $value2) { |
1386 foreach ($value1 as $key2 => $value2) { |
1381 $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned); |
1387 $Distribution[$key1][$key2] = $pct_data_scanned ? round($value2 / $pct_data_scanned) : 1; |
1382 } |
1388 } |
1383 } |
1389 } |
1384 break; |
1390 break; |
1385 } |
1391 } |
1386 continue; |
1392 continue; |
1467 $SynchSeekOffset = 0; |
1473 $SynchSeekOffset = 0; |
1468 $SyncSeekAttempts = 0; |
1474 $SyncSeekAttempts = 0; |
1469 $SyncSeekAttemptsMax = 1000; |
1475 $SyncSeekAttemptsMax = 1000; |
1470 $FirstFrameThisfileInfo = null; |
1476 $FirstFrameThisfileInfo = null; |
1471 while ($SynchSeekOffset < $sync_seek_buffer_size) { |
1477 while ($SynchSeekOffset < $sync_seek_buffer_size) { |
1472 if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { |
1478 if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !$this->feof()) { |
1473 |
1479 |
1474 if ($SynchSeekOffset > $sync_seek_buffer_size) { |
1480 if ($SynchSeekOffset > $sync_seek_buffer_size) { |
1475 // if a synch's not found within the first 128k bytes, then give up |
1481 // if a synch's not found within the first 128k bytes, then give up |
1476 $this->error('Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB'); |
1482 $this->error('Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB'); |
1477 if (isset($info['audio']['bitrate'])) { |
1483 if (isset($info['audio']['bitrate'])) { |
1479 } |
1485 } |
1480 if (isset($info['mpeg']['audio'])) { |
1486 if (isset($info['mpeg']['audio'])) { |
1481 unset($info['mpeg']['audio']); |
1487 unset($info['mpeg']['audio']); |
1482 } |
1488 } |
1483 if (empty($info['mpeg'])) { |
1489 if (empty($info['mpeg'])) { |
1484 unset($info['mpeg']); |
|
1485 } |
|
1486 return false; |
|
1487 |
|
1488 } elseif (feof($this->getid3->fp)) { |
|
1489 |
|
1490 $this->error('Could not find valid MPEG audio synch before end of file'); |
|
1491 if (isset($info['audio']['bitrate'])) { |
|
1492 unset($info['audio']['bitrate']); |
|
1493 } |
|
1494 if (isset($info['mpeg']['audio'])) { |
|
1495 unset($info['mpeg']['audio']); |
|
1496 } |
|
1497 if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) { |
|
1498 unset($info['mpeg']); |
1490 unset($info['mpeg']); |
1499 } |
1491 } |
1500 return false; |
1492 return false; |
1501 } |
1493 } |
1502 } |
1494 } |
1644 getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]); |
1636 getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]); |
1645 $synchstartoffset += $dummy['mpeg']['audio']['framelength']; |
1637 $synchstartoffset += $dummy['mpeg']['audio']['framelength']; |
1646 } |
1638 } |
1647 $frames_scanned++; |
1639 $frames_scanned++; |
1648 if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) { |
1640 if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) { |
1649 $this_pct_scanned = ($this->ftell() - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']); |
1641 $this_pct_scanned = getid3_lib::SafeDiv($this->ftell() - $scan_start_offset[$current_segment], $info['avdataend'] - $info['avdataoffset']); |
1650 if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) { |
1642 if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) { |
1651 // file likely contains < $max_frames_scan, just scan as one segment |
1643 // file likely contains < $max_frames_scan, just scan as one segment |
1652 $max_scan_segments = 1; |
1644 $max_scan_segments = 1; |
1653 $frames_scan_per_segment = $max_frames_scan; |
1645 $frames_scan_per_segment = $max_frames_scan; |
1654 } else { |
1646 } else { |