diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java
index 0a0d19a2ce..a27a80b783 100644
--- a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java
+++ b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java
@@ -268,6 +268,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
return new ExtractorRendererBuilder(this, userAgent, contentUri,
new FragmentedMp4Extractor());
case TYPE_WEBM:
+ case TYPE_MKV:
return new ExtractorRendererBuilder(this, userAgent, contentUri, new WebmExtractor());
default:
throw new IllegalStateException("Unsupported type: " + contentType);
@@ -377,7 +378,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
}
private boolean haveTracks(int type) {
- return player != null && player.getTracks(type) != null;
+ return player != null && player.getTrackCount(type) > 0;
}
public void showVideoPopup(View v) {
@@ -440,8 +441,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
if (player == null) {
return;
}
- String[] tracks = player.getTracks(trackType);
- if (tracks == null) {
+ int trackCount = player.getTrackCount(trackType);
+ if (trackCount == 0) {
return;
}
popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@@ -455,11 +456,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
Menu menu = popup.getMenu();
// ID_OFFSET ensures we avoid clashing with Menu.NONE (which equals 0)
menu.add(MENU_GROUP_TRACKS, DemoPlayer.DISABLED_TRACK + ID_OFFSET, Menu.NONE, R.string.off);
- if (tracks.length == 1 && TextUtils.isEmpty(tracks[0])) {
+ if (trackCount == 1 && TextUtils.isEmpty(player.getTrackName(trackType, 0))) {
menu.add(MENU_GROUP_TRACKS, DemoPlayer.PRIMARY_TRACK + ID_OFFSET, Menu.NONE, R.string.on);
} else {
- for (int i = 0; i < tracks.length; i++) {
- menu.add(MENU_GROUP_TRACKS, i + ID_OFFSET, Menu.NONE, tracks[i]);
+ for (int i = 0; i < trackCount; i++) {
+ menu.add(MENU_GROUP_TRACKS, i + ID_OFFSET, Menu.NONE, player.getTrackName(trackType, i));
}
}
menu.setGroupCheckable(MENU_GROUP_TRACKS, true, true);
diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java
index c7e639699b..6a095fec53 100644
--- a/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java
+++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java
@@ -263,8 +263,12 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
pushSurface(true);
}
- public String[] getTracks(int type) {
- return trackNames == null ? null : trackNames[type];
+ public int getTrackCount(int type) {
+ return !player.getRendererHasMedia(type) ? 0 : trackNames[type].length;
+ }
+
+ public String getTrackName(int type, int index) {
+ return trackNames[type][index];
}
public int getSelectedTrackIndex(int type) {
@@ -323,15 +327,16 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
if (multiTrackSources == null) {
multiTrackSources = new MultiTrackChunkSource[RENDERER_COUNT];
}
- for (int i = 0; i < RENDERER_COUNT; i++) {
- if (renderers[i] == null) {
+ for (int rendererIndex = 0; rendererIndex < RENDERER_COUNT; rendererIndex++) {
+ if (renderers[rendererIndex] == null) {
// Convert a null renderer to a dummy renderer.
- renderers[i] = new DummyTrackRenderer();
- } else if (trackNames[i] == null) {
- // We have a renderer so we must have at least one track, but the names are unknown.
- // Initialize the correct number of null track names.
- int trackCount = multiTrackSources[i] == null ? 1 : multiTrackSources[i].getTrackCount();
- trackNames[i] = new String[trackCount];
+ renderers[rendererIndex] = new DummyTrackRenderer();
+ }
+ if (trackNames[rendererIndex] == null) {
+ // Convert a null trackNames to an array of suitable length.
+ int trackCount = multiTrackSources[rendererIndex] != null
+ ? multiTrackSources[rendererIndex].getTrackCount() : 1;
+ trackNames[rendererIndex] = new String[trackCount];
}
}
// Complete preparation.
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 d88db9377c..58e2019e28 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
@@ -17,6 +17,7 @@ package com.google.android.exoplayer.ext.opus;
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.ExoPlayer;
+import com.google.android.exoplayer.MediaClock;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleSource;
@@ -38,7 +39,7 @@ import java.util.List;
*
* @author vigneshv@google.com (Vignesh Venkatasubramanian)
*/
-public class LibopusAudioTrackRenderer extends TrackRenderer {
+public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClock {
/**
* Interface definition for a callback to be notified of {@link LibopusAudioTrackRenderer} events.
@@ -87,6 +88,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer {
private int trackIndex;
private long currentPositionUs;
+ private boolean allowPositionDiscontinuity;
private boolean inputStreamEnded;
private boolean outputStreamEnded;
private boolean sourceIsReady;
@@ -119,8 +121,8 @@ public class LibopusAudioTrackRenderer extends TrackRenderer {
}
@Override
- protected boolean isTimeSource() {
- return true;
+ protected MediaClock getMediaClock() {
+ return this;
}
@Override
@@ -237,7 +239,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer {
// If we are out of sync, allow currentPositionUs to jump backwards.
if ((handleBufferResult & AudioTrack.RESULT_POSITION_DISCONTINUITY) != 0) {
- currentPositionUs = Long.MIN_VALUE;
+ allowPositionDiscontinuity = true;
}
// Release the buffer if it was consumed.
@@ -323,26 +325,31 @@ public class LibopusAudioTrackRenderer extends TrackRenderer {
}
@Override
- protected long getCurrentPositionUs() {
- long audioTrackCurrentPositionUs = audioTrack.getCurrentPositionUs(isEnded());
- if (audioTrackCurrentPositionUs != AudioTrack.CURRENT_POSITION_NOT_SET) {
- // Make sure we don't ever report time moving backwards.
- currentPositionUs = Math.max(currentPositionUs, audioTrackCurrentPositionUs);
+ public long getPositionUs() {
+ long newCurrentPositionUs = audioTrack.getCurrentPositionUs(isEnded());
+ if (newCurrentPositionUs != AudioTrack.CURRENT_POSITION_NOT_SET) {
+ currentPositionUs = allowPositionDiscontinuity ? newCurrentPositionUs
+ : Math.max(currentPositionUs, newCurrentPositionUs);
+ allowPositionDiscontinuity = false;
}
return currentPositionUs;
}
@Override
protected long getBufferedPositionUs() {
- long sourceBufferedPosition = source.getBufferedPositionUs();
- return sourceBufferedPosition == UNKNOWN_TIME_US || sourceBufferedPosition == END_OF_TRACK_US
- ? sourceBufferedPosition : Math.max(sourceBufferedPosition, getCurrentPositionUs());
+ return source.getBufferedPositionUs();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
+ source.seekToUs(positionUs);
+ seekToInternal(positionUs);
+ }
+
+ private void seekToInternal(long positionUs) {
audioTrack.reset();
currentPositionUs = positionUs;
+ allowPositionDiscontinuity = true;
source.seekToUs(positionUs);
inputStreamEnded = false;
outputStreamEnded = false;
@@ -352,10 +359,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer {
@Override
protected void onEnabled(long positionUs, boolean joining) {
source.enable(trackIndex, positionUs);
- sourceIsReady = false;
- inputStreamEnded = false;
- outputStreamEnded = false;
- currentPositionUs = Long.MIN_VALUE;
+ seekToInternal(positionUs);
}
@Override
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 628c5e759f..5ceff05548 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
@@ -111,7 +111,6 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
private boolean outputRgb;
private int trackIndex;
- private long currentPositionUs;
private boolean inputStreamEnded;
private boolean outputStreamEnded;
private boolean sourceIsReady;
@@ -181,9 +180,9 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
}
try {
sourceIsReady = source.continueBuffering(positionUs);
- checkForDiscontinuity();
+ checkForDiscontinuity(positionUs);
if (format == null) {
- readFormat();
+ readFormat(positionUs);
} else {
// TODO: Add support for dynamic switching between one type of surface to another.
// Create the decoder.
@@ -194,7 +193,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
processOutputBuffer(positionUs, elapsedRealtimeUs);
// Queue input buffers.
- while (feedInputBuffer()) {}
+ while (feedInputBuffer(positionUs)) {}
}
} catch (VpxDecoderException e) {
notifyDecoderError(e);
@@ -226,7 +225,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
long elapsedSinceStartOfLoop = SystemClock.elapsedRealtime() * 1000 - elapsedRealtimeUs;
long timeToRenderUs = outputBuffer.timestampUs - positionUs - elapsedSinceStartOfLoop;
- if (timeToRenderUs < -30000 || outputBuffer.timestampUs < currentPositionUs) {
+ if (timeToRenderUs < -30000 || outputBuffer.timestampUs < positionUs) {
// Drop frame if we are too late.
droppedFrameCount++;
if (droppedFrameCount == maxDroppedFrameCountToNotify) {
@@ -276,7 +275,6 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
}
private void releaseOutputBuffer() throws VpxDecoderException {
- currentPositionUs = outputBuffer.timestampUs;
decoder.releaseOutputBuffer(outputBuffer);
outputBuffer = null;
}
@@ -296,7 +294,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
surface.unlockCanvasAndPost(canvas);
}
- private boolean feedInputBuffer() throws IOException, VpxDecoderException {
+ private boolean feedInputBuffer(long positionUs) throws IOException, VpxDecoderException {
if (inputStreamEnded) {
return false;
}
@@ -308,8 +306,8 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
}
}
- int result = source.readData(trackIndex, currentPositionUs, formatHolder,
- inputBuffer.sampleHolder, false);
+ int result = source.readData(trackIndex, positionUs, formatHolder, inputBuffer.sampleHolder,
+ false);
if (result == SampleSource.NOTHING_READ) {
return false;
}
@@ -336,11 +334,11 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
return true;
}
- private void checkForDiscontinuity() throws IOException {
+ private void checkForDiscontinuity(long positionUs) throws IOException {
if (decoder == null) {
return;
}
- int result = source.readData(trackIndex, currentPositionUs, formatHolder, null, true);
+ int result = source.readData(trackIndex, positionUs, formatHolder, null, true);
if (result == SampleSource.DISCONTINUITY_READ) {
flushDecoder();
}
@@ -367,36 +365,28 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
return source.getTrackInfo(trackIndex).durationUs;
}
- @Override
- protected long getCurrentPositionUs() {
- return currentPositionUs;
- }
-
@Override
protected long getBufferedPositionUs() {
- long sourceBufferedPosition = source.getBufferedPositionUs();
- return sourceBufferedPosition == UNKNOWN_TIME_US || sourceBufferedPosition == END_OF_TRACK_US
- ? sourceBufferedPosition : Math.max(sourceBufferedPosition, getCurrentPositionUs());
+ return source.getBufferedPositionUs();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
- currentPositionUs = positionUs;
source.seekToUs(positionUs);
- inputStreamEnded = false;
- outputStreamEnded = false;
- renderedFirstFrame = false;
- sourceIsReady = false;
+ seekToInternal();
}
@Override
protected void onEnabled(long positionUs, boolean joining) {
source.enable(trackIndex, positionUs);
+ seekToInternal();
+ }
+
+ private void seekToInternal() {
sourceIsReady = false;
inputStreamEnded = false;
outputStreamEnded = false;
renderedFirstFrame = false;
- currentPositionUs = positionUs;
}
@Override
@@ -427,8 +417,8 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
source.disable(trackIndex);
}
- private void readFormat() throws IOException {
- int result = source.readData(trackIndex, currentPositionUs, formatHolder, null, false);
+ private void readFormat(long positionUs) throws IOException {
+ int result = source.readData(trackIndex, positionUs, formatHolder, null, false);
if (result == SampleSource.FORMAT_READ) {
format = formatHolder.format;
}
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 39aec48781..f926073740 100644
--- a/library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java
@@ -59,9 +59,4 @@ public class DummyTrackRenderer extends TrackRenderer {
throw new IllegalStateException();
}
- @Override
- protected long getCurrentPositionUs() {
- throw new IllegalStateException();
- }
-
}
diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java
index a0b544062a..e54645e095 100644
--- a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java
+++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java
@@ -261,21 +261,31 @@ public interface ExoPlayer {
*/
public void prepare(TrackRenderer... renderers);
+ /**
+ * Returns whether the renderer at the given index has media to play.
+ *
+ * Always returns false whilst the player is in the {@link #STATE_PREPARING} state.
+ *
+ * @param rendererIndex The index of the renderer.
+ * @return True if the renderer has media to play, false otherwise.
+ */
+ public boolean getRendererHasMedia(int rendererIndex);
+
/**
* Sets whether the renderer at the given index is enabled.
*
- * @param index The index of the renderer.
+ * @param rendererIndex The index of the renderer.
* @param enabled Whether the renderer at the given index should be enabled.
*/
- public void setRendererEnabled(int index, boolean enabled);
+ public void setRendererEnabled(int rendererIndex, boolean enabled);
/**
* Whether the renderer at the given index is enabled.
*
- * @param index The index of the renderer.
+ * @param rendererIndex The index of the renderer.
* @return Whether the renderer is enabled.
*/
- public boolean getRendererEnabled(int index);
+ public boolean getRendererEnabled(int rendererIndex);
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
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 a378cd5652..6729bfddd8 100644
--- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java
+++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java
@@ -21,6 +21,7 @@ import android.os.Looper;
import android.os.Message;
import android.util.Log;
+import java.util.Arrays;
import java.util.concurrent.CopyOnWriteArraySet;
/**
@@ -33,6 +34,7 @@ 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 boolean playWhenReady;
@@ -56,6 +58,7 @@ 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;
@@ -92,20 +95,26 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public void prepare(TrackRenderer... renderers) {
+ Arrays.fill(rendererHasMediaFlags, false);
internalPlayer.prepare(renderers);
}
@Override
- public void setRendererEnabled(int index, boolean enabled) {
- if (rendererEnabledFlags[index] != enabled) {
- rendererEnabledFlags[index] = enabled;
- internalPlayer.setRendererEnabled(index, enabled);
+ public boolean getRendererHasMedia(int rendererIndex) {
+ return rendererHasMediaFlags[rendererIndex];
+ }
+
+ @Override
+ public void setRendererEnabled(int rendererIndex, boolean enabled) {
+ if (rendererEnabledFlags[rendererIndex] != enabled) {
+ rendererEnabledFlags[rendererIndex] = enabled;
+ internalPlayer.setRendererEnabled(rendererIndex, enabled);
}
}
@Override
- public boolean getRendererEnabled(int index) {
- return rendererEnabledFlags[index];
+ public boolean getRendererEnabled(int rendererIndex) {
+ return rendererEnabledFlags[rendererIndex];
}
@Override
@@ -182,6 +191,16 @@ import java.util.concurrent.CopyOnWriteArraySet;
// Not private so it can be called from an inner class without going through a thunk method.
/* 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);
+ playbackState = msg.arg1;
+ for (Listener listener : listeners) {
+ listener.onPlayerStateChanged(playWhenReady, playbackState);
+ }
+ break;
+ }
case ExoPlayerImplInternal.MSG_STATE_CHANGED: {
playbackState = msg.arg1;
for (Listener listener : listeners) {
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 d828b8275c..5f065094f5 100644
--- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java
+++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java
@@ -40,9 +40,10 @@ import java.util.List;
private static final String TAG = "ExoPlayerImplInternal";
// External messages
- public static final int MSG_STATE_CHANGED = 1;
- public static final int MSG_SET_PLAY_WHEN_READY_ACK = 2;
- public static final int MSG_ERROR = 3;
+ public static final int MSG_PREPARED = 1;
+ public static final int MSG_STATE_CHANGED = 2;
+ public static final int MSG_SET_PLAY_WHEN_READY_ACK = 3;
+ public static final int MSG_ERROR = 4;
// Internal messages
private static final int MSG_PREPARE = 1;
@@ -62,14 +63,15 @@ import java.util.List;
private final Handler handler;
private final HandlerThread internalPlaybackThread;
private final Handler eventHandler;
- private final MediaClock mediaClock;
+ private final StandaloneMediaClock standaloneMediaClock;
private final boolean[] rendererEnabledFlags;
private final long minBufferUs;
private final long minRebufferUs;
private final List enabledRenderers;
private TrackRenderer[] renderers;
- private TrackRenderer timeSourceTrackRenderer;
+ private TrackRenderer rendererMediaClockSource;
+ private MediaClock rendererMediaClock;
private boolean released;
private boolean playWhenReady;
@@ -98,7 +100,7 @@ import java.util.List;
this.durationUs = TrackRenderer.UNKNOWN_TIME_US;
this.bufferedPositionUs = TrackRenderer.UNKNOWN_TIME_US;
- mediaClock = new MediaClock();
+ standaloneMediaClock = new StandaloneMediaClock();
enabledRenderers = new ArrayList<>(rendererEnabledFlags.length);
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
// not normally change to this priority" is incorrect.
@@ -250,9 +252,11 @@ import java.util.List;
resetInternal();
this.renderers = renderers;
for (int i = 0; i < renderers.length; i++) {
- if (renderers[i].isTimeSource()) {
- Assertions.checkState(timeSourceTrackRenderer == null);
- timeSourceTrackRenderer = renderers[i];
+ MediaClock mediaClock = renderers[i].getMediaClock();
+ if (mediaClock != null) {
+ Assertions.checkState(rendererMediaClock == null);
+ rendererMediaClock = mediaClock;
+ rendererMediaClockSource = renderers[i];
}
}
setState(ExoPlayer.STATE_PREPARING);
@@ -280,9 +284,11 @@ import java.util.List;
long durationUs = 0;
boolean allRenderersEnded = true;
boolean allRenderersReadyOrEnded = true;
- for (int i = 0; i < renderers.length; i++) {
- TrackRenderer renderer = renderers[i];
- if (renderer.getState() == TrackRenderer.STATE_PREPARED) {
+ 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]) {
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.
@@ -296,7 +302,7 @@ import java.util.List;
durationUs = Math.max(durationUs, trackDurationUs);
}
}
- if (rendererEnabledFlags[i]) {
+ if (rendererEnabledFlags[rendererIndex]) {
renderer.enable(positionUs, false);
enabledRenderers.add(renderer);
allRenderersEnded = allRenderersEnded && renderer.isEnded();
@@ -309,14 +315,19 @@ import java.util.List;
if (allRenderersEnded
&& (durationUs == TrackRenderer.UNKNOWN_TIME_US || durationUs <= positionUs)) {
// We don't expect this case, but handle it anyway.
- setState(ExoPlayer.STATE_ENDED);
+ state = ExoPlayer.STATE_ENDED;
} else {
- setState(allRenderersReadyOrEnded ? ExoPlayer.STATE_READY : ExoPlayer.STATE_BUFFERING);
- if (playWhenReady && state == ExoPlayer.STATE_READY) {
- startRenderers();
- }
+ state = allRenderersReadyOrEnded ? ExoPlayer.STATE_READY : ExoPlayer.STATE_BUFFERING;
}
+ // 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();
+
+ // Start the renderers if required, and schedule the first piece of work.
+ if (playWhenReady && state == ExoPlayer.STATE_READY) {
+ startRenderers();
+ }
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}
@@ -364,26 +375,26 @@ import java.util.List;
private void startRenderers() throws ExoPlaybackException {
rebuffering = false;
- mediaClock.start();
+ standaloneMediaClock.start();
for (int i = 0; i < enabledRenderers.size(); i++) {
enabledRenderers.get(i).start();
}
}
private void stopRenderers() throws ExoPlaybackException {
- mediaClock.stop();
+ standaloneMediaClock.stop();
for (int i = 0; i < enabledRenderers.size(); i++) {
ensureStopped(enabledRenderers.get(i));
}
}
private void updatePositionUs() {
- if (timeSourceTrackRenderer != null && enabledRenderers.contains(timeSourceTrackRenderer)
- && !timeSourceTrackRenderer.isEnded()) {
- positionUs = timeSourceTrackRenderer.getCurrentPositionUs();
- mediaClock.setPositionUs(positionUs);
+ if (rendererMediaClock != null && enabledRenderers.contains(rendererMediaClockSource)
+ && !rendererMediaClockSource.isEnded()) {
+ positionUs = rendererMediaClock.getPositionUs();
+ standaloneMediaClock.setPositionUs(positionUs);
} else {
- positionUs = mediaClock.getPositionUs();
+ positionUs = standaloneMediaClock.getPositionUs();
}
elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
}
@@ -464,8 +475,8 @@ import java.util.List;
private void seekToInternal(long positionMs) throws ExoPlaybackException {
rebuffering = false;
positionUs = positionMs * 1000L;
- mediaClock.stop();
- mediaClock.setPositionUs(positionUs);
+ standaloneMediaClock.stop();
+ standaloneMediaClock.setPositionUs(positionUs);
if (state == ExoPlayer.STATE_IDLE || state == ExoPlayer.STATE_PREPARING) {
return;
}
@@ -496,7 +507,7 @@ import java.util.List;
handler.removeMessages(MSG_DO_SOME_WORK);
handler.removeMessages(MSG_INCREMENTAL_PREPARE);
rebuffering = false;
- mediaClock.stop();
+ standaloneMediaClock.stop();
if (renderers == null) {
return;
}
@@ -506,7 +517,8 @@ import java.util.List;
release(renderer);
}
renderers = null;
- timeSourceTrackRenderer = null;
+ rendererMediaClock = null;
+ rendererMediaClockSource = null;
enabledRenderers.clear();
}
@@ -555,18 +567,18 @@ import java.util.List;
}
}
- private void setRendererEnabledInternal(int index, boolean enabled)
+ private void setRendererEnabledInternal(int rendererIndex, boolean enabled)
throws ExoPlaybackException {
- if (rendererEnabledFlags[index] == enabled) {
+ if (rendererEnabledFlags[rendererIndex] == enabled) {
return;
}
- rendererEnabledFlags[index] = enabled;
+ rendererEnabledFlags[rendererIndex] = enabled;
if (state == ExoPlayer.STATE_IDLE || state == ExoPlayer.STATE_PREPARING) {
return;
}
- TrackRenderer renderer = renderers[index];
+ TrackRenderer renderer = renderers[rendererIndex];
int rendererState = renderer.getState();
if (rendererState != TrackRenderer.STATE_PREPARED &&
rendererState != TrackRenderer.STATE_ENABLED &&
@@ -583,10 +595,10 @@ import java.util.List;
}
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
} else {
- if (renderer == timeSourceTrackRenderer) {
+ if (renderer == rendererMediaClockSource) {
// We've been using timeSourceTrackRenderer to advance the current position, but it's
// being disabled. Sync mediaClock so that it can take over timing responsibilities.
- mediaClock.setPositionUs(renderer.getCurrentPositionUs());
+ standaloneMediaClock.setPositionUs(rendererMediaClock.getPositionUs());
}
ensureStopped(renderer);
enabledRenderers.remove(renderer);
diff --git a/library/src/main/java/com/google/android/exoplayer/MediaClock.java b/library/src/main/java/com/google/android/exoplayer/MediaClock.java
index c2696e3b74..6cfe50e156 100644
--- a/library/src/main/java/com/google/android/exoplayer/MediaClock.java
+++ b/library/src/main/java/com/google/android/exoplayer/MediaClock.java
@@ -15,65 +15,14 @@
*/
package com.google.android.exoplayer;
-import android.os.SystemClock;
-
/**
- * A simple clock for tracking the progression of media time. The clock can be started, stopped and
- * its time can be set and retrieved. When started, this clock is based on
- * {@link SystemClock#elapsedRealtime()}.
+ * Tracks the progression of media time.
*/
-/* package */ class MediaClock {
-
- private boolean started;
+public interface MediaClock {
/**
- * The media time when the clock was last set or stopped.
+ * @return The current media position in microseconds.
*/
- private long positionUs;
-
- /**
- * The difference between {@link SystemClock#elapsedRealtime()} and {@link #positionUs}
- * when the clock was last set or started.
- */
- private long deltaUs;
-
- /**
- * Starts the clock. Does nothing if the clock is already started.
- */
- public void start() {
- if (!started) {
- started = true;
- deltaUs = elapsedRealtimeMinus(positionUs);
- }
- }
-
- /**
- * Stops the clock. Does nothing if the clock is already stopped.
- */
- public void stop() {
- if (started) {
- positionUs = elapsedRealtimeMinus(deltaUs);
- started = false;
- }
- }
-
- /**
- * @param timeUs The position to set in microseconds.
- */
- public void setPositionUs(long timeUs) {
- this.positionUs = timeUs;
- deltaUs = elapsedRealtimeMinus(timeUs);
- }
-
- /**
- * @return The current position in microseconds.
- */
- public long getPositionUs() {
- return started ? elapsedRealtimeMinus(deltaUs) : positionUs;
- }
-
- private long elapsedRealtimeMinus(long toSubtractUs) {
- return SystemClock.elapsedRealtime() * 1000 - toSubtractUs;
- }
+ long getPositionUs();
}
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 48b54db597..a28240477d 100644
--- a/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java
@@ -31,7 +31,7 @@ import java.nio.ByteBuffer;
* Decodes and renders audio using {@link MediaCodec} and {@link android.media.AudioTrack}.
*/
@TargetApi(16)
-public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
+public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implements MediaClock {
/**
* Interface definition for a callback to be notified of {@link MediaCodecAudioTrackRenderer}
@@ -72,6 +72,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
private int audioSessionId;
private long currentPositionUs;
+ private boolean allowPositionDiscontinuity;
/**
* @param source The upstream source from which the renderer obtains samples.
@@ -151,8 +152,8 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
- protected boolean isTimeSource() {
- return true;
+ protected MediaClock getMediaClock() {
+ return this;
}
@Override
@@ -163,7 +164,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
@Override
protected void onEnabled(long positionUs, boolean joining) {
super.onEnabled(positionUs, joining);
- currentPositionUs = Long.MIN_VALUE;
+ seekToInternal(positionUs);
}
@Override
@@ -219,14 +220,12 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
- protected long getCurrentPositionUs() {
- long audioTrackCurrentPositionUs = audioTrack.getCurrentPositionUs(isEnded());
- if (audioTrackCurrentPositionUs == AudioTrack.CURRENT_POSITION_NOT_SET) {
- // Use the super class position before audio playback starts.
- currentPositionUs = Math.max(currentPositionUs, super.getCurrentPositionUs());
- } else {
- // Make sure we don't ever report time moving backwards.
- currentPositionUs = Math.max(currentPositionUs, audioTrackCurrentPositionUs);
+ public long getPositionUs() {
+ long newCurrentPositionUs = audioTrack.getCurrentPositionUs(isEnded());
+ if (newCurrentPositionUs != AudioTrack.CURRENT_POSITION_NOT_SET) {
+ currentPositionUs = allowPositionDiscontinuity ? newCurrentPositionUs
+ : Math.max(currentPositionUs, newCurrentPositionUs);
+ allowPositionDiscontinuity = false;
}
return currentPositionUs;
}
@@ -244,9 +243,14 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
+ seekToInternal(positionUs);
+ }
+
+ private void seekToInternal(long positionUs) {
// TODO: Try and re-use the same AudioTrack instance once [Internal: b/7941810] is fixed.
audioTrack.reset();
- currentPositionUs = Long.MIN_VALUE;
+ currentPositionUs = positionUs;
+ allowPositionDiscontinuity = true;
}
@Override
@@ -290,7 +294,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
// If we are out of sync, allow currentPositionUs to jump backwards.
if ((handleBufferResult & AudioTrack.RESULT_POSITION_DISCONTINUITY) != 0) {
- currentPositionUs = Long.MIN_VALUE;
+ allowPositionDiscontinuity = true;
}
// Release the buffer if it was consumed.
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 45d148355c..457320ed0d 100644
--- a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java
@@ -212,7 +212,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
private boolean outputStreamEnded;
private boolean waitingForKeys;
private boolean waitingForFirstSyncFrame;
- private long currentPositionUs;
/**
* @param source The upstream source from which the renderer obtains samples.
@@ -283,11 +282,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
@Override
protected void onEnabled(long positionUs, boolean joining) {
source.enable(trackIndex, positionUs);
- sourceState = SOURCE_STATE_NOT_READY;
- inputStreamEnded = false;
- outputStreamEnded = false;
- waitingForKeys = false;
- currentPositionUs = positionUs;
+ seekToInternal();
}
/**
@@ -457,11 +452,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
source.release();
}
- @Override
- protected long getCurrentPositionUs() {
- return currentPositionUs;
- }
-
@Override
protected long getDurationUs() {
return source.getTrackInfo(trackIndex).durationUs;
@@ -469,15 +459,16 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
@Override
protected long getBufferedPositionUs() {
- long sourceBufferedPosition = source.getBufferedPositionUs();
- return sourceBufferedPosition == UNKNOWN_TIME_US || sourceBufferedPosition == END_OF_TRACK_US
- ? sourceBufferedPosition : Math.max(sourceBufferedPosition, getCurrentPositionUs());
+ return source.getBufferedPositionUs();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
- currentPositionUs = positionUs;
source.seekToUs(positionUs);
+ seekToInternal();
+ }
+
+ private void seekToInternal() {
sourceState = SOURCE_STATE_NOT_READY;
inputStreamEnded = false;
outputStreamEnded = false;
@@ -499,9 +490,9 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
sourceState = source.continueBuffering(positionUs)
? (sourceState == SOURCE_STATE_NOT_READY ? SOURCE_STATE_READY : sourceState)
: SOURCE_STATE_NOT_READY;
- checkForDiscontinuity();
+ checkForDiscontinuity(positionUs);
if (format == null) {
- readFormat();
+ readFormat(positionUs);
}
if (codec == null && shouldInitCodec()) {
maybeInitCodec();
@@ -509,8 +500,8 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
if (codec != null) {
TraceUtil.beginSection("drainAndFeed");
while (drainOutputBuffer(positionUs, elapsedRealtimeUs)) {}
- if (feedInputBuffer(true)) {
- while (feedInputBuffer(false)) {}
+ if (feedInputBuffer(positionUs, true)) {
+ while (feedInputBuffer(positionUs, false)) {}
}
TraceUtil.endSection();
}
@@ -520,18 +511,18 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
}
- private void readFormat() throws IOException, ExoPlaybackException {
- int result = source.readData(trackIndex, currentPositionUs, formatHolder, sampleHolder, false);
+ private void readFormat(long positionUs) throws IOException, ExoPlaybackException {
+ int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
if (result == SampleSource.FORMAT_READ) {
onInputFormatChanged(formatHolder);
}
}
- private void checkForDiscontinuity() throws IOException, ExoPlaybackException {
+ private void checkForDiscontinuity(long positionUs) throws IOException, ExoPlaybackException {
if (codec == null) {
return;
}
- int result = source.readData(trackIndex, currentPositionUs, formatHolder, sampleHolder, true);
+ int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, true);
if (result == SampleSource.DISCONTINUITY_READ) {
flushCodec();
}
@@ -561,13 +552,16 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
/**
+ * @param positionUs The current media time in microseconds, measured at the start of the
+ * current iteration of the rendering loop.
* @param firstFeed True if this is the first call to this method from the current invocation of
* {@link #doSomeWork(long, long)}. False otherwise.
* @return True if it may be possible to feed more input data. False otherwise.
* @throws IOException If an error occurs reading data from the upstream source.
* @throws ExoPlaybackException If an error occurs feeding the input buffer.
*/
- private boolean feedInputBuffer(boolean firstFeed) throws IOException, ExoPlaybackException {
+ private boolean feedInputBuffer(long positionUs, boolean firstFeed)
+ throws IOException, ExoPlaybackException {
if (inputStreamEnded
|| codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) {
// The input stream has ended, or we need to re-initialize the codec but are still waiting
@@ -607,7 +601,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
}
- result = source.readData(trackIndex, currentPositionUs, formatHolder, sampleHolder, false);
+ result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
if (firstFeed && sourceState == SOURCE_STATE_READY && result == SampleSource.NOTHING_READ) {
sourceState = SOURCE_STATE_READY_READ_MAY_FAIL;
}
@@ -857,8 +851,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
outputBufferInfo, outputIndex, decodeOnlyIndex != -1)) {
if (decodeOnlyIndex != -1) {
decodeOnlyPresentationTimestamps.remove(decodeOnlyIndex);
- } else {
- currentPositionUs = outputBufferInfo.presentationTimeUs;
}
outputIndex = -1;
return true;
diff --git a/library/src/main/java/com/google/android/exoplayer/StandaloneMediaClock.java b/library/src/main/java/com/google/android/exoplayer/StandaloneMediaClock.java
new file mode 100644
index 0000000000..f4b85b0d35
--- /dev/null
+++ b/library/src/main/java/com/google/android/exoplayer/StandaloneMediaClock.java
@@ -0,0 +1,76 @@
+/*
+ * 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 android.os.SystemClock;
+
+/**
+ * A standalone {@link MediaClock}. The clock can be started, stopped and its time can be set and
+ * retrieved. When started, this clock is based on {@link SystemClock#elapsedRealtime()}.
+ */
+/* package */ class StandaloneMediaClock implements MediaClock {
+
+ private boolean started;
+
+ /**
+ * The media time when the clock was last set or stopped.
+ */
+ private long positionUs;
+
+ /**
+ * The difference between {@link SystemClock#elapsedRealtime()} and {@link #positionUs}
+ * when the clock was last set or started.
+ */
+ private long deltaUs;
+
+ /**
+ * Starts the clock. Does nothing if the clock is already started.
+ */
+ public void start() {
+ if (!started) {
+ started = true;
+ deltaUs = elapsedRealtimeMinus(positionUs);
+ }
+ }
+
+ /**
+ * Stops the clock. Does nothing if the clock is already stopped.
+ */
+ public void stop() {
+ if (started) {
+ positionUs = elapsedRealtimeMinus(deltaUs);
+ started = false;
+ }
+ }
+
+ /**
+ * @param timeUs The position to set in microseconds.
+ */
+ public void setPositionUs(long timeUs) {
+ this.positionUs = timeUs;
+ deltaUs = elapsedRealtimeMinus(timeUs);
+ }
+
+ @Override
+ public long getPositionUs() {
+ return started ? elapsedRealtimeMinus(deltaUs) : positionUs;
+ }
+
+ private long elapsedRealtimeMinus(long toSubtractUs) {
+ return SystemClock.elapsedRealtime() * 1000 - toSubtractUs;
+ }
+
+}
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 3b8b4f372b..4d2f994a01 100644
--- a/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer/TrackRenderer.java
@@ -81,18 +81,15 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
private int state;
/**
- * A time source renderer is a renderer that, when started, advances its own playback position.
- * This means that {@link #getCurrentPositionUs()} will return increasing positions independently
- * to increasing values being passed to {@link #doSomeWork(long, long)}. A player may have at most
- * one time source renderer. If provided, the player will use such a renderer as its source of
- * time during playback.
- *
- * This method may be called when the renderer is in any state.
+ * If the renderer advances its own playback position then this method returns a corresponding
+ * {@link MediaClock}. If provided, the player will use the returned {@link MediaClock} as its
+ * source of time during playback. A player may have at most one renderer that returns a
+ * {@link MediaClock} from this method.
*
- * @return True if the renderer should be considered a time source. False otherwise.
+ * @return The {@link MediaClock} tracking the playback position of the renderer, or null.
*/
- protected boolean isTimeSource() {
- return false;
+ protected MediaClock getMediaClock() {
+ return null;
}
/**
@@ -312,16 +309,6 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
*/
protected abstract long getDurationUs();
- /**
- * Returns the current playback position.
- *
- * This method may be called when the renderer is in the following states:
- * {@link #STATE_ENABLED}, {@link #STATE_STARTED}
- *
- * @return The current playback position in microseconds.
- */
- protected abstract long getCurrentPositionUs();
-
/**
* Returns an estimate of the absolute position in microseconds up to which data is buffered.
*
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 c0774f15ad..3aa11e7962 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
@@ -63,7 +63,6 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback
private final SampleHolder sampleHolder;
private int trackIndex;
- private long currentPositionUs;
private boolean inputStreamEnded;
private long pendingMetadataTimestamp;
@@ -112,17 +111,16 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback
@Override
protected void onEnabled(long positionUs, boolean joining) {
source.enable(trackIndex, positionUs);
- seekToInternal(positionUs);
+ seekToInternal();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
source.seekToUs(positionUs);
- seekToInternal(positionUs);
+ seekToInternal();
}
- private void seekToInternal(long positionUs) {
- currentPositionUs = positionUs;
+ private void seekToInternal() {
pendingMetadata = null;
inputStreamEnded = false;
}
@@ -130,7 +128,6 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs)
throws ExoPlaybackException {
- currentPositionUs = positionUs;
try {
source.continueBuffering(positionUs);
} catch (IOException e) {
@@ -152,7 +149,7 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback
}
}
- if (pendingMetadata != null && pendingMetadataTimestamp <= currentPositionUs) {
+ if (pendingMetadata != null && pendingMetadataTimestamp <= positionUs) {
invokeRenderer(pendingMetadata);
pendingMetadata = null;
}
@@ -169,11 +166,6 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback
return source.getTrackInfo(trackIndex).durationUs;
}
- @Override
- protected long getCurrentPositionUs() {
- return currentPositionUs;
- }
-
@Override
protected long getBufferedPositionUs() {
return TrackRenderer.END_OF_TRACK_US;
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 7387d53bdc..0eae41bc13 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
@@ -52,7 +52,6 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
private int parserIndex;
private int trackIndex;
- private long currentPositionUs;
private boolean inputStreamEnded;
private Subtitle subtitle;
@@ -110,18 +109,17 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
parserThread = new HandlerThread("textParser");
parserThread.start();
parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]);
- seekToInternal(positionUs);
+ seekToInternal();
}
@Override
protected void seekTo(long positionUs) {
source.seekToUs(positionUs);
- seekToInternal(positionUs);
+ seekToInternal();
}
- private void seekToInternal(long positionUs) {
+ private void seekToInternal() {
inputStreamEnded = false;
- currentPositionUs = positionUs;
subtitle = null;
nextSubtitle = null;
parserHelper.flush();
@@ -130,7 +128,6 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
- currentPositionUs = positionUs;
try {
source.continueBuffering(positionUs);
} catch (IOException e) {
@@ -205,11 +202,6 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
source.release();
}
- @Override
- protected long getCurrentPositionUs() {
- return currentPositionUs;
- }
-
@Override
protected long getDurationUs() {
return source.getTrackInfo(trackIndex).durationUs;
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 947ec3a84f..343d3d0c1e 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
@@ -63,7 +63,6 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
private final TreeSet pendingCaptionLists;
private int trackIndex;
- private long currentPositionUs;
private boolean inputStreamEnded;
private int captionMode;
@@ -114,17 +113,16 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
@Override
protected void onEnabled(long positionUs, boolean joining) {
source.enable(trackIndex, positionUs);
- seekToInternal(positionUs);
+ seekToInternal();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
source.seekToUs(positionUs);
- seekToInternal(positionUs);
+ seekToInternal();
}
- private void seekToInternal(long positionUs) {
- currentPositionUs = positionUs;
+ private void seekToInternal() {
inputStreamEnded = false;
pendingCaptionLists.clear();
clearPendingSample();
@@ -134,9 +132,7 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
}
@Override
- protected void doSomeWork(long positionUs, long elapsedRealtimeUs)
- throws ExoPlaybackException {
- currentPositionUs = positionUs;
+ protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
try {
source.continueBuffering(positionUs);
} catch (IOException e) {
@@ -144,7 +140,7 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
}
if (isSamplePending()) {
- maybeParsePendingSample();
+ maybeParsePendingSample(positionUs);
}
int result = inputStreamEnded ? SampleSource.END_OF_STREAM : SampleSource.SAMPLE_READ;
@@ -152,7 +148,7 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
try {
result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
if (result == SampleSource.SAMPLE_READ) {
- maybeParsePendingSample();
+ maybeParsePendingSample(positionUs);
} else if (result == SampleSource.END_OF_STREAM) {
inputStreamEnded = true;
}
@@ -162,7 +158,7 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
}
while (!pendingCaptionLists.isEmpty()) {
- if (pendingCaptionLists.first().timeUs > currentPositionUs) {
+ if (pendingCaptionLists.first().timeUs > positionUs) {
// We're too early to render any of the pending caption lists.
return;
}
@@ -186,11 +182,6 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
return source.getTrackInfo(trackIndex).durationUs;
}
- @Override
- protected long getCurrentPositionUs() {
- return currentPositionUs;
- }
-
@Override
protected long getBufferedPositionUs() {
return TrackRenderer.END_OF_TRACK_US;
@@ -238,8 +229,8 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
}
}
- private void maybeParsePendingSample() {
- if (sampleHolder.timeUs > currentPositionUs + MAX_SAMPLE_READAHEAD_US) {
+ private void maybeParsePendingSample(long positionUs) {
+ if (sampleHolder.timeUs > positionUs + MAX_SAMPLE_READAHEAD_US) {
// We're too early to parse the sample.
return;
}