Skip to content

Commit 245e623

Browse files
toniheiSheenaChhabra
authored andcommitted
Set correct track id when skipping empty tracks in Mp4Extractor
The track id must be the index in the list of published tracks as it's used as such elsewhere. This is currently not true if we skip an empty track as all subsequent tracks get a wrong or even invalid id. #minor-release PiperOrigin-RevId: 604929178 (cherry picked from commit 5f9c96a)
1 parent 74d0f93 commit 245e623

File tree

8 files changed

+1441
-3
lines changed

8 files changed

+1441
-3
lines changed

‎libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,8 @@ private void processMoovAtom(ContainerAtom moov) throws ParserException {
585585
isQuickTime,
586586
/* modifyTrackFunction= */ track -> track);
587587

588-
int trackCount = trackSampleTables.size();
589-
for (int i = 0; i < trackCount; i++) {
588+
int trackIndex = 0;
589+
for (int i = 0; i < trackSampleTables.size(); i++) {
590590
TrackSampleTable trackSampleTable = trackSampleTables.get(i);
591591
if (trackSampleTable.sampleCount == 0) {
592592
continue;
@@ -596,7 +596,7 @@ private void processMoovAtom(ContainerAtom moov) throws ParserException {
596596
track.durationUs != C.TIME_UNSET ? track.durationUs : trackSampleTable.durationUs;
597597
durationUs = max(durationUs, trackDurationUs);
598598
Mp4Track mp4Track =
599-
new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type));
599+
new Mp4Track(track, trackSampleTable, extractorOutput.track(trackIndex++, track.type));
600600

601601
int maxInputSize;
602602
if (MimeTypes.AUDIO_TRUEHD.equals(track.format.sampleMimeType)) {

‎libraries/extractor/src/test/java/androidx/media3/extractor/mp4/Mp4ExtractorTest.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,19 @@
1616
package androidx.media3.extractor.mp4;
1717

1818
import static androidx.media3.extractor.mp4.FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
19+
import static com.google.common.truth.Truth.assertThat;
1920

21+
import androidx.media3.extractor.Extractor;
22+
import androidx.media3.extractor.PositionHolder;
2023
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
2124
import androidx.media3.extractor.text.SubtitleParser;
2225
import androidx.media3.test.utils.ExtractorAsserts;
26+
import androidx.media3.test.utils.FakeExtractorInput;
27+
import androidx.media3.test.utils.FakeExtractorOutput;
28+
import androidx.media3.test.utils.FakeTrackOutput;
29+
import androidx.media3.test.utils.TestUtil;
30+
import androidx.test.core.app.ApplicationProvider;
31+
import com.google.common.collect.ImmutableList;
2332
import java.util.ArrayList;
2433
import java.util.List;
2534
import org.junit.Test;
@@ -226,6 +235,51 @@ public void mp4SampleWithEditList() throws Exception {
226235
simulationConfig);
227236
}
228237

238+
@Test
239+
public void mp4SampleWithEmptyTrack() throws Exception {
240+
ExtractorAsserts.assertBehavior(
241+
getExtractorFactory(subtitlesParsedDuringExtraction),
242+
"media/mp4/sample_empty_track.mp4",
243+
simulationConfig);
244+
}
245+
246+
@Test
247+
public void getSeekPoints_withEmptyTracks_returnsValidInformation() throws Exception {
248+
Mp4Extractor extractor =
249+
(Mp4Extractor) getExtractorFactory(subtitlesParsedDuringExtraction).create();
250+
FakeExtractorInput input =
251+
new FakeExtractorInput.Builder()
252+
.setData(
253+
TestUtil.getByteArray(
254+
ApplicationProvider.getApplicationContext(),
255+
"media/mp4/sample_empty_track.mp4"))
256+
.build();
257+
FakeExtractorOutput output =
258+
new FakeExtractorOutput(
259+
(id, type) -> new FakeTrackOutput(/* deduplicateConsecutiveFormats= */ true));
260+
PositionHolder seekPositionHolder = new PositionHolder();
261+
extractor.init(output);
262+
int readResult = Extractor.RESULT_CONTINUE;
263+
while (readResult != Extractor.RESULT_END_OF_INPUT) {
264+
readResult = extractor.read(input, seekPositionHolder);
265+
if (readResult == Extractor.RESULT_SEEK) {
266+
long seekPosition = seekPositionHolder.position;
267+
input.setPosition((int) seekPosition);
268+
}
269+
}
270+
ImmutableList.Builder<Long> trackSeekTimesUs = ImmutableList.builder();
271+
long testPositionUs = output.seekMap.getDurationUs() / 2;
272+
273+
for (int i = 0; i < output.numberOfTracks; i++) {
274+
int trackId = output.trackOutputs.keyAt(i);
275+
trackSeekTimesUs.add(extractor.getSeekPoints(testPositionUs, trackId).first.timeUs);
276+
}
277+
long extractorSeekTimeUs = extractor.getSeekPoints(testPositionUs).first.timeUs;
278+
279+
assertThat(output.numberOfTracks).isEqualTo(2);
280+
assertThat(extractorSeekTimeUs).isIn(trackSeekTimesUs.build());
281+
}
282+
229283
private static ExtractorAsserts.ExtractorFactory getExtractorFactory(
230284
boolean subtitlesParsedDuringExtraction) {
231285
SubtitleParser.Factory subtitleParserFactory;

0 commit comments

Comments
 (0)