Make SampleSource interfaces right for TrackSelector.
The TrackSelector API will look like: TrackSelection[] selectTrack( TrackRenderer[] renderers, TrackGroup[] trackGroups); In this CL: - SampleSources return TrackGroup[], so that the result can be easily passed to the selector. - TrackStream gets its own file to sit alongside other Track* classes. - A TrackSelection object is introduced to encapsulate group and track indices. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=115251331
This commit is contained in:
parent
39a924451a
commit
6ba4fa3b51
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.PriorityHandlerThread;
|
||||
import com.google.android.exoplayer.util.TraceUtil;
|
||||
@ -75,8 +74,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
private final long minRebufferUs;
|
||||
private final List<TrackRenderer> enabledRenderers;
|
||||
private final int[] selectedTrackIndices;
|
||||
private final int[][] groupIndices;
|
||||
private final int[][][] trackIndices;
|
||||
private final TrackSelection[][] trackSelections;
|
||||
private final Format[][][] trackFormats;
|
||||
private final Handler handler;
|
||||
private final HandlerThread internalPlaybackThread;
|
||||
@ -127,9 +125,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
standaloneMediaClock = new StandaloneMediaClock();
|
||||
pendingSeekCount = new AtomicInteger();
|
||||
enabledRenderers = new ArrayList<>(renderers.length);
|
||||
groupIndices = new int[renderers.length][];
|
||||
trackSelections = new TrackSelection[renderers.length][];
|
||||
trackFormats = new Format[renderers.length][][];
|
||||
trackIndices = new int[renderers.length][][];
|
||||
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
|
||||
// not normally change to this priority" is incorrect.
|
||||
internalPlaybackThread = new PriorityHandlerThread("ExoPlayerImplInternal:Handler",
|
||||
@ -300,17 +297,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
return;
|
||||
}
|
||||
|
||||
this.durationUs = source.getDurationUs();
|
||||
this.bufferedPositionUs = source.getBufferedPositionUs();
|
||||
|
||||
boolean allRenderersEnded = true;
|
||||
boolean allRenderersReadyOrEnded = true;
|
||||
durationUs = source.getDurationUs();
|
||||
bufferedPositionUs = source.getBufferedPositionUs();
|
||||
TrackGroup[] trackGroups = source.getTrackGroups();
|
||||
|
||||
// The maximum number of tracks that one renderer can support is the total number of tracks in
|
||||
// all groups, plus possibly one adaptive track per group.
|
||||
int maxTrackCount = source.getTrackGroupCount();
|
||||
for (int groupIndex = 0; groupIndex < source.getTrackGroupCount(); groupIndex++) {
|
||||
maxTrackCount += source.getTrackGroup(groupIndex).length;
|
||||
int maxTrackCount = trackGroups.length;
|
||||
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
|
||||
maxTrackCount += trackGroups[groupIndex].length;
|
||||
}
|
||||
// Construct tracks for each renderer.
|
||||
Format[][] externalTrackFormats = new Format[renderers.length][];
|
||||
@ -318,11 +313,10 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
TrackRenderer renderer = renderers[rendererIndex];
|
||||
int rendererTrackCount = 0;
|
||||
Format[] rendererExternalTrackFormats = new Format[maxTrackCount];
|
||||
int[] rendererTrackGroups = new int[maxTrackCount];
|
||||
int[][] rendererTrackIndices = new int[maxTrackCount][];
|
||||
TrackSelection[] rendererTrackSelections = new TrackSelection[maxTrackCount];
|
||||
Format[][] rendererTrackFormats = new Format[maxTrackCount][];
|
||||
for (int groupIndex = 0; groupIndex < source.getTrackGroupCount(); groupIndex++) {
|
||||
TrackGroup trackGroup = source.getTrackGroup(groupIndex);
|
||||
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
|
||||
TrackGroup trackGroup = trackGroups[groupIndex];
|
||||
// TODO[REFACTOR]: This should check that the renderer is capable of adaptive playback, in
|
||||
// addition to checking that the group is adaptive.
|
||||
if (trackGroup.adaptive) {
|
||||
@ -331,7 +325,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
int[] adaptiveTrackIndices = new int[trackGroup.length];
|
||||
Format[] adaptiveTrackFormats = new Format[trackGroup.length];
|
||||
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
||||
Format trackFormat = source.getTrackGroup(groupIndex).getFormat(trackIndex);
|
||||
Format trackFormat = trackGroup.getFormat(trackIndex);
|
||||
if ((renderer.supportsFormat(trackFormat) & TrackRenderer.FORMAT_SUPPORT_MASK)
|
||||
== TrackRenderer.FORMAT_HANDLED) {
|
||||
adaptiveTrackIndices[adaptiveTrackIndexCount] = trackIndex;
|
||||
@ -340,9 +334,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
}
|
||||
if (adaptiveTrackIndexCount > 1) {
|
||||
// We succeeded in building an adaptive track.
|
||||
rendererTrackGroups[rendererTrackCount] = groupIndex;
|
||||
rendererTrackIndices[rendererTrackCount] =
|
||||
Arrays.copyOf(adaptiveTrackIndices, adaptiveTrackIndexCount);
|
||||
rendererTrackSelections[rendererTrackCount] = new TrackSelection(groupIndex,
|
||||
Arrays.copyOf(adaptiveTrackIndices, adaptiveTrackIndexCount));
|
||||
rendererTrackFormats[rendererTrackCount] =
|
||||
Arrays.copyOf(adaptiveTrackFormats, adaptiveTrackIndexCount);
|
||||
rendererExternalTrackFormats[rendererTrackCount++] = Format.createSampleFormat(
|
||||
@ -350,30 +343,32 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
}
|
||||
}
|
||||
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
||||
Format trackFormat = source.getTrackGroup(groupIndex).getFormat(trackIndex);
|
||||
Format trackFormat = trackGroup.getFormat(trackIndex);
|
||||
if ((renderer.supportsFormat(trackFormat) & TrackRenderer.FORMAT_SUPPORT_MASK)
|
||||
== TrackRenderer.FORMAT_HANDLED) {
|
||||
rendererTrackGroups[rendererTrackCount] = groupIndex;
|
||||
rendererTrackIndices[rendererTrackCount] = new int[] {trackIndex};
|
||||
rendererTrackSelections[rendererTrackCount] = new TrackSelection(groupIndex,
|
||||
trackIndex);
|
||||
rendererTrackFormats[rendererTrackCount] = new Format[] {trackFormat};
|
||||
rendererExternalTrackFormats[rendererTrackCount++] = trackFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
groupIndices[rendererIndex] = Arrays.copyOf(rendererTrackGroups, rendererTrackCount);
|
||||
trackIndices[rendererIndex] = Arrays.copyOf(rendererTrackIndices, rendererTrackCount);
|
||||
trackSelections[rendererIndex] = Arrays.copyOf(rendererTrackSelections, rendererTrackCount);
|
||||
trackFormats[rendererIndex] = Arrays.copyOf(rendererTrackFormats, rendererTrackCount);
|
||||
externalTrackFormats[rendererIndex] = Arrays.copyOf(rendererExternalTrackFormats,
|
||||
rendererTrackCount);
|
||||
}
|
||||
|
||||
boolean allRenderersEnded = true;
|
||||
boolean allRenderersReadyOrEnded = true;
|
||||
|
||||
// Enable renderers where appropriate.
|
||||
for (int rendererIndex = 0; rendererIndex < renderers.length; rendererIndex++) {
|
||||
TrackRenderer renderer = renderers[rendererIndex];
|
||||
int trackIndex = selectedTrackIndices[rendererIndex];
|
||||
if (0 <= trackIndex && trackIndex < trackIndices[rendererIndex].length) {
|
||||
TrackStream trackStream = source.enable(groupIndices[rendererIndex][trackIndex],
|
||||
trackIndices[rendererIndex][trackIndex], positionUs);
|
||||
if (0 <= trackIndex && trackIndex < trackSelections[rendererIndex].length) {
|
||||
TrackStream trackStream = source.enable(trackSelections[rendererIndex][trackIndex],
|
||||
positionUs);
|
||||
renderer.enable(trackFormats[rendererIndex][trackIndex], trackStream, positionUs, false);
|
||||
enabledRenderers.add(renderer);
|
||||
allRenderersEnded = allRenderersEnded && renderer.isEnded();
|
||||
@ -572,7 +567,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
resetRendererInternal(renderers[i]);
|
||||
}
|
||||
enabledRenderers.clear();
|
||||
Arrays.fill(trackIndices, null);
|
||||
Arrays.fill(trackSelections, null);
|
||||
source = null;
|
||||
}
|
||||
|
||||
@ -622,13 +617,13 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
TrackRenderer renderer = renderers[rendererIndex];
|
||||
int rendererState = renderer.getState();
|
||||
if (trackIndices[rendererIndex].length == 0) {
|
||||
if (trackSelections[rendererIndex].length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isEnabled = rendererState == TrackRenderer.STATE_ENABLED
|
||||
|| rendererState == TrackRenderer.STATE_STARTED;
|
||||
boolean shouldEnable = 0 <= trackIndex && trackIndex < trackIndices[rendererIndex].length;
|
||||
boolean shouldEnable = 0 <= trackIndex && trackIndex < trackSelections[rendererIndex].length;
|
||||
|
||||
if (isEnabled) {
|
||||
// The renderer is currently enabled. We need to disable it, so that we can either re-enable
|
||||
@ -650,8 +645,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
boolean playing = playWhenReady && state == ExoPlayer.STATE_READY;
|
||||
// Consider as joining if the renderer was previously disabled, but not when switching tracks.
|
||||
boolean joining = !isEnabled && playing;
|
||||
TrackStream trackStream = source.enable(groupIndices[rendererIndex][trackIndex],
|
||||
trackIndices[rendererIndex][trackIndex], positionUs);
|
||||
TrackStream trackStream = source.enable(trackSelections[rendererIndex][trackIndex],
|
||||
positionUs);
|
||||
renderer.enable(trackFormats[rendererIndex][trackIndex], trackStream, positionUs, joining);
|
||||
enabledRenderers.add(renderer);
|
||||
if (playing) {
|
||||
|
@ -156,13 +156,8 @@ public final class FrameworkSampleSource implements SampleSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackGroupCount() {
|
||||
return tracks.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackGroup getTrackGroup(int group) {
|
||||
return tracks[group];
|
||||
public TrackGroup[] getTrackGroups() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -171,14 +166,17 @@ public final class FrameworkSampleSource implements SampleSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackStream enable(int group, int[] track, long positionUs) {
|
||||
public TrackStream enable(TrackSelection selection, long positionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
Assertions.checkState(trackStates[group] == TRACK_STATE_DISABLED);
|
||||
Assertions.checkState(selection.tracks.length == 1);
|
||||
Assertions.checkState(selection.tracks[0] == 0);
|
||||
int track = selection.group;
|
||||
Assertions.checkState(trackStates[track] == TRACK_STATE_DISABLED);
|
||||
enabledTrackCount++;
|
||||
trackStates[group] = TRACK_STATE_ENABLED;
|
||||
extractor.selectTrack(group);
|
||||
trackStates[track] = TRACK_STATE_ENABLED;
|
||||
extractor.selectTrack(track);
|
||||
seekToUsInternal(positionUs, positionUs != 0);
|
||||
return new TrackStreamImpl(group);
|
||||
return new TrackStreamImpl(track);
|
||||
}
|
||||
|
||||
/* package */ long readReset(int track) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
import com.google.android.exoplayer.util.TraceUtil;
|
||||
|
@ -48,7 +48,7 @@ public class MultiSampleSource implements SampleSource {
|
||||
this.durationUs = C.UNKNOWN_TIME_US;
|
||||
int totalTrackGroupCount = 0;
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
totalTrackGroupCount += sources[i].getTrackGroupCount();
|
||||
totalTrackGroupCount += sources[i].getTrackGroups().length;
|
||||
if (sources[i].getDurationUs() > durationUs) {
|
||||
durationUs = sources[i].getDurationUs();
|
||||
}
|
||||
@ -56,9 +56,9 @@ public class MultiSampleSource implements SampleSource {
|
||||
tracks = new TrackGroup[totalTrackGroupCount];
|
||||
int trackGroupIndex = 0;
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
int sourceTrackGroupCount = sources[i].getTrackGroupCount();
|
||||
int sourceTrackGroupCount = sources[i].getTrackGroups().length;
|
||||
for (int j = 0; j < sourceTrackGroupCount; j++) {
|
||||
tracks[trackGroupIndex++] = sources[i].getTrackGroup(j);
|
||||
tracks[trackGroupIndex++] = sources[i].getTrackGroups()[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,19 +71,15 @@ public class MultiSampleSource implements SampleSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackGroupCount() {
|
||||
return tracks.length;
|
||||
public TrackGroup[] getTrackGroups() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackGroup getTrackGroup(int group) {
|
||||
return tracks[group];
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackStream enable(int group, int[] tracks, long positionUs) {
|
||||
Pair<Integer, Integer> sourceAndGroup = getSourceAndTrackGroupIndices(group);
|
||||
return sources[sourceAndGroup.first].enable(sourceAndGroup.second, tracks, positionUs);
|
||||
public TrackStream enable(TrackSelection selection, long positionUs) {
|
||||
Pair<Integer, Integer> sourceAndGroup = getSourceAndTrackGroupIndices(selection.group);
|
||||
return sources[sourceAndGroup.first].enable(
|
||||
new TrackSelection(sourceAndGroup.second, selection.tracks), positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -132,7 +128,7 @@ public class MultiSampleSource implements SampleSource {
|
||||
private Pair<Integer, Integer> getSourceAndTrackGroupIndices(int group) {
|
||||
int totalTrackGroupCount = 0;
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
int sourceTrackGroupCount = sources[i].getTrackGroupCount();
|
||||
int sourceTrackGroupCount = sources[i].getTrackGroups().length;
|
||||
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
||||
return Pair.create(i, group - totalTrackGroupCount);
|
||||
}
|
||||
|
@ -52,23 +52,13 @@ public interface SampleSource {
|
||||
long getDurationUs();
|
||||
|
||||
/**
|
||||
* Returns the number of track groups exposed by the source.
|
||||
* Returns the {@link TrackGroup}s exposed by the source.
|
||||
* <p>
|
||||
* This method should only be called after the source has been prepared.
|
||||
*
|
||||
* @return The number of track groups exposed by the source.
|
||||
* @return The {@link TrackGroup}s.
|
||||
*/
|
||||
public int getTrackGroupCount();
|
||||
|
||||
/**
|
||||
* Returns the {@link TrackGroup} at the specified index.
|
||||
* <p>
|
||||
* This method should only be called after the source has been prepared.
|
||||
*
|
||||
* @int group The group index.
|
||||
* @return The corresponding {@link TrackGroup}.
|
||||
*/
|
||||
public TrackGroup getTrackGroup(int group);
|
||||
public TrackGroup[] getTrackGroups();
|
||||
|
||||
/**
|
||||
* Indicates to the source that it should continue buffering data for its enabled tracks.
|
||||
@ -101,19 +91,19 @@ public interface SampleSource {
|
||||
void seekToUs(long positionUs);
|
||||
|
||||
/**
|
||||
* Enables the specified group to read the specified tracks. A {@link TrackStream} is returned
|
||||
* through which the enabled track's data can be read.
|
||||
* Enables the source to read a track defined by a {@link TrackSelection}. A {@link TrackStream}
|
||||
* is returned through which the track's data can be read.
|
||||
* <p>
|
||||
* This method should only be called after the source has been prepared, and when the specified
|
||||
* group is disabled. Note that {@code tracks.length} is only permitted to be greater than one
|
||||
* if {@link TrackGroup#adaptive} is true for the group.
|
||||
* This method should only be called after the source has been prepared, and when there are no
|
||||
* other enabled tracks with the same {@link TrackSelection#group} index. Note that
|
||||
* {@code TrackSelection#tracks} must be of length 1 unless {@link TrackGroup#adaptive} is true
|
||||
* for the group.
|
||||
*
|
||||
* @param group The group index.
|
||||
* @param tracks The track indices.
|
||||
* @param selection Defines the track.
|
||||
* @param positionUs The current playback position in microseconds.
|
||||
* @return A {@link TrackStream} from which the enabled track's data can be read.
|
||||
*/
|
||||
public TrackStream enable(int group, int[] tracks, long positionUs);
|
||||
public TrackStream enable(TrackSelection selection, long positionUs);
|
||||
|
||||
/**
|
||||
* Releases the source.
|
||||
@ -122,77 +112,4 @@ public interface SampleSource {
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* A stream of data corresponding to a single {@link SampleSource} track.
|
||||
*/
|
||||
interface TrackStream {
|
||||
|
||||
/**
|
||||
* The end of stream has been reached.
|
||||
*/
|
||||
static final int END_OF_STREAM = -1;
|
||||
/**
|
||||
* Nothing was read.
|
||||
*/
|
||||
static final int NOTHING_READ = -2;
|
||||
/**
|
||||
* A sample was read.
|
||||
*/
|
||||
static final int SAMPLE_READ = -3;
|
||||
/**
|
||||
* A format was read.
|
||||
*/
|
||||
static final int FORMAT_READ = -4;
|
||||
/**
|
||||
* Returned from {@link #readReset()} to indicate no reset is required.
|
||||
*/
|
||||
static final long NO_RESET = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* Returns whether data is available to be read.
|
||||
* <p>
|
||||
* Note: If the stream has ended then {@link #END_OF_STREAM} can always be read from
|
||||
* {@link #readData(FormatHolder, SampleHolder)}. Hence an ended stream is always ready.
|
||||
*
|
||||
* @return True if data is available to be read. False otherwise.
|
||||
*/
|
||||
boolean isReady();
|
||||
|
||||
/**
|
||||
* If there's an underlying error preventing data from being read, it's thrown by this method.
|
||||
* If not, this method does nothing.
|
||||
*
|
||||
* @throws IOException The underlying error.
|
||||
*/
|
||||
void maybeThrowError() throws IOException;
|
||||
|
||||
/**
|
||||
* Attempts to read a pending reset.
|
||||
*
|
||||
* @return If a reset was read then the position after the reset. Else {@link #NO_RESET}.
|
||||
*/
|
||||
long readReset();
|
||||
|
||||
/**
|
||||
* Attempts to read the next format or sample.
|
||||
* <p>
|
||||
* This method will always return {@link #NOTHING_READ} in the case that there's a pending
|
||||
* discontinuity to be read from {@link #readReset} for the specified track.
|
||||
*
|
||||
* @param formatHolder A {@link FormatHolder} to populate in the case of a new format.
|
||||
* @param sampleHolder A {@link SampleHolder} to populate in the case of a new sample. If the
|
||||
* caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
||||
* references a valid output buffer.
|
||||
* @return The result, which can be {@link #END_OF_STREAM}, {@link #NOTHING_READ},
|
||||
* {@link #FORMAT_READ} or {@link #SAMPLE_READ}.
|
||||
*/
|
||||
int readData(FormatHolder formatHolder, SampleHolder sampleHolder);
|
||||
|
||||
/**
|
||||
* Disables the track.
|
||||
*/
|
||||
void disable();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
import com.google.android.exoplayer.upstream.Loader;
|
||||
@ -53,7 +52,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
||||
private final Format format;
|
||||
private final long durationUs;
|
||||
private final int minLoadableRetryCount;
|
||||
private final TrackGroup tracks;
|
||||
private final TrackGroup[] trackGroups;
|
||||
|
||||
private int state;
|
||||
private byte[] sampleData;
|
||||
@ -76,7 +75,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
||||
this.format = format;
|
||||
this.durationUs = durationUs;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
tracks = new TrackGroup(format);
|
||||
trackGroups = new TrackGroup[] {new TrackGroup(format)};
|
||||
sampleData = new byte[INITIAL_SAMPLE_SIZE];
|
||||
}
|
||||
|
||||
@ -106,17 +105,12 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackGroupCount() {
|
||||
return 1;
|
||||
public TrackGroup[] getTrackGroups() {
|
||||
return trackGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackGroup getTrackGroup(int group) {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackStream enable(int group, int[] tracks, long positionUs) {
|
||||
public TrackStream enable(TrackSelection selection, long positionUs) {
|
||||
state = STATE_SEND_FORMAT;
|
||||
clearCurrentLoadableException();
|
||||
maybeStartLoading();
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
|
||||
/**
|
||||
* Defines a group of tracks exposed by a {@link SampleSource}.
|
||||
* <p>
|
||||
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
/**
|
||||
* Defines a track selection.
|
||||
*/
|
||||
public final class TrackSelection {
|
||||
|
||||
/**
|
||||
* The index of the {@link TrackGroup}.
|
||||
*/
|
||||
public final int group;
|
||||
/**
|
||||
* The indices of the individual tracks within the {@link TrackGroup}.
|
||||
*/
|
||||
public final int[] tracks;
|
||||
|
||||
/**
|
||||
* @param group The index of the {@link TrackGroup}.
|
||||
* @param tracks The indices of the individual tracks within the {@link TrackGroup}.
|
||||
*/
|
||||
public TrackSelection(int group, int... tracks) {
|
||||
this.group = group;
|
||||
this.tracks = tracks;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A stream of media data.
|
||||
*/
|
||||
public interface TrackStream {
|
||||
|
||||
/**
|
||||
* The end of stream has been reached.
|
||||
*/
|
||||
int END_OF_STREAM = -1;
|
||||
/**
|
||||
* Nothing was read.
|
||||
*/
|
||||
int NOTHING_READ = -2;
|
||||
/**
|
||||
* A sample was read.
|
||||
*/
|
||||
int SAMPLE_READ = -3;
|
||||
/**
|
||||
* A format was read.
|
||||
*/
|
||||
int FORMAT_READ = -4;
|
||||
/**
|
||||
* Returned from {@link #readReset()} to indicate no reset is required.
|
||||
*/
|
||||
long NO_RESET = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* Returns whether data is available to be read.
|
||||
* <p>
|
||||
* Note: If the stream has ended then {@link #END_OF_STREAM} can always be read from
|
||||
* {@link #readData(FormatHolder, SampleHolder)}. Hence an ended stream is always ready.
|
||||
*
|
||||
* @return True if data is available to be read. False otherwise.
|
||||
*/
|
||||
boolean isReady();
|
||||
|
||||
/**
|
||||
* If there's an underlying error preventing data from being read, it's thrown by this method.
|
||||
* If not, this method does nothing.
|
||||
*
|
||||
* @throws IOException The underlying error.
|
||||
*/
|
||||
void maybeThrowError() throws IOException;
|
||||
|
||||
/**
|
||||
* Attempts to read a pending reset.
|
||||
*
|
||||
* @return If a reset was read then the position after the reset. Else {@link #NO_RESET}.
|
||||
*/
|
||||
long readReset();
|
||||
|
||||
/**
|
||||
* Attempts to read the next format or sample.
|
||||
* <p>
|
||||
* This method will always return {@link #NOTHING_READ} in the case that there's a pending
|
||||
* discontinuity to be read from {@link #readReset} for the specified track.
|
||||
*
|
||||
* @param formatHolder A {@link FormatHolder} to populate in the case of a new format.
|
||||
* @param sampleHolder A {@link SampleHolder} to populate in the case of a new sample. If the
|
||||
* caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
||||
* references a valid output buffer.
|
||||
* @return The result, which can be {@link #END_OF_STREAM}, {@link #NOTHING_READ},
|
||||
* {@link #FORMAT_READ} or {@link #SAMPLE_READ}.
|
||||
*/
|
||||
int readData(FormatHolder formatHolder, SampleHolder sampleHolder);
|
||||
|
||||
/**
|
||||
* Disables the track.
|
||||
*/
|
||||
void disable();
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ package com.google.android.exoplayer.chunk;
|
||||
import com.google.android.exoplayer.C;
|
||||
import com.google.android.exoplayer.Format;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.TrackStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -21,8 +21,9 @@ import com.google.android.exoplayer.FormatHolder;
|
||||
import com.google.android.exoplayer.LoadControl;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.TrackGroup;
|
||||
import com.google.android.exoplayer.TrackSelection;
|
||||
import com.google.android.exoplayer.TrackStream;
|
||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
||||
import com.google.android.exoplayer.upstream.Loader;
|
||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||
@ -77,6 +78,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||
private long lastPerformedBufferOperation;
|
||||
private boolean pendingReset;
|
||||
|
||||
private TrackGroup[] trackGroups;
|
||||
private long durationUs;
|
||||
private Loader loader;
|
||||
private boolean loadingFinished;
|
||||
@ -156,6 +158,9 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||
TrackGroup trackGroup = chunkSource.getTracks();
|
||||
if (trackGroup.length > 0) {
|
||||
loader = new Loader("Loader:" + trackGroup.getFormat(0).containerMimeType);
|
||||
trackGroups = new TrackGroup[] {trackGroup};
|
||||
} else {
|
||||
trackGroups = new TrackGroup[0];
|
||||
}
|
||||
state = STATE_PREPARED;
|
||||
return true;
|
||||
@ -172,22 +177,17 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackGroupCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackGroup getTrackGroup(int group) {
|
||||
public TrackGroup[] getTrackGroups() {
|
||||
Assertions.checkState(state != STATE_IDLE);
|
||||
return chunkSource.getTracks();
|
||||
return trackGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackStream enable(int group, int[] tracks, long positionUs) {
|
||||
public TrackStream enable(TrackSelection selection, long positionUs) {
|
||||
Assertions.checkState(state == STATE_PREPARED);
|
||||
Assertions.checkState(enabledTrackCount++ == 0);
|
||||
state = STATE_ENABLED;
|
||||
chunkSource.enable(tracks);
|
||||
chunkSource.enable(selection.tracks);
|
||||
loadControl.register(this, bufferSizeContribution);
|
||||
downstreamFormat = null;
|
||||
downstreamSampleFormat = null;
|
||||
|
@ -21,6 +21,8 @@ import com.google.android.exoplayer.ParserException;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.TrackGroup;
|
||||
import com.google.android.exoplayer.TrackSelection;
|
||||
import com.google.android.exoplayer.TrackStream;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.upstream.Allocator;
|
||||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
@ -288,23 +290,21 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackGroupCount() {
|
||||
return tracks.length;
|
||||
public TrackGroup[] getTrackGroups() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackGroup getTrackGroup(int group) {
|
||||
return tracks[group];
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackStream enable(int group, int[] tracks, long positionUs) {
|
||||
public TrackStream enable(TrackSelection selection, long positionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
Assertions.checkState(!trackEnabledStates[group]);
|
||||
Assertions.checkState(selection.tracks.length == 1);
|
||||
Assertions.checkState(selection.tracks[0] == 0);
|
||||
int track = selection.group;
|
||||
Assertions.checkState(!trackEnabledStates[track]);
|
||||
enabledTrackCount++;
|
||||
trackEnabledStates[group] = true;
|
||||
pendingMediaFormat[group] = true;
|
||||
pendingResets[group] = false;
|
||||
trackEnabledStates[track] = true;
|
||||
pendingMediaFormat[track] = true;
|
||||
pendingResets[track] = false;
|
||||
if (enabledTrackCount == 1) {
|
||||
// Treat all enables in non-seekable media as being from t=0.
|
||||
positionUs = !seekMap.isSeekable() ? 0 : positionUs;
|
||||
@ -312,7 +312,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
||||
lastSeekPositionUs = positionUs;
|
||||
restartFrom(positionUs);
|
||||
}
|
||||
return new TrackStreamImpl(group);
|
||||
return new TrackStreamImpl(track);
|
||||
}
|
||||
|
||||
/* package */ void disable(int track) {
|
||||
|
@ -22,6 +22,8 @@ import com.google.android.exoplayer.LoadControl;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.TrackGroup;
|
||||
import com.google.android.exoplayer.TrackSelection;
|
||||
import com.google.android.exoplayer.TrackStream;
|
||||
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
|
||||
import com.google.android.exoplayer.chunk.Chunk;
|
||||
import com.google.android.exoplayer.chunk.ChunkOperationHolder;
|
||||
@ -179,19 +181,16 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackGroupCount() {
|
||||
return trackGroups.length;
|
||||
public TrackGroup[] getTrackGroups() {
|
||||
Assertions.checkState(prepared);
|
||||
return trackGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackGroup getTrackGroup(int group) {
|
||||
Assertions.checkState(prepared);
|
||||
return trackGroups[group];
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackStream enable(int group, int[] tracks, long positionUs) {
|
||||
public TrackStream enable(TrackSelection selection, long positionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
int group = selection.group;
|
||||
int[] tracks = selection.tracks;
|
||||
setTrackGroupEnabledState(group, true);
|
||||
downstreamSampleFormats[group] = null;
|
||||
pendingResets[group] = false;
|
||||
|
@ -19,9 +19,9 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.Format;
|
||||
import com.google.android.exoplayer.FormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.TrackStream;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.os.Handler;
|
||||
|
@ -19,9 +19,9 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.Format;
|
||||
import com.google.android.exoplayer.FormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.TrackStream;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -20,9 +20,9 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.Format;
|
||||
import com.google.android.exoplayer.FormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource.TrackStream;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.TrackStream;
|
||||
import com.google.android.exoplayer.text.Cue;
|
||||
import com.google.android.exoplayer.text.TextRenderer;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
Loading…
x
Reference in New Issue
Block a user