mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Add possibility to update ExtractorOutput duration
PiperOrigin-RevId: 292912511
This commit is contained in:
parent
de3877237b
commit
ed88f4f1dd
7 changed files with 50 additions and 22 deletions
|
|
@ -653,8 +653,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekMap(SeekMap seekMap) {
|
public void seekMap(SeekMap seekMap) {
|
||||||
this.seekMap = icyHeaders == null ? seekMap : new Unseekable(/* durationUs */ C.TIME_UNSET);
|
handler.post(() -> setSeekMap(seekMap));
|
||||||
handler.post(maybeFinishPrepareRunnable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Icy metadata. Called by the loading thread.
|
// Icy metadata. Called by the loading thread.
|
||||||
|
|
@ -691,6 +690,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
return trackOutput;
|
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() {
|
private void maybeFinishPrepare() {
|
||||||
SeekMap seekMap = this.seekMap;
|
SeekMap seekMap = this.seekMap;
|
||||||
if (released || preparedState != null || !sampleQueuesBuilt || seekMap == null) {
|
if (released || preparedState != null || !sampleQueuesBuilt || seekMap == null) {
|
||||||
|
|
@ -705,7 +718,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
int trackCount = sampleQueues.length;
|
int trackCount = sampleQueues.length;
|
||||||
TrackGroup[] trackArray = new TrackGroup[trackCount];
|
TrackGroup[] trackArray = new TrackGroup[trackCount];
|
||||||
boolean[] trackIsAudioVideoFlags = new boolean[trackCount];
|
boolean[] trackIsAudioVideoFlags = new boolean[trackCount];
|
||||||
durationUs = seekMap.getDurationUs();
|
|
||||||
for (int i = 0; i < trackCount; i++) {
|
for (int i = 0; i < trackCount; i++) {
|
||||||
Format trackFormat = sampleQueues[i].getUpstreamFormat();
|
Format trackFormat = sampleQueues[i].getUpstreamFormat();
|
||||||
String mimeType = trackFormat.sampleMimeType;
|
String mimeType = trackFormat.sampleMimeType;
|
||||||
|
|
@ -731,11 +743,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
}
|
}
|
||||||
trackArray[i] = new TrackGroup(trackFormat);
|
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 =
|
preparedState =
|
||||||
new PreparedState(seekMap, new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
|
new PreparedState(seekMap, new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
|
||||||
listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable(), isLive);
|
|
||||||
Assertions.checkNotNull(callback).onPrepared(this);
|
Assertions.checkNotNull(callback).onPrepared(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,12 @@ import com.google.android.exoplayer2.util.Util;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
/* package */ static final long MIN_TIME_BETWEEN_POINTS_US = C.MICROS_PER_SECOND / 10;
|
/* package */ static final long MIN_TIME_BETWEEN_POINTS_US = C.MICROS_PER_SECOND / 10;
|
||||||
|
|
||||||
private final long durationUs;
|
|
||||||
private final long dataEndPosition;
|
private final long dataEndPosition;
|
||||||
private final LongArray timesUs;
|
private final LongArray timesUs;
|
||||||
private final LongArray positions;
|
private final LongArray positions;
|
||||||
|
|
||||||
|
private long durationUs;
|
||||||
|
|
||||||
public IndexSeeker(long durationUs, long dataStartPosition, long dataEndPosition) {
|
public IndexSeeker(long durationUs, long dataStartPosition, long dataEndPosition) {
|
||||||
this.durationUs = durationUs;
|
this.durationUs = durationUs;
|
||||||
this.dataEndPosition = dataEndPosition;
|
this.dataEndPosition = dataEndPosition;
|
||||||
|
|
@ -104,4 +105,8 @@ import com.google.android.exoplayer2.util.Util;
|
||||||
long lastIndexedTimeUs = timesUs.get(timesUs.size() - 1);
|
long lastIndexedTimeUs = timesUs.get(timesUs.size() - 1);
|
||||||
return timeUs - lastIndexedTimeUs < MIN_TIME_BETWEEN_POINTS_US;
|
return timeUs - lastIndexedTimeUs < MIN_TIME_BETWEEN_POINTS_US;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* package */ void setDurationUs(long durationUs) {
|
||||||
|
this.durationUs = durationUs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,31 @@ public final class Mp3Extractor implements Extractor {
|
||||||
public int read(ExtractorInput input, PositionHolder seekPosition)
|
public int read(ExtractorInput input, PositionHolder seekPosition)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
assertInitialized();
|
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) {
|
if (synchronizedHeaderData == 0) {
|
||||||
try {
|
try {
|
||||||
synchronize(input, false);
|
synchronize(input, false);
|
||||||
|
|
@ -254,17 +279,6 @@ public final class Mp3Extractor implements Extractor {
|
||||||
return readSample(input);
|
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"})
|
@RequiresNonNull({"currentTrackOutput", "realTrackOutput", "seeker"})
|
||||||
private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException {
|
private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException {
|
||||||
if (sampleBytesRemaining == 0) {
|
if (sampleBytesRemaining == 0) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = UNSET TIME
|
duration = 2808000
|
||||||
getPosition(0) = [[timeUs=0, position=224]]
|
getPosition(0) = [[timeUs=0, position=224]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = UNSET TIME
|
duration = 2808000
|
||||||
getPosition(0) = [[timeUs=0, position=224]]
|
getPosition(0) = [[timeUs=0, position=224]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = UNSET TIME
|
duration = 2808000
|
||||||
getPosition(0) = [[timeUs=0, position=224]]
|
getPosition(0) = [[timeUs=0, position=224]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = UNSET TIME
|
duration = 2808000
|
||||||
getPosition(0) = [[timeUs=0, position=224]]
|
getPosition(0) = [[timeUs=0, position=224]]
|
||||||
numberOfTracks = 1
|
numberOfTracks = 1
|
||||||
track 0:
|
track 0:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue