Add possibility to update ExtractorOutput duration

PiperOrigin-RevId: 292912511
This commit is contained in:
kimvde 2020-02-03 15:09:09 +00:00 committed by kim-vde
parent de3877237b
commit ed88f4f1dd
7 changed files with 50 additions and 22 deletions

View file

@ -653,8 +653,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
public void seekMap(SeekMap seekMap) {
this.seekMap = icyHeaders == null ? seekMap : new Unseekable(/* durationUs */ C.TIME_UNSET);
handler.post(maybeFinishPrepareRunnable);
handler.post(() -> setSeekMap(seekMap));
}
// Icy metadata. Called by the loading thread.
@ -691,6 +690,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return trackOutput;
}
private void setSeekMap(SeekMap seekMap) {
this.seekMap = icyHeaders == null ? seekMap : new Unseekable(/* durationUs */ C.TIME_UNSET);
if (preparedState == null) {
maybeFinishPrepare();
} else {
preparedState =
new PreparedState(seekMap, preparedState.tracks, preparedState.trackIsAudioVideoFlags);
}
durationUs = seekMap.getDurationUs();
isLive = length == C.LENGTH_UNSET && seekMap.getDurationUs() == C.TIME_UNSET;
dataType = isLive ? C.DATA_TYPE_MEDIA_PROGRESSIVE_LIVE : C.DATA_TYPE_MEDIA;
listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable(), isLive);
}
private void maybeFinishPrepare() {
SeekMap seekMap = this.seekMap;
if (released || preparedState != null || !sampleQueuesBuilt || seekMap == null) {
@ -705,7 +718,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int trackCount = sampleQueues.length;
TrackGroup[] trackArray = new TrackGroup[trackCount];
boolean[] trackIsAudioVideoFlags = new boolean[trackCount];
durationUs = seekMap.getDurationUs();
for (int i = 0; i < trackCount; i++) {
Format trackFormat = sampleQueues[i].getUpstreamFormat();
String mimeType = trackFormat.sampleMimeType;
@ -731,11 +743,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
trackArray[i] = new TrackGroup(trackFormat);
}
isLive = length == C.LENGTH_UNSET && seekMap.getDurationUs() == C.TIME_UNSET;
dataType = isLive ? C.DATA_TYPE_MEDIA_PROGRESSIVE_LIVE : C.DATA_TYPE_MEDIA;
preparedState =
new PreparedState(seekMap, new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable(), isLive);
Assertions.checkNotNull(callback).onPrepared(this);
}

View file

@ -27,11 +27,12 @@ import com.google.android.exoplayer2.util.Util;
@VisibleForTesting
/* package */ static final long MIN_TIME_BETWEEN_POINTS_US = C.MICROS_PER_SECOND / 10;
private final long durationUs;
private final long dataEndPosition;
private final LongArray timesUs;
private final LongArray positions;
private long durationUs;
public IndexSeeker(long durationUs, long dataStartPosition, long dataEndPosition) {
this.durationUs = durationUs;
this.dataEndPosition = dataEndPosition;
@ -104,4 +105,8 @@ import com.google.android.exoplayer2.util.Util;
long lastIndexedTimeUs = timesUs.get(timesUs.size() - 1);
return timeUs - lastIndexedTimeUs < MIN_TIME_BETWEEN_POINTS_US;
}
/* package */ void setDurationUs(long durationUs) {
this.durationUs = durationUs;
}
}

View file

@ -216,6 +216,31 @@ public final class Mp3Extractor implements Extractor {
public int read(ExtractorInput input, PositionHolder seekPosition)
throws IOException, InterruptedException {
assertInitialized();
int readResult = readInternal(input);
if (readResult == RESULT_END_OF_INPUT && seeker instanceof IndexSeeker) {
// Duration is exact when index seeker is used.
long durationUs = computeTimeUs(samplesRead);
if (seeker.getDurationUs() != durationUs) {
((IndexSeeker) seeker).setDurationUs(durationUs);
extractorOutput.seekMap(seeker);
}
}
return readResult;
}
/**
* Disables the extractor from being able to seek through the media.
*
* <p>Please note that this needs to be called before {@link #read}.
*/
public void disableSeeking() {
disableSeeking = true;
}
// Internal methods.
@RequiresNonNull({"extractorOutput", "currentTrackOutput", "realTrackOutput"})
private int readInternal(ExtractorInput input) throws IOException, InterruptedException {
if (synchronizedHeaderData == 0) {
try {
synchronize(input, false);
@ -254,17 +279,6 @@ public final class Mp3Extractor implements Extractor {
return readSample(input);
}
/**
* Disables the extractor from being able to seek through the media.
*
* <p>Please note that this needs to be called before {@link #read}.
*/
public void disableSeeking() {
disableSeeking = true;
}
// Internal methods.
@RequiresNonNull({"currentTrackOutput", "realTrackOutput", "seeker"})
private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException {
if (sampleBytesRemaining == 0) {

View file

@ -1,6 +1,6 @@
seekMap:
isSeekable = true
duration = UNSET TIME
duration = 2808000
getPosition(0) = [[timeUs=0, position=224]]
numberOfTracks = 1
track 0:

View file

@ -1,6 +1,6 @@
seekMap:
isSeekable = true
duration = UNSET TIME
duration = 2808000
getPosition(0) = [[timeUs=0, position=224]]
numberOfTracks = 1
track 0:

View file

@ -1,6 +1,6 @@
seekMap:
isSeekable = true
duration = UNSET TIME
duration = 2808000
getPosition(0) = [[timeUs=0, position=224]]
numberOfTracks = 1
track 0:

View file

@ -1,6 +1,6 @@
seekMap:
isSeekable = true
duration = UNSET TIME
duration = 2808000
getPosition(0) = [[timeUs=0, position=224]]
numberOfTracks = 1
track 0: