Don't reuse SampleStream instance in SingleSampleMediaSource
Referential equality is going to become important for detecting whether a SampleStream has been replaced, so we need to create new instances as we do elsewhere. This also enables multiple SampleStreams to be provided for a single TrackGroup, as is also true for DASH and SmoothStreaming. It's forbidden to ask for multiple SampleStreams from a single TrackGroup currently, but we may choose to relax that at some point (and indicate whether it's allowed as a flag on each TrackGroup). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=129842336
This commit is contained in:
parent
665c9fc14c
commit
aab4e36d1a
@ -29,13 +29,14 @@ import com.google.android.exoplayer2.upstream.Loader;
|
|||||||
import com.google.android.exoplayer2.upstream.Loader.Loadable;
|
import com.google.android.exoplayer2.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads data at a given {@link Uri} as a single sample belonging to a single {@link MediaPeriod}.
|
* Loads data at a given {@link Uri} as a single sample belonging to a single {@link MediaPeriod}.
|
||||||
*/
|
*/
|
||||||
public final class SingleSampleMediaSource implements MediaPeriod, MediaSource, SampleStream,
|
public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
||||||
Loader.Callback<SingleSampleMediaSource.SourceLoadable> {
|
Loader.Callback<SingleSampleMediaSource.SourceLoadable> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,26 +64,21 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
|||||||
*/
|
*/
|
||||||
private static final int INITIAL_SAMPLE_SIZE = 1;
|
private static final int INITIAL_SAMPLE_SIZE = 1;
|
||||||
|
|
||||||
private static final int STREAM_STATE_SEND_FORMAT = 0;
|
|
||||||
private static final int STREAM_STATE_SEND_SAMPLE = 1;
|
|
||||||
private static final int STREAM_STATE_END_OF_STREAM = 2;
|
|
||||||
|
|
||||||
private final Uri uri;
|
private final Uri uri;
|
||||||
private final DataSource.Factory dataSourceFactory;
|
private final DataSource.Factory dataSourceFactory;
|
||||||
private final Format format;
|
|
||||||
private final long durationUs;
|
private final long durationUs;
|
||||||
private final int minLoadableRetryCount;
|
private final int minLoadableRetryCount;
|
||||||
private final TrackGroupArray tracks;
|
private final TrackGroupArray tracks;
|
||||||
private final Handler eventHandler;
|
private final Handler eventHandler;
|
||||||
private final EventListener eventListener;
|
private final EventListener eventListener;
|
||||||
private final int eventSourceId;
|
private final int eventSourceId;
|
||||||
|
private final ArrayList<SampleStreamImpl> sampleStreams;
|
||||||
|
/* package */ final Format format;
|
||||||
|
|
||||||
private Loader loader;
|
/* package */ Loader loader;
|
||||||
private boolean loadingFinished;
|
/* package */ boolean loadingFinished;
|
||||||
|
/* package */ byte[] sampleData;
|
||||||
private int streamState;
|
/* package */ int sampleSize;
|
||||||
private byte[] sampleData;
|
|
||||||
private int sampleSize;
|
|
||||||
|
|
||||||
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
||||||
long durationUs) {
|
long durationUs) {
|
||||||
@ -107,7 +103,7 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
|||||||
this.eventSourceId = eventSourceId;
|
this.eventSourceId = eventSourceId;
|
||||||
tracks = new TrackGroupArray(new TrackGroup(format));
|
tracks = new TrackGroupArray(new TrackGroup(format));
|
||||||
sampleData = new byte[INITIAL_SAMPLE_SIZE];
|
sampleData = new byte[INITIAL_SAMPLE_SIZE];
|
||||||
streamState = STREAM_STATE_SEND_FORMAT;
|
sampleStreams = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaSource implementation.
|
// MediaSource implementation.
|
||||||
@ -165,13 +161,15 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
|||||||
@Override
|
@Override
|
||||||
public SampleStream[] selectTracks(List<SampleStream> oldStreams,
|
public SampleStream[] selectTracks(List<SampleStream> oldStreams,
|
||||||
List<TrackSelection> newSelections, long positionUs) {
|
List<TrackSelection> newSelections, long positionUs) {
|
||||||
Assertions.checkState(oldStreams.size() <= 1);
|
for (int i = 0; i < oldStreams.size(); i++) {
|
||||||
Assertions.checkState(newSelections.size() <= 1);
|
SampleStreamImpl oldStream = (SampleStreamImpl) oldStreams.get(i);
|
||||||
// Select new tracks.
|
sampleStreams.remove(oldStream);
|
||||||
|
}
|
||||||
SampleStream[] newStreams = new SampleStream[newSelections.size()];
|
SampleStream[] newStreams = new SampleStream[newSelections.size()];
|
||||||
if (!newSelections.isEmpty()) {
|
for (int i = 0; i < newStreams.length; i++) {
|
||||||
newStreams[0] = this;
|
SampleStreamImpl newStream = new SampleStreamImpl();
|
||||||
streamState = STREAM_STATE_SEND_FORMAT;
|
sampleStreams.add(newStream);
|
||||||
|
newStreams[i] = newStream;
|
||||||
}
|
}
|
||||||
return newStreams;
|
return newStreams;
|
||||||
}
|
}
|
||||||
@ -186,6 +184,11 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readDiscontinuity() {
|
||||||
|
return C.UNSET_TIME_US;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNextLoadPositionUs() {
|
public long getNextLoadPositionUs() {
|
||||||
return loadingFinished || loader.isLoading() ? C.END_OF_SOURCE_US : 0;
|
return loadingFinished || loader.isLoading() ? C.END_OF_SOURCE_US : 0;
|
||||||
@ -198,8 +201,8 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long seekToUs(long positionUs) {
|
public long seekToUs(long positionUs) {
|
||||||
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
for (int i = 0; i < sampleStreams.size(); i++) {
|
||||||
streamState = STREAM_STATE_SEND_SAMPLE;
|
sampleStreams.get(i).seekToUs(positionUs);
|
||||||
}
|
}
|
||||||
return positionUs;
|
return positionUs;
|
||||||
}
|
}
|
||||||
@ -211,57 +214,11 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
|||||||
loader = null;
|
loader = null;
|
||||||
}
|
}
|
||||||
loadingFinished = false;
|
loadingFinished = false;
|
||||||
streamState = STREAM_STATE_SEND_FORMAT;
|
sampleStreams.clear();
|
||||||
sampleData = null;
|
sampleData = null;
|
||||||
sampleSize = 0;
|
sampleSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SampleStream implementation.
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isReady() {
|
|
||||||
return loadingFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void maybeThrowError() throws IOException {
|
|
||||||
loader.maybeThrowError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long readDiscontinuity() {
|
|
||||||
return C.UNSET_TIME_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
|
||||||
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
|
||||||
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
|
||||||
return C.RESULT_BUFFER_READ;
|
|
||||||
} else if (streamState == STREAM_STATE_SEND_FORMAT) {
|
|
||||||
formatHolder.format = format;
|
|
||||||
streamState = STREAM_STATE_SEND_SAMPLE;
|
|
||||||
return C.RESULT_FORMAT_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assertions.checkState(streamState == STREAM_STATE_SEND_SAMPLE);
|
|
||||||
if (!loadingFinished) {
|
|
||||||
return C.RESULT_NOTHING_READ;
|
|
||||||
} else {
|
|
||||||
buffer.timeUs = 0;
|
|
||||||
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
|
||||||
buffer.ensureSpaceForWrite(sampleSize);
|
|
||||||
buffer.data.put(sampleData, 0, sampleSize);
|
|
||||||
streamState = STREAM_STATE_END_OF_STREAM;
|
|
||||||
return C.RESULT_BUFFER_READ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void skipToKeyframeBefore(long timeUs) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loader.Callback implementation.
|
// Loader.Callback implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -298,6 +255,61 @@ public final class SingleSampleMediaSource implements MediaPeriod, MediaSource,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class SampleStreamImpl implements SampleStream {
|
||||||
|
|
||||||
|
private static final int STREAM_STATE_SEND_FORMAT = 0;
|
||||||
|
private static final int STREAM_STATE_SEND_SAMPLE = 1;
|
||||||
|
private static final int STREAM_STATE_END_OF_STREAM = 2;
|
||||||
|
|
||||||
|
private int streamState;
|
||||||
|
|
||||||
|
public void seekToUs(long positionUs) {
|
||||||
|
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
||||||
|
streamState = STREAM_STATE_SEND_SAMPLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return loadingFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void maybeThrowError() throws IOException {
|
||||||
|
loader.maybeThrowError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
|
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
||||||
|
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
|
return C.RESULT_BUFFER_READ;
|
||||||
|
} else if (streamState == STREAM_STATE_SEND_FORMAT) {
|
||||||
|
formatHolder.format = format;
|
||||||
|
streamState = STREAM_STATE_SEND_SAMPLE;
|
||||||
|
return C.RESULT_FORMAT_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assertions.checkState(streamState == STREAM_STATE_SEND_SAMPLE);
|
||||||
|
if (!loadingFinished) {
|
||||||
|
return C.RESULT_NOTHING_READ;
|
||||||
|
} else {
|
||||||
|
buffer.timeUs = 0;
|
||||||
|
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||||
|
buffer.ensureSpaceForWrite(sampleSize);
|
||||||
|
buffer.data.put(sampleData, 0, sampleSize);
|
||||||
|
streamState = STREAM_STATE_END_OF_STREAM;
|
||||||
|
return C.RESULT_BUFFER_READ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skipToKeyframeBefore(long timeUs) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* package */ static final class SourceLoadable implements Loadable {
|
/* package */ static final class SourceLoadable implements Loadable {
|
||||||
|
|
||||||
private final Uri uri;
|
private final Uri uri;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user