diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer/ext/opus/LibopusAudioTrackRenderer.java b/extensions/opus/src/main/java/com/google/android/exoplayer/ext/opus/LibopusAudioTrackRenderer.java index 51b27cf7b1..bfdbcf50b0 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer/ext/opus/LibopusAudioTrackRenderer.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer/ext/opus/LibopusAudioTrackRenderer.java @@ -131,8 +131,9 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); seekToInternal(positionUs); } diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java index 71e59bafd7..1ea758b6a1 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java @@ -349,8 +349,9 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer { } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); seekToInternal(); } diff --git a/library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java index 1a1305898e..fd36939093 100644 --- a/library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java @@ -18,15 +18,25 @@ package com.google.android.exoplayer; /** * A {@link TrackRenderer} that does nothing. *

- * This renderer returns {@link TrackRenderer#STATE_IGNORE} from {@link #doPrepare(long)} in order - * to request that it should be ignored. {@link IllegalStateException} is thrown from all methods - * that are documented to indicate that they should not be invoked unless the renderer is prepared. + * This renderer returns 0 from {@link #getTrackCount()} in order to request that it should be + * ignored. {@link IllegalStateException} is thrown from all other methods documented to indicate + * that they should not be invoked unless the renderer is prepared. */ public final class DummyTrackRenderer extends TrackRenderer { @Override - protected int doPrepare(long positionUs) { - return STATE_IGNORE; + protected boolean doPrepare(long positionUs) throws ExoPlaybackException { + return true; + } + + @Override + protected int getTrackCount() { + return 0; + } + + @Override + protected TrackInfo getTrackInfo(int track) { + throw new IllegalStateException(); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java index 6729bfddd8..2823cc7f31 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java @@ -34,8 +34,8 @@ import java.util.concurrent.CopyOnWriteArraySet; private final Handler eventHandler; private final ExoPlayerImplInternal internalPlayer; private final CopyOnWriteArraySet listeners; - private final boolean[] rendererHasMediaFlags; - private final boolean[] rendererEnabledFlags; + private final TrackInfo[][] trackInfos; + private final int[] selectedTrackIndices; private boolean playWhenReady; private int playbackState; @@ -58,18 +58,15 @@ import java.util.concurrent.CopyOnWriteArraySet; this.playWhenReady = false; this.playbackState = STATE_IDLE; this.listeners = new CopyOnWriteArraySet<>(); - this.rendererHasMediaFlags = new boolean[rendererCount]; - this.rendererEnabledFlags = new boolean[rendererCount]; - for (int i = 0; i < rendererEnabledFlags.length; i++) { - rendererEnabledFlags[i] = true; - } + this.trackInfos = new TrackInfo[rendererCount][]; + this.selectedTrackIndices = new int[rendererCount]; eventHandler = new Handler() { @Override public void handleMessage(Message msg) { ExoPlayerImpl.this.handleEvent(msg); } }; - internalPlayer = new ExoPlayerImplInternal(eventHandler, playWhenReady, rendererEnabledFlags, + internalPlayer = new ExoPlayerImplInternal(eventHandler, playWhenReady, selectedTrackIndices, minBufferMs, minRebufferMs); } @@ -95,26 +92,49 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public void prepare(TrackRenderer... renderers) { - Arrays.fill(rendererHasMediaFlags, false); + Arrays.fill(trackInfos, null); internalPlayer.prepare(renderers); } @Override + // TODO: Deprecate in ExoPlayer. public boolean getRendererHasMedia(int rendererIndex) { - return rendererHasMediaFlags[rendererIndex]; + return getRendererTrackCount(rendererIndex) > 0; } @Override + // TODO: Deprecate in ExoPlayer. public void setRendererEnabled(int rendererIndex, boolean enabled) { - if (rendererEnabledFlags[rendererIndex] != enabled) { - rendererEnabledFlags[rendererIndex] = enabled; - internalPlayer.setRendererEnabled(rendererIndex, enabled); + setRendererSelectedTrack(rendererIndex, enabled ? 0 : -1); + } + + @Override + // TODO: Deprecate in ExoPlayer. + public boolean getRendererEnabled(int rendererIndex) { + return getRendererSelectedTrack(rendererIndex) == 0; + } + + // TODO: Expose in ExoPlayer. + public int getRendererTrackCount(int rendererIndex) { + return trackInfos[rendererIndex] != null ? trackInfos[rendererIndex].length : 0; + } + + // TODO: Expose in ExoPlayer. + public TrackInfo getRendererTrackInfo(int rendererIndex, int trackIndex) { + return trackInfos[rendererIndex][trackIndex]; + } + + // TODO: Expose in ExoPlayer. + public void setRendererSelectedTrack(int rendererIndex, int trackIndex) { + if (selectedTrackIndices[rendererIndex] != trackIndex) { + selectedTrackIndices[rendererIndex] = trackIndex; + internalPlayer.setRendererSelectedTrack(rendererIndex, trackIndex); } } - @Override - public boolean getRendererEnabled(int rendererIndex) { - return rendererEnabledFlags[rendererIndex]; + // TODO: Expose in ExoPlayer. + public int getRendererSelectedTrack(int rendererIndex) { + return selectedTrackIndices[rendererIndex]; } @Override @@ -192,9 +212,8 @@ import java.util.concurrent.CopyOnWriteArraySet; /* package */ void handleEvent(Message msg) { switch (msg.what) { case ExoPlayerImplInternal.MSG_PREPARED: { - boolean[] rendererHasMediaFlags = (boolean[]) msg.obj; - System.arraycopy(rendererHasMediaFlags, 0, this.rendererHasMediaFlags, 0, - rendererHasMediaFlags.length); + TrackInfo[][] trackInfos = (TrackInfo[][]) msg.obj; + System.arraycopy(trackInfos, 0, this.trackInfos, 0, trackInfos.length); playbackState = msg.arg1; for (Listener listener : listeners) { listener.onPlayerStateChanged(playWhenReady, playbackState); 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 8e7690e04c..b87a16b165 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java @@ -31,6 +31,7 @@ import android.util.Log; import android.util.Pair; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -54,7 +55,7 @@ import java.util.List; private static final int MSG_RELEASE = 5; private static final int MSG_SEEK_TO = 6; private static final int MSG_DO_SOME_WORK = 7; - private static final int MSG_SET_RENDERER_ENABLED = 8; + private static final int MSG_SET_RENDERER_SELECTED_TRACK = 8; private static final int MSG_CUSTOM = 9; private static final int PREPARE_INTERVAL_MS = 10; @@ -65,11 +66,12 @@ import java.util.List; private final HandlerThread internalPlaybackThread; private final Handler eventHandler; private final StandaloneMediaClock standaloneMediaClock; - private final boolean[] rendererEnabledFlags; + private final List enabledRenderers; + private final TrackInfo[][] trackInfos; + private final int[] selectedTrackIndices; private final long minBufferUs; private final long minRebufferUs; - private final List enabledRenderers; private TrackRenderer[] renderers; private TrackRenderer rendererMediaClockSource; private MediaClock rendererMediaClock; @@ -87,22 +89,19 @@ import java.util.List; private volatile long bufferedPositionUs; public ExoPlayerImplInternal(Handler eventHandler, boolean playWhenReady, - boolean[] rendererEnabledFlags, int minBufferMs, int minRebufferMs) { + int[] selectedTrackIndices, int minBufferMs, int minRebufferMs) { this.eventHandler = eventHandler; this.playWhenReady = playWhenReady; - this.rendererEnabledFlags = new boolean[rendererEnabledFlags.length]; this.minBufferUs = minBufferMs * 1000L; this.minRebufferUs = minRebufferMs * 1000L; - for (int i = 0; i < rendererEnabledFlags.length; i++) { - this.rendererEnabledFlags[i] = rendererEnabledFlags[i]; - } - + this.selectedTrackIndices = Arrays.copyOf(selectedTrackIndices, selectedTrackIndices.length); this.state = ExoPlayer.STATE_IDLE; this.durationUs = TrackRenderer.UNKNOWN_TIME_US; this.bufferedPositionUs = TrackRenderer.UNKNOWN_TIME_US; standaloneMediaClock = new StandaloneMediaClock(); - enabledRenderers = new ArrayList<>(rendererEnabledFlags.length); + enabledRenderers = new ArrayList<>(selectedTrackIndices.length); + trackInfos = new TrackInfo[selectedTrackIndices.length][]; // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can // not normally change to this priority" is incorrect. internalPlaybackThread = new PriorityHandlerThread(getClass().getSimpleName() + ":Handler", @@ -146,8 +145,9 @@ import java.util.List; handler.sendEmptyMessage(MSG_STOP); } - public void setRendererEnabled(int index, boolean enabled) { - handler.obtainMessage(MSG_SET_RENDERER_ENABLED, index, enabled ? 1 : 0).sendToTarget(); + public void setRendererSelectedTrack(int rendererIndex, int trackIndex) { + handler.obtainMessage(MSG_SET_RENDERER_SELECTED_TRACK, rendererIndex, trackIndex) + .sendToTarget(); } public void sendMessage(ExoPlayerComponent target, int messageType, Object message) { @@ -223,8 +223,8 @@ import java.util.List; sendMessageInternal(msg.arg1, msg.obj); return true; } - case MSG_SET_RENDERER_ENABLED: { - setRendererEnabledInternal(msg.arg1, msg.arg2 != 0); + case MSG_SET_RENDERER_SELECTED_TRACK: { + setRendererSelectedTrackInternal(msg.arg1, msg.arg2); return true; } default: @@ -253,6 +253,7 @@ import java.util.List; private void prepareInternal(TrackRenderer[] renderers) throws ExoPlaybackException { resetInternal(); this.renderers = renderers; + Arrays.fill(trackInfos, null); for (int i = 0; i < renderers.length; i++) { MediaClock mediaClock = renderers[i].getMediaClock(); if (mediaClock != null) { @@ -288,11 +289,15 @@ import java.util.List; long durationUs = 0; boolean allRenderersEnded = true; boolean allRenderersReadyOrEnded = true; - boolean[] rendererHasMediaFlags = new boolean[renderers.length]; for (int rendererIndex = 0; rendererIndex < renderers.length; rendererIndex++) { TrackRenderer renderer = renderers[rendererIndex]; - rendererHasMediaFlags[rendererIndex] = renderer.getState() == TrackRenderer.STATE_PREPARED; - if (rendererHasMediaFlags[rendererIndex]) { + int rendererTrackCount = renderer.getTrackCount(); + TrackInfo[] rendererTrackInfos = new TrackInfo[rendererTrackCount]; + for (int trackIndex = 0; trackIndex < rendererTrackCount; trackIndex++) { + rendererTrackInfos[trackIndex] = renderer.getTrackInfo(trackIndex); + } + trackInfos[rendererIndex] = rendererTrackInfos; + if (rendererTrackCount > 0) { if (durationUs == TrackRenderer.UNKNOWN_TIME_US) { // We've already encountered a track for which the duration is unknown, so the media // duration is unknown regardless of the duration of this track. @@ -306,8 +311,9 @@ import java.util.List; durationUs = Math.max(durationUs, trackDurationUs); } } - if (rendererEnabledFlags[rendererIndex]) { - renderer.enable(positionUs, false); + int trackIndex = selectedTrackIndices[rendererIndex]; + if (0 <= trackIndex && trackIndex < rendererTrackInfos.length) { + renderer.enable(trackIndex, positionUs, false); enabledRenderers.add(renderer); allRenderersEnded = allRenderersEnded && renderer.isEnded(); allRenderersReadyOrEnded = allRenderersReadyOrEnded && rendererReadyOrEnded(renderer); @@ -325,8 +331,8 @@ import java.util.List; } // Fire an event indicating that the player has been prepared, passing the initial state and - // renderer media flags. - eventHandler.obtainMessage(MSG_PREPARED, state, 0, rendererHasMediaFlags).sendToTarget(); + // renderer track information. + eventHandler.obtainMessage(MSG_PREPARED, state, 0, trackInfos).sendToTarget(); // Start the renderers if required, and schedule the first piece of work. if (playWhenReady && state == ExoPlayer.STATE_READY) { @@ -583,43 +589,54 @@ import java.util.List; } } - private void setRendererEnabledInternal(int rendererIndex, boolean enabled) + private void setRendererSelectedTrackInternal(int rendererIndex, int trackIndex) throws ExoPlaybackException { - if (rendererEnabledFlags[rendererIndex] == enabled) { + if (selectedTrackIndices[rendererIndex] == trackIndex) { return; } - rendererEnabledFlags[rendererIndex] = enabled; + selectedTrackIndices[rendererIndex] = trackIndex; if (state == ExoPlayer.STATE_IDLE || state == ExoPlayer.STATE_PREPARING) { return; } TrackRenderer renderer = renderers[rendererIndex]; int rendererState = renderer.getState(); - if (rendererState != TrackRenderer.STATE_PREPARED && - rendererState != TrackRenderer.STATE_ENABLED && - rendererState != TrackRenderer.STATE_STARTED) { + if (rendererState == TrackRenderer.STATE_UNPREPARED + || rendererState == TrackRenderer.STATE_RELEASED + || renderer.getTrackCount() == 0) { return; } - if (enabled) { - boolean playing = playWhenReady && state == ExoPlayer.STATE_READY; - renderer.enable(positionUs, playing); - enabledRenderers.add(renderer); - if (playing) { - renderer.start(); - } - handler.sendEmptyMessage(MSG_DO_SOME_WORK); - } else { - if (renderer == rendererMediaClockSource) { + boolean isEnabled = rendererState == TrackRenderer.STATE_ENABLED + || rendererState == TrackRenderer.STATE_STARTED; + boolean shouldEnable = 0 <= trackIndex && trackIndex < trackInfos[rendererIndex].length; + + if (isEnabled) { + // The renderer is currently enabled. We need to disable it, so that we can either re-enable + // it with the newly selected track (if shouldEnable is true) or because we want to leave it + // disabled (if shouldEnable is false). + if (!shouldEnable && renderer == rendererMediaClockSource) { // We've been using rendererMediaClockSource to advance the current position, but it's being - // disabled. Sync standaloneMediaClock so that it can take over timing responsibilities. + // disabled and won't be re-enabled. Sync standaloneMediaClock so that it can take over + // timing responsibilities. standaloneMediaClock.setPositionUs(rendererMediaClock.getPositionUs()); } ensureStopped(renderer); enabledRenderers.remove(renderer); renderer.disable(); } + + if (shouldEnable) { + // Re-enable the renderer with the newly selected track. + boolean playing = playWhenReady && state == ExoPlayer.STATE_READY; + renderer.enable(trackIndex, positionUs, playing); + enabledRenderers.add(renderer); + if (playing) { + renderer.start(); + } + handler.sendEmptyMessage(MSG_DO_SOME_WORK); + } } private void ensureStopped(TrackRenderer renderer) throws ExoPlaybackException { diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java index ecb99ac2ab..edacf72230 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java @@ -162,8 +162,9 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); seekToInternal(positionUs); } 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 13676b1c5e..3136ba4b9c 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java @@ -241,8 +241,9 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); seekToInternal(); } 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 1187fd4286..db88d2906e 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java @@ -261,8 +261,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); renderedFirstFrame = false; if (joining && allowedJoiningTimeUs > 0) { joiningDeadlineUs = SystemClock.elapsedRealtime() * 1000L + allowedJoiningTimeUs; 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 c5c69a830a..4ba94c07a5 100644 --- a/library/src/main/java/com/google/android/exoplayer/SampleSourceTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/SampleSourceTrackRenderer.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer; import com.google.android.exoplayer.SampleSource.SampleSourceReader; import java.io.IOException; +import java.util.Arrays; /** * Base class for {@link TrackRenderer} implementations that render samples obtained from a @@ -27,7 +28,9 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer { private final SampleSourceReader source; - private int trackIndex; + private int enabledSourceTrackIndex; + private int[] handledSourceTrackIndices; + private TrackInfo[] trackInfos; /** * @param source The upstream source from which the renderer obtains samples. @@ -37,21 +40,26 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer { } @Override - protected int doPrepare(long positionUs) throws ExoPlaybackException { + protected boolean doPrepare(long positionUs) throws ExoPlaybackException { boolean sourcePrepared = source.prepare(positionUs); if (!sourcePrepared) { - return TrackRenderer.STATE_UNPREPARED; + return false; } - int trackCount = source.getTrackCount(); - for (int i = 0; i < trackCount; i++) { - TrackInfo trackInfo = source.getTrackInfo(i); + int handledTrackCount = 0; + int sourceTrackCount = source.getTrackCount(); + int[] trackIndices = new int[sourceTrackCount]; + TrackInfo[] trackInfos = new TrackInfo[sourceTrackCount]; + for (int trackIndex = 0; trackIndex < sourceTrackCount; trackIndex++) { + TrackInfo trackInfo = source.getTrackInfo(trackIndex); if (handlesTrack(trackInfo)) { - trackIndex = i; - onTrackSelected(trackInfo); - return TrackRenderer.STATE_PREPARED; + trackIndices[handledTrackCount] = trackIndex; + trackInfos[handledTrackCount] = trackInfo; + handledTrackCount++; } } - return TrackRenderer.STATE_IGNORE; + this.handledSourceTrackIndices = Arrays.copyOf(trackIndices, handledTrackCount); + this.trackInfos = Arrays.copyOf(trackInfos, handledTrackCount); + return true; } /** @@ -72,8 +80,10 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer { } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - source.enable(trackIndex, positionUs); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + this.enabledSourceTrackIndex = handledSourceTrackIndices[track]; + source.enable(enabledSourceTrackIndex, positionUs); } @Override @@ -88,7 +98,7 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer { @Override protected long getDurationUs() { - return source.getTrackInfo(trackIndex).durationUs; + return source.getTrackInfo(enabledSourceTrackIndex).durationUs; } @Override @@ -102,7 +112,7 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer { @Override protected void onDisabled() throws ExoPlaybackException { - source.disable(trackIndex); + source.disable(enabledSourceTrackIndex); } @Override @@ -111,13 +121,23 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer { } protected final boolean continueBufferingSource(long positionUs) { - return source.continueBuffering(trackIndex, positionUs); + return source.continueBuffering(enabledSourceTrackIndex, positionUs); } protected final int readSource(long positionUs, MediaFormatHolder formatHolder, SampleHolder sampleHolder, boolean onlyReadDiscontinuity) { - return source.readData(trackIndex, positionUs, formatHolder, sampleHolder, + return source.readData(enabledSourceTrackIndex, positionUs, formatHolder, sampleHolder, onlyReadDiscontinuity); } + @Override + protected final int getTrackCount() { + return trackInfos.length; + } + + @Override + protected final TrackInfo getTrackInfo(int track) { + return trackInfos[track]; + } + } 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 408ac49982..00945d466d 100644 --- a/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java @@ -31,14 +31,24 @@ import com.google.android.exoplayer.util.Assertions; */ public abstract class TrackRenderer implements ExoPlayerComponent { + /** + * Represents an unknown time or duration. Equal to {@link C#UNKNOWN_TIME_US}. + */ + public static final long UNKNOWN_TIME_US = C.UNKNOWN_TIME_US; // -1 + /** + * Represents a time or duration that should match the duration of the longest track whose + * duration is known. Equal to {@link C#MATCH_LONGEST_US}. + */ + public static final long MATCH_LONGEST_US = C.MATCH_LONGEST_US; // -2 + /** + * Represents the time of the end of the track. + */ + public static final long END_OF_TRACK_US = -3; + /** * The renderer has been released and should not be used. */ - protected static final int STATE_RELEASED = -2; - /** - * The renderer should be ignored by the player. - */ - protected static final int STATE_IGNORE = -1; + protected static final int STATE_RELEASED = -1; /** * The renderer has not yet been prepared. */ @@ -64,20 +74,6 @@ public abstract class TrackRenderer implements ExoPlayerComponent { */ protected static final int STATE_STARTED = 3; - /** - * Represents an unknown time or duration. Equal to {@link C#UNKNOWN_TIME_US}. - */ - public static final long UNKNOWN_TIME_US = C.UNKNOWN_TIME_US; // -1 - /** - * Represents a time or duration that should match the duration of the longest track whose - * duration is known. Equal to {@link C#MATCH_LONGEST_US}. - */ - public static final long MATCH_LONGEST_US = C.MATCH_LONGEST_US; // -2 - /** - * Represents the time of the end of the track. - */ - public static final long END_OF_TRACK_US = -3; - private int state; /** @@ -111,41 +107,65 @@ public abstract class TrackRenderer implements ExoPlayerComponent { */ /* package */ final int prepare(long positionUs) throws ExoPlaybackException { Assertions.checkState(state == STATE_UNPREPARED); - state = doPrepare(positionUs); - Assertions.checkState(state == STATE_UNPREPARED || - state == STATE_PREPARED || - state == STATE_IGNORE); + state = doPrepare(positionUs) ? STATE_PREPARED : STATE_UNPREPARED; return state; } /** * Invoked to make progress when the renderer is in the {@link #STATE_UNPREPARED} state. This - * method will be called repeatedly until a value other than {@link #STATE_UNPREPARED} is - * returned. + * method will be called repeatedly until {@code true} is returned. *

* This method should return quickly, and should not block if the renderer is currently unable to * make any useful progress. * * @param positionUs The player's current playback position. - * @return The new state of the renderer. One of {@link #STATE_UNPREPARED}, - * {@link #STATE_PREPARED} and {@link #STATE_IGNORE}. + * @return True if the renderer is now prepared. False otherwise. * @throws ExoPlaybackException If an error occurs. */ - protected abstract int doPrepare(long positionUs) throws ExoPlaybackException; + protected abstract boolean doPrepare(long positionUs) throws ExoPlaybackException; /** - * Enable the renderer. + * Returns the number of tracks exposed by the renderer. + *

+ * This method may be called when the renderer is in the following states: + * {@link #STATE_PREPARED}, {@link #STATE_ENABLED}, {@link #STATE_STARTED} * + * @return The number of tracks. + */ + // TODO: This method should be abstract. This implementation is provided as an interim step only. + protected int getTrackCount() { + return 1; + } + + /** + * Returns information about the specified track. + *

+ * This method may be called when the renderer is in the following states: + * {@link #STATE_PREPARED}, {@link #STATE_ENABLED}, {@link #STATE_STARTED} + * + * @param track The track index. + * @return Information about the specified track. + */ + // TODO: This method should be abstract. This implementation is provided as an interim step only. + protected TrackInfo getTrackInfo(int track) { + return new TrackInfo("application/octet-stream", getDurationUs()); + } + + /** + * Enable the renderer for a specified track. + * + * @param track The track for which the renderer is being enabled. * @param positionUs The player's current position. * @param joining Whether this renderer is being enabled to join an ongoing playback. If true * then {@link #start} must be called immediately after this method returns (unless a * {@link ExoPlaybackException} is thrown). * @throws ExoPlaybackException If an error occurs. */ - /* package */ final void enable(long positionUs, boolean joining) throws ExoPlaybackException { + /* package */ final void enable(int track, long positionUs, boolean joining) + throws ExoPlaybackException { Assertions.checkState(state == STATE_PREPARED); state = STATE_ENABLED; - onEnabled(positionUs, joining); + onEnabled(track, positionUs, joining); } /** @@ -153,13 +173,15 @@ public abstract class TrackRenderer implements ExoPlayerComponent { *

* The default implementation is a no-op. * + * @param track The track for which the renderer is being enabled. * @param positionUs The player's current position. * @param joining Whether this renderer is being enabled to join an ongoing playback. If true * then {@link #onStarted} is guaranteed to be called immediately after this method returns * (unless a {@link ExoPlaybackException} is thrown). * @throws ExoPlaybackException If an error occurs. */ - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { // Do nothing. } 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 18521ca0c9..18d87c31f0 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 @@ -93,8 +93,9 @@ public final class MetadataTrackRenderer extends SampleSourceTrackRenderer im } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); seekToInternal(); } 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 0c7f6c34ea..4c96587c39 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 @@ -171,8 +171,9 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); parserThread = new HandlerThread("textParser"); parserThread.start(); parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]); 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 df8dc44911..f906396490 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 @@ -94,8 +94,9 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme } @Override - protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException { - super.onEnabled(positionUs, joining); + protected void onEnabled(int track, long positionUs, boolean joining) + throws ExoPlaybackException { + super.onEnabled(track, positionUs, joining); seekToInternal(); }