diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ad682a22d2a..c9b409d0db2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -19,6 +19,8 @@ * Add support for composition-level audio effects. * Track Selection: * Extractors: + * Fix issue where padding was not skipped when reading odd-sized chunks + from WAV files ([#1117](https://github.com/androidx/media/pull/1117)). * Audio: * Allow renderer recovery by disabling offload if audio track fails to initialize in offload mode. diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/wav/WavHeaderReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/wav/WavHeaderReader.java index 53cf0f902a3..4db508135ff 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/wav/WavHeaderReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/wav/WavHeaderReader.java @@ -172,6 +172,12 @@ private static ChunkHeader skipToChunk( while (chunkHeader.id != chunkId) { Log.w(TAG, "Ignoring unknown WAV chunk: " + chunkHeader.id); long bytesToSkip = ChunkHeader.SIZE_IN_BYTES + chunkHeader.size; + // According to the RIFF specification, if a chunk's body size is odd, it's followed by a + // padding byte of value 0. This ensures each chunk occupies an even number of bytes in the + // file. The padding byte isn't included in the size field. + if (chunkHeader.size % 2 != 0) { + bytesToSkip++; // padding present if size is odd, skip it. + } if (bytesToSkip > Integer.MAX_VALUE) { throw ParserException.createForUnsupportedContainerFeature( "Chunk is too large (~2GB+) to skip; id: " + chunkHeader.id); diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/wav/WavExtractorTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/wav/WavExtractorTest.java index f0a2da1204c..a7a92c82d04 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/wav/WavExtractorTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/wav/WavExtractorTest.java @@ -48,6 +48,15 @@ public void sample_withTrailingBytes_extractsSameData() throws Exception { simulationConfig); } + @Test + public void sample_withOddMetadataChunkSize_extractsSameData() throws Exception { + ExtractorAsserts.assertBehavior( + WavExtractor::new, + "media/wav/sample_with_odd_metadata_chunk_size.wav", + new AssertionConfig.Builder().setDumpFilesPrefix("extractordumps/wav/sample.wav").build(), + simulationConfig); + } + @Test public void sample_imaAdpcm() throws Exception { ExtractorAsserts.assertBehavior( diff --git a/libraries/test_data/src/test/assets/media/wav/sample_with_odd_metadata_chunk_size.wav b/libraries/test_data/src/test/assets/media/wav/sample_with_odd_metadata_chunk_size.wav new file mode 100644 index 00000000000..eb48ba3e3fd Binary files /dev/null and b/libraries/test_data/src/test/assets/media/wav/sample_with_odd_metadata_chunk_size.wav differ