From 6ba4fa3b51b972cc8dd7af2c3688f2a45896807a Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 22 Feb 2016 11:32:40 -0800 Subject: [PATCH] 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 --- .../exoplayer/ExoPlayerImplInternal.java | 63 +++++------ .../exoplayer/FrameworkSampleSource.java | 22 ++-- .../exoplayer/MediaCodecTrackRenderer.java | 1 - .../MediaCodecVideoTrackRenderer.java | 1 - .../android/exoplayer/MultiSampleSource.java | 24 ++-- .../android/exoplayer/SampleSource.java | 105 ++---------------- .../exoplayer/SampleSourceTrackRenderer.java | 1 - .../android/exoplayer/SingleSampleSource.java | 16 +-- .../google/android/exoplayer/TrackGroup.java | 2 - .../android/exoplayer/TrackRenderer.java | 1 - .../android/exoplayer/TrackSelection.java | 41 +++++++ .../google/android/exoplayer/TrackStream.java | 91 +++++++++++++++ .../BaseChunkSampleSourceEventListener.java | 2 +- .../exoplayer/chunk/ChunkSampleSource.java | 20 ++-- .../extractor/ExtractorSampleSource.java | 26 ++--- .../exoplayer/hls/HlsSampleSource.java | 17 ++- .../metadata/MetadataTrackRenderer.java | 2 +- .../exoplayer/text/TextTrackRenderer.java | 2 +- .../text/eia608/Eia608TrackRenderer.java | 2 +- 19 files changed, 232 insertions(+), 207 deletions(-) create mode 100644 library/src/main/java/com/google/android/exoplayer/TrackSelection.java create mode 100644 library/src/main/java/com/google/android/exoplayer/TrackStream.java diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java index 70f143f047..dcc3ba9e18 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java @@ -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 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) { diff --git a/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java b/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java index 0913da122d..b4fb2117b3 100644 --- a/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java @@ -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) { diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java index db04a10b22..4c223408f8 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java index 4cf48592f0..2d47682938 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/MultiSampleSource.java b/library/src/main/java/com/google/android/exoplayer/MultiSampleSource.java index 32d54dddc3..87ce02538e 100644 --- a/library/src/main/java/com/google/android/exoplayer/MultiSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/MultiSampleSource.java @@ -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 sourceAndGroup = getSourceAndTrackGroupIndices(group); - return sources[sourceAndGroup.first].enable(sourceAndGroup.second, tracks, positionUs); + public TrackStream enable(TrackSelection selection, long positionUs) { + Pair 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 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); } diff --git a/library/src/main/java/com/google/android/exoplayer/SampleSource.java b/library/src/main/java/com/google/android/exoplayer/SampleSource.java index 4ad8847504..6478ce3af9 100644 --- a/library/src/main/java/com/google/android/exoplayer/SampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/SampleSource.java @@ -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. *

* 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. - *

- * 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. *

- * 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. - *

- * 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. - *

- * 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(); - - } - } diff --git a/library/src/main/java/com/google/android/exoplayer/SampleSourceTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/SampleSourceTrackRenderer.java index efd86750b0..bca5f2654a 100644 --- a/library/src/main/java/com/google/android/exoplayer/SampleSourceTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/SampleSourceTrackRenderer.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/SingleSampleSource.java b/library/src/main/java/com/google/android/exoplayer/SingleSampleSource.java index b9dbac64eb..e46d0163c8 100644 --- a/library/src/main/java/com/google/android/exoplayer/SingleSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/SingleSampleSource.java @@ -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(); diff --git a/library/src/main/java/com/google/android/exoplayer/TrackGroup.java b/library/src/main/java/com/google/android/exoplayer/TrackGroup.java index 917e090f9c..24b2646dcf 100644 --- a/library/src/main/java/com/google/android/exoplayer/TrackGroup.java +++ b/library/src/main/java/com/google/android/exoplayer/TrackGroup.java @@ -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}. *

diff --git a/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java index 0ca153b1b3..0a0c9856bb 100644 --- a/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/TrackSelection.java b/library/src/main/java/com/google/android/exoplayer/TrackSelection.java new file mode 100644 index 0000000000..213b13b3e0 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer/TrackSelection.java @@ -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; + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer/TrackStream.java b/library/src/main/java/com/google/android/exoplayer/TrackStream.java new file mode 100644 index 0000000000..452171226d --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer/TrackStream.java @@ -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. + *

+ * 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. + *

+ * 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(); + +} diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/BaseChunkSampleSourceEventListener.java b/library/src/main/java/com/google/android/exoplayer/chunk/BaseChunkSampleSourceEventListener.java index 1f9619be5c..8d6e5dd965 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/BaseChunkSampleSourceEventListener.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/BaseChunkSampleSourceEventListener.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java index 5dd8504d9a..ed55e4ea2f 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java b/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java index a980da9b42..5e576650b2 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java @@ -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) { diff --git a/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java b/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java index 8f402fdc7d..a9ab4af273 100644 --- a/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/metadata/MetadataTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/metadata/MetadataTrackRenderer.java index 60bcf1cef0..43481649c5 100644 --- a/library/src/main/java/com/google/android/exoplayer/metadata/MetadataTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/metadata/MetadataTrackRenderer.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java index 484b0dd3dd..344c4cdcd3 100644 --- a/library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/text/eia608/Eia608TrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/text/eia608/Eia608TrackRenderer.java index cb0ce8d3a0..7b384581d8 100644 --- a/library/src/main/java/com/google/android/exoplayer/text/eia608/Eia608TrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/text/eia608/Eia608TrackRenderer.java @@ -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;