Skip to content

Commit b6b2826

Browse files
icbakermarcbaechinger
authored andcommitted
Permit duplicate Opus headers
This reinstates the permissive behaviour removed by fe7e5b8 Test file created by opening bear.opus in a hex editor and naively duplicating the two header packets, starting at (and including) the first `OggS` in the file and ending just before the third `OggS`. #minor-release Issue: #10038 PiperOrigin-RevId: 452015662
1 parent 5460ac8 commit b6b2826

8 files changed

Lines changed: 3445 additions & 4 deletions

File tree

library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package com.google.android.exoplayer2.extractor.ogg;
1717

18-
import static com.google.android.exoplayer2.util.Assertions.checkState;
1918
import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
2019

2120
import androidx.annotation.Nullable;
@@ -39,10 +38,20 @@
3938
'O', 'p', 'u', 's', 'T', 'a', 'g', 's'
4039
};
4140

41+
private boolean firstCommentHeaderSeen;
42+
4243
public static boolean verifyBitstreamType(ParsableByteArray data) {
4344
return peekPacketStartsWith(data, OPUS_ID_HEADER_SIGNATURE);
4445
}
4546

47+
@Override
48+
protected void reset(boolean headerData) {
49+
super.reset(headerData);
50+
if (headerData) {
51+
firstCommentHeaderSeen = false;
52+
}
53+
}
54+
4655
@Override
4756
protected long preparePayload(ParsableByteArray packet) {
4857
return convertTimeToGranule(getPacketDurationUs(packet.getData()));
@@ -57,9 +66,15 @@ protected boolean readHeaders(ParsableByteArray packet, long position, SetupData
5766
int channelCount = OpusUtil.getChannelCount(headerBytes);
5867
List<byte[]> initializationData = OpusUtil.buildInitializationData(headerBytes);
5968

60-
// The ID header must come at the start of the file:
61-
// https://datatracker.ietf.org/doc/html/rfc7845#section-3
62-
checkState(setupData.format == null);
69+
if (setupData.format != null) {
70+
// setupData.format being non-null indicates we've already seen an ID header. Multiple ID
71+
// headers are not permitted by the Opus spec [1], but have been observed in real files [2],
72+
// so we just ignore all subsequent ones.
73+
// [1] https://datatracker.ietf.org/doc/html/rfc7845#section-3 and
74+
// https://datatracker.ietf.org/doc/html/rfc7845#section-5
75+
// [2] https://github.com/google/ExoPlayer/issues/10038
76+
return true;
77+
}
6378
setupData.format =
6479
new Format.Builder()
6580
.setSampleMimeType(MimeTypes.AUDIO_OPUS)
@@ -72,6 +87,15 @@ protected boolean readHeaders(ParsableByteArray packet, long position, SetupData
7287
// The comment header must come immediately after the ID header, so the format will already
7388
// be populated: https://datatracker.ietf.org/doc/html/rfc7845#section-3
7489
checkStateNotNull(setupData.format);
90+
if (firstCommentHeaderSeen) {
91+
// Multiple comment headers are not permitted by the Opus spec [1], but have been observed
92+
// in real files [2], so we just ignore all subsequent ones.
93+
// [1] https://datatracker.ietf.org/doc/html/rfc7845#section-3 and
94+
// https://datatracker.ietf.org/doc/html/rfc7845#section-5
95+
// [2] https://github.com/google/ExoPlayer/issues/10038
96+
return true;
97+
}
98+
firstCommentHeaderSeen = true;
7599
packet.skipBytes(OPUS_COMMENT_HEADER_SIGNATURE.length);
76100
VorbisUtil.CommentHeader commentHeader =
77101
VorbisUtil.readVorbisCommentHeader(

library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorParameterizedTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ public void opus() throws Exception {
4343
ExtractorAsserts.assertBehavior(OggExtractor::new, "media/ogg/bear.opus", simulationConfig);
4444
}
4545

46+
// https://github.com/google/ExoPlayer/issues/10038
47+
@Test
48+
public void opus_duplicateHeader() throws Exception {
49+
ExtractorAsserts.assertBehavior(
50+
OggExtractor::new, "media/ogg/bear_duplicate_header.opus", simulationConfig);
51+
}
52+
4653
@Test
4754
public void flac() throws Exception {
4855
ExtractorAsserts.assertBehavior(OggExtractor::new, "media/ogg/bear_flac.ogg", simulationConfig);

0 commit comments

Comments
 (0)