diff --git a/src/wave/wave-demuxer.ts b/src/wave/wave-demuxer.ts index 4b6f111..ea7f44e 100644 --- a/src/wave/wave-demuxer.ts +++ b/src/wave/wave-demuxer.ts @@ -15,7 +15,7 @@ import { DEFAULT_TRACK_DISPOSITION, MetadataTags } from '../metadata'; import { assert, UNDETERMINED_LANGUAGE } from '../misc'; import { EncodedPacket, PLACEHOLDER_DATA } from '../packet'; import { readAscii, readBytes, Reader, readU16, readU32, readU64 } from '../reader'; -import { parseId3V2Tag, readId3V2Header } from '../id3'; +import { ID3_V2_HEADER_SIZE, parseId3V2Tag, readId3V2Header } from '../id3'; export enum WaveFormat { PCM = 0x0001, @@ -286,10 +286,15 @@ export class WaveDemuxer extends Demuxer { const id3V2Header = readId3V2Header(slice); if (id3V2Header) { - // Extract the content portion (skip the 10-byte header) - const contentSlice = slice.slice(startPos + 10, id3V2Header.size); + // Clamp to the available data in case the ID3 header claims more than the WAV chunk provides + // https://github.com/Vanilagy/mediabunny/issues/300 + const availableSize = size - ID3_V2_HEADER_SIZE; + id3V2Header.size = Math.min(id3V2Header.size, availableSize); - parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + if (id3V2Header.size > 0) { + const contentSlice = slice.slice(startPos + ID3_V2_HEADER_SIZE, id3V2Header.size); + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + } } } diff --git a/test/node/read-wav.test.ts b/test/node/read-wav.test.ts new file mode 100644 index 0000000..87f6f79 --- /dev/null +++ b/test/node/read-wav.test.ts @@ -0,0 +1,24 @@ +import { test } from 'vitest'; +import path from 'node:path'; +import { ALL_FORMATS, EncodedPacketSink, Input, FilePathSource } from '../../src/index.js'; + +const __dirname = new URL('.', import.meta.url).pathname; + +test('Should handle WAV file with oversized ID3 chunk', async () => { + const filePath = path.join(__dirname, '..', 'public/oversized-id3.wav'); + using input = new Input({ + source: new FilePathSource(filePath), + formats: ALL_FORMATS, + }); + + const track = await input.getPrimaryAudioTrack(); + if (!track) { + throw new Error('No audio track found'); + } + + const sink = new EncodedPacketSink(track); + + for await (const packet of sink.packets()) { + void packet; + } +}); diff --git a/test/public/oversized-id3.wav b/test/public/oversized-id3.wav new file mode 100644 index 0000000..6996ea3 Binary files /dev/null and b/test/public/oversized-id3.wav differ