Populate MediaFormat.KEY_DURATION in MediaExtractorCompat

Previously, `getTrackFormat()` in `MediaExtractorCompat` returned a `MediaFormat` without setting `MediaFormat.KEY_DURATION`. With this change:

- `MediaFormat.KEY_DURATION` is set based on the track's duration, if available.
- If the track duration is unset, the duration from the seek map is used as a fallback.
- When neither duration is set, `MediaFormat.KEY_DURATION` remains unset.

This ensures that `MediaFormat.KEY_DURATION` is populated when possible, enhancing duration information availability.

PiperOrigin-RevId: 691395114
This commit is contained in:
rohks 2024-10-30 06:26:17 -07:00 committed by Copybara-Service
parent 27de9f02e0
commit df07fa35d8
2 changed files with 87 additions and 1 deletions

View File

@ -417,7 +417,15 @@ public final class MediaExtractorCompat {
/** Returns the track {@link MediaFormat} at the specified {@code trackIndex}. */ /** Returns the track {@link MediaFormat} at the specified {@code trackIndex}. */
public MediaFormat getTrackFormat(int trackIndex) { public MediaFormat getTrackFormat(int trackIndex) {
return tracks.get(trackIndex).createDownstreamMediaFormat(formatHolder, noDataBuffer); MediaExtractorTrack track = tracks.get(trackIndex);
MediaFormat mediaFormat = track.createDownstreamMediaFormat(formatHolder, noDataBuffer);
long trackDurationUs = track.sampleQueue.trackDurationUs;
if (trackDurationUs != C.TIME_UNSET) {
mediaFormat.setLong(MediaFormat.KEY_DURATION, trackDurationUs);
} else if (seekMap != null && seekMap.getDurationUs() != C.TIME_UNSET) {
mediaFormat.setLong(MediaFormat.KEY_DURATION, seekMap.getDurationUs());
}
return mediaFormat;
} }
/** /**
@ -865,6 +873,7 @@ public final class MediaExtractorCompat {
private final class MediaExtractorSampleQueue extends SampleQueue { private final class MediaExtractorSampleQueue extends SampleQueue {
public final int trackId; public final int trackId;
public long trackDurationUs;
private int mainTrackIndex; private int mainTrackIndex;
private int compatibilityTrackIndex; private int compatibilityTrackIndex;
@ -873,6 +882,7 @@ public final class MediaExtractorCompat {
// values for DRM-related arguments. // values for DRM-related arguments.
super(allocator, /* drmSessionManager= */ null, /* drmEventDispatcher= */ null); super(allocator, /* drmSessionManager= */ null, /* drmEventDispatcher= */ null);
this.trackId = trackId; this.trackId = trackId;
trackDurationUs = C.TIME_UNSET;
mainTrackIndex = C.INDEX_UNSET; mainTrackIndex = C.INDEX_UNSET;
compatibilityTrackIndex = C.INDEX_UNSET; compatibilityTrackIndex = C.INDEX_UNSET;
} }
@ -887,6 +897,12 @@ public final class MediaExtractorCompat {
// SampleQueue implementation. // SampleQueue implementation.
@Override
public void durationUs(long durationUs) {
this.trackDurationUs = durationUs;
super.durationUs(durationUs);
}
@Override @Override
public Format getAdjustedUpstreamFormat(Format format) { public Format getAdjustedUpstreamFormat(Format format) {
if (getUpstreamFormat() == null) { if (getUpstreamFormat() == null) {

View File

@ -616,6 +616,76 @@ public class MediaExtractorCompatTest {
.isEqualTo(-1); .isEqualTo(-1);
} }
@Test
public void getTrackFormat_withBothTrackAndSeekMapDurationsSet_prioritizesTrackDuration()
throws IOException {
TrackOutput[] outputs = new TrackOutput[1];
fakeExtractor.addReadAction(
(input, seekPosition) -> {
outputs[0] = extractorOutput.track(/* id= */ 0, C.TRACK_TYPE_VIDEO);
extractorOutput.endTracks();
extractorOutput.seekMap(
new FakeSeekMap(
/* durationUs= */ 1_000_000L, (timeUs) -> new SeekPoints(SeekPoint.START)));
outputs[0].format(PLACEHOLDER_FORMAT_VIDEO);
outputs[0].durationUs(2_000_000L);
return Extractor.RESULT_CONTINUE;
});
mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0);
mediaExtractorCompat.selectTrack(/* trackIndex= */ 0);
MediaFormat mediaFormat = mediaExtractorCompat.getTrackFormat(/* trackIndex= */ 0);
assertThat(mediaFormat.containsKey(MediaFormat.KEY_DURATION)).isTrue();
assertThat(mediaFormat.getLong(MediaFormat.KEY_DURATION)).isEqualTo(2_000_000L);
}
@Test
public void getTrackFormat_withOnlySeekMapDurationSet_returnsSeekMapDuration()
throws IOException {
TrackOutput[] outputs = new TrackOutput[1];
fakeExtractor.addReadAction(
(input, seekPosition) -> {
outputs[0] = extractorOutput.track(/* id= */ 0, C.TRACK_TYPE_VIDEO);
extractorOutput.endTracks();
extractorOutput.seekMap(
new FakeSeekMap(
/* durationUs= */ 1_000_000L, (timeUs) -> new SeekPoints(SeekPoint.START)));
outputs[0].format(PLACEHOLDER_FORMAT_VIDEO);
return Extractor.RESULT_CONTINUE;
});
mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0);
mediaExtractorCompat.selectTrack(/* trackIndex= */ 0);
MediaFormat mediaFormat = mediaExtractorCompat.getTrackFormat(/* trackIndex= */ 0);
assertThat(mediaFormat.containsKey(MediaFormat.KEY_DURATION)).isTrue();
assertThat(mediaFormat.getLong(MediaFormat.KEY_DURATION)).isEqualTo(1_000_000L);
}
@Test
public void getTrackFormat_withNoTrackOrSeekMapDurationSet_returnsNoDuration()
throws IOException {
TrackOutput[] outputs = new TrackOutput[1];
fakeExtractor.addReadAction(
(input, seekPosition) -> {
outputs[0] = extractorOutput.track(/* id= */ 0, C.TRACK_TYPE_VIDEO);
extractorOutput.endTracks();
outputs[0].format(
new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setCodecs("avc.123")
.build());
return Extractor.RESULT_CONTINUE;
});
mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0);
mediaExtractorCompat.selectTrack(/* trackIndex= */ 0);
MediaFormat mediaFormat = mediaExtractorCompat.getTrackFormat(/* trackIndex= */ 0);
assertThat(mediaFormat.containsKey(MediaFormat.KEY_DURATION)).isFalse();
}
// Internal methods. // Internal methods.
private void assertReadSample(int trackIndex, long timeUs, int size, byte... sampleData) { private void assertReadSample(int trackIndex, long timeUs, int size, byte... sampleData) {