mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 05:44:58 +00:00
LibAudio: Accurately skip MP3 frames using the actual header size
Prevously, the header size was used to calculate the `slot_count` field of `MP3::Header`, but `build_seek_table()` just used the maximum size of the header instead, causing it not to seek far enough, and in cases where a possible sync code occurred two bytes before the next frame, it would read that possible sync code as if it was a real frame. It would then either reject it due to bad field values, or could possibly skip over the next real frame due to a larger calculated frame size in the bogus frame. By fixing this issue, we now properly calculate the duration of MP3 files where these fake sync codes occur. In the case of the raw file for this podcast: https://changelog.com/podcast/554 the duration goes from 1:21:57 to 1:22:47, which is the real duration according to the player user interface.
This commit is contained in:
parent
5b8895fff0
commit
e087d35cd8
2 changed files with 7 additions and 3 deletions
|
@ -192,7 +192,7 @@ MaybeLoaderError MP3LoaderPlugin::build_seek_table()
|
|||
frame_count++;
|
||||
sample_count += MP3::frame_size;
|
||||
|
||||
TRY(m_stream->seek(error_or_header.value().frame_size - 6, SeekMode::FromCurrentPosition));
|
||||
TRY(m_stream->seek(error_or_header.value().frame_size - error_or_header.value().header_size, SeekMode::FromCurrentPosition));
|
||||
|
||||
// TODO: This is just here to clear the bitstream buffer.
|
||||
// Bitstream should have a method to sync its state to the underlying stream.
|
||||
|
@ -223,10 +223,13 @@ ErrorOr<MP3::Header, LoaderError> MP3LoaderPlugin::read_header()
|
|||
header.copyright_bit = TRY(m_bitstream->read_bit());
|
||||
header.original_bit = TRY(m_bitstream->read_bit());
|
||||
header.emphasis = static_cast<MP3::Emphasis>(TRY(m_bitstream->read_bits(2)));
|
||||
if (!header.protection_bit)
|
||||
header.header_size = 4;
|
||||
if (!header.protection_bit) {
|
||||
header.crc16 = TRY(m_bitstream->read_bits<u16>(16));
|
||||
header.header_size += 2;
|
||||
}
|
||||
header.frame_size = 144 * header.bitrate * 1000 / header.samplerate + header.padding_bit;
|
||||
header.slot_count = header.frame_size - ((header.channel_count() == 2 ? 32 : 17) + (header.protection_bit ? 0 : 2) + 4);
|
||||
header.slot_count = header.frame_size - ((header.channel_count() == 2 ? 32 : 17) + header.header_size);
|
||||
return header;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ struct Header {
|
|||
bool original_bit { false };
|
||||
Emphasis emphasis { Emphasis::None };
|
||||
u16 crc16 { 0 };
|
||||
size_t header_size { 0 };
|
||||
size_t frame_size { 0 };
|
||||
size_t slot_count { 0 };
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue