Skip to content

Commit b32fa8c

Browse files
rohitjoinscopybara-github
authored andcommitted
Prioritize metadata seekers over index seeking in Mp3Extractor
The `FLAG_ENABLE_INDEX_SEEKING` flag now enables index seeking only as a fallback when no other seeking metadata (like Xing, VBRI, or MLLT) is present in the MP3 file. This ensures that more efficient metadata-based seekers are used when available. Issue: #2839 PiperOrigin-RevId: 819419541
1 parent 748f01f commit b32fa8c

File tree

8 files changed

+1594
-19
lines changed

8 files changed

+1594
-19
lines changed

RELEASENOTES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@
147147
the whole file).
148148
* Add support for extracting HEIC Motion Photos. The `HeifExtractor` can
149149
now parse HEIC files containing embedded video and audio tracks.
150+
* MP3: Change `FLAG_ENABLE_INDEX_SEEKING` to prefer seeking information
151+
from metadata headers (like Xing and VBRI) when available, falling back
152+
to index-based seeking if no other seeking information is present. This
153+
improves performance for files with seeking metadata
154+
([#2839](https://github.com/androidx/media/issues/2839)).
150155
* Inspector:
151156
* Introduced a new `:media3-inspector` module to serve as the dedicated
152157
home for media inspection utilities. This module now houses a new

libraries/extractor/src/main/java/androidx/media3/extractor/mp3/Mp3Extractor.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,17 @@ public final class Mp3Extractor implements Extractor {
107107
public static final int FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS = 1 << 1;
108108

109109
/**
110-
* Flag to force index seeking, in which a time-to-byte mapping is built as the file is read.
110+
* Flag to enable index seeking, in which a time-to-byte mapping is built as the file is read. If
111+
* other seeking metadata (e.g., Xing, VBRI, MLLT) is present in the file, it will be preferred
112+
* for performance reasons. This flag allows index seeking to be used as a fallback in cases where
113+
* no other seeking metadata is available.
111114
*
112115
* <p>This seeker may require to scan a significant portion of the file to compute a seek point.
113116
* Therefore, it should only be used if one of the following is true:
114117
*
115118
* <ul>
116119
* <li>The file is small.
117-
* <li>The bitrate is variable (or it's unknown whether it's variable) and the file does not
118-
* provide precise enough seeking metadata.
120+
* <li>The bitrate is variable (or it's unknown whether it's variable).
119121
* </ul>
120122
*/
121123
public static final int FLAG_ENABLE_INDEX_SEEKING = 1 << 2;
@@ -479,27 +481,23 @@ private Seeker computeSeeker(ExtractorInput input) throws IOException {
479481
}
480482

481483
@Nullable Seeker resultSeeker = null;
482-
if ((flags & FLAG_ENABLE_INDEX_SEEKING) != 0) {
483-
long durationUs;
484-
long dataEndPosition = C.INDEX_UNSET;
485-
if (metadataSeeker != null) {
486-
durationUs = metadataSeeker.getDurationUs();
487-
dataEndPosition = metadataSeeker.getDataEndPosition();
488-
} else if (seekFrameSeeker != null) {
489-
durationUs = seekFrameSeeker.getDurationUs();
490-
dataEndPosition = seekFrameSeeker.getDataEndPosition();
491-
} else {
492-
durationUs = getId3TlenUs(metadata);
493-
}
494-
resultSeeker =
495-
new IndexSeeker(
496-
durationUs, /* dataStartPosition= */ input.getPosition(), dataEndPosition);
497-
} else if (metadataSeeker != null) {
484+
if (metadataSeeker != null) {
498485
resultSeeker = metadataSeeker;
499486
} else if (seekFrameSeeker != null) {
500487
resultSeeker = seekFrameSeeker;
501488
}
502489

490+
if ((flags & FLAG_ENABLE_INDEX_SEEKING) != 0
491+
&& (resultSeeker == null || !resultSeeker.isSeekable())) {
492+
long durationUs =
493+
resultSeeker != null ? resultSeeker.getDurationUs() : getId3TlenUs(metadata);
494+
long dataEndPosition =
495+
resultSeeker != null ? resultSeeker.getDataEndPosition() : C.INDEX_UNSET;
496+
resultSeeker =
497+
new IndexSeeker(
498+
durationUs, /* dataStartPosition= */ input.getPosition(), dataEndPosition);
499+
}
500+
503501
if (resultSeeker != null
504502
&& shouldFallbackToConstantBitrateSeeking(resultSeeker)
505503
&& resultSeeker.getDurationUs() != C.TIME_UNSET

libraries/extractor/src/test/java/androidx/media3/extractor/mp3/Mp3ExtractorTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ public void mp3SampleWithXingHeader() throws Exception {
4646
simulationConfig);
4747
}
4848

49+
@Test
50+
public void mp3SampleWithXingHeader_indexSeekingFlag_usesXingSeeker() throws Exception {
51+
ExtractorAsserts.assertBehavior(
52+
() -> new Mp3Extractor(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING),
53+
"media/mp3/bear-vbr-xing-header.mp3",
54+
/* peekLimit= */ 1300,
55+
simulationConfig);
56+
}
57+
4958
@Test
5059
public void mp3SampleWithXingHeader_noTableOfContents() throws Exception {
5160
ExtractorAsserts.assertBehavior(
@@ -55,6 +64,19 @@ public void mp3SampleWithXingHeader_noTableOfContents() throws Exception {
5564
simulationConfig);
5665
}
5766

67+
@Test
68+
public void mp3SampleWithXingHeader_noTableOfContents_indexSeeking() throws Exception {
69+
String filename = "mp3/bear-vbr-xing-header-no-toc.mp3";
70+
ExtractorAsserts.assertBehavior(
71+
() -> new Mp3Extractor(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING),
72+
"media/" + filename,
73+
/* peekLimit= */ 1300,
74+
new AssertionConfig.Builder()
75+
.setDumpFilesPrefix("extractordumps/" + filename + ".index-seeking")
76+
.build(),
77+
simulationConfig);
78+
}
79+
5880
@Test
5981
public void mp3SampleWithXingHeader_noTableOfContents_cbrSeeking() throws Exception {
6082
String filename = "mp3/bear-vbr-xing-header-no-toc.mp3";

0 commit comments

Comments
 (0)