Internal plumbing for multi-track support.

- Generalize rendererEnabledFlags to be selected track indices through
  ExoPlayerImpl/ExoPlayerImplInternal.
- Selecting an out-of-bound track index (e.g. -1) is equivalent to
  disabling a renderer prior to the generalization.
- A prepared TrackRenderer that exposes 0 tracks is equivalent to a
  TrackRenderer in the STATE_IGNORE state prior to the generalization.

Issue #514.
This commit is contained in:
Oliver Woodman 2015-08-11 18:06:21 +01:00
parent 13f4a3e3bd
commit 6085d185fa
13 changed files with 222 additions and 126 deletions

View file

@ -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);
}

View file

@ -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();
}

View file

@ -18,15 +18,25 @@ package com.google.android.exoplayer;
/**
* A {@link TrackRenderer} that does nothing.
* <p>
* 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

View file

@ -34,8 +34,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
private final Handler eventHandler;
private final ExoPlayerImplInternal internalPlayer;
private final CopyOnWriteArraySet<Listener> 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);

View file

@ -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<TrackRenderer> enabledRenderers;
private final TrackInfo[][] trackInfos;
private final int[] selectedTrackIndices;
private final long minBufferUs;
private final long minRebufferUs;
private final List<TrackRenderer> 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 {

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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];
}
}

View file

@ -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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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 {
* <p>
* 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.
}

View file

@ -93,8 +93,9 @@ public final class MetadataTrackRenderer<T> 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();
}

View file

@ -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]);

View file

@ -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();
}