diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java index 5c741cb2bf..df6b9f8af7 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java @@ -18,7 +18,7 @@ package com.google.android.exoplayer2.demo; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.drm.StreamingDrmSessionManager; @@ -130,7 +130,8 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb TrackGroup trackGroup = trackGroups.get(groupIndex); for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { String status = getTrackStatusString(false); - String formatSupport = getFormatSupportString(Renderer.FORMAT_UNSUPPORTED_TYPE); + String formatSupport = getFormatSupportString( + RendererCapabilities.FORMAT_UNSUPPORTED_TYPE); Log.d(TAG, " " + status + " Track:" + trackIndex + ", " + getFormatString(trackGroup.getFormat(trackIndex)) + ", supported=" + formatSupport); @@ -296,13 +297,13 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb private static String getFormatSupportString(int formatSupport) { switch (formatSupport) { - case Renderer.FORMAT_HANDLED: + case RendererCapabilities.FORMAT_HANDLED: return "YES"; - case Renderer.FORMAT_EXCEEDS_CAPABILITIES: + case RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES: return "NO_EXCEEDS_CAPABILITIES"; - case Renderer.FORMAT_UNSUPPORTED_SUBTYPE: + case RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE: return "NO_UNSUPPORTED_TYPE"; - case Renderer.FORMAT_UNSUPPORTED_TYPE: + case RendererCapabilities.FORMAT_UNSUPPORTED_TYPE: return "NO"; default: return "?"; @@ -314,11 +315,11 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb return "N/A"; } switch (adaptiveSupport) { - case Renderer.ADAPTIVE_SEAMLESS: + case RendererCapabilities.ADAPTIVE_SEAMLESS: return "YES"; - case Renderer.ADAPTIVE_NOT_SEAMLESS: + case RendererCapabilities.ADAPTIVE_NOT_SEAMLESS: return "YES_NOT_SEAMLESS"; - case Renderer.ADAPTIVE_NOT_SUPPORTED: + case RendererCapabilities.ADAPTIVE_NOT_SUPPORTED: return "NO"; default: return "?"; diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java b/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java index 433d45023f..cab1ba588d 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java @@ -16,7 +16,7 @@ package com.google.android.exoplayer2.demo; import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.MappingTrackSelector; @@ -81,7 +81,7 @@ import java.util.Locale; trackGroupsAdaptive = new boolean[trackGroups.length]; for (int i = 0; i < trackGroups.length; i++) { trackGroupsAdaptive[i] = trackInfo.getAdaptiveSupport(rendererIndex, i, false) - != Renderer.ADAPTIVE_NOT_SUPPORTED; + != RendererCapabilities.ADAPTIVE_NOT_SUPPORTED; } isDisabled = selector.getRendererDisabled(rendererIndex); override = selector.hasSelectionOverride(rendererIndex, trackGroups) @@ -133,7 +133,7 @@ import java.util.Locale; trackViewLayoutId, root, false); trackView.setText(buildTrackName(group.getFormat(trackIndex))); if (trackInfo.getTrackFormatSupport(rendererIndex, groupIndex, trackIndex) - == Renderer.FORMAT_HANDLED) { + == RendererCapabilities.FORMAT_HANDLED) { haveSupportedTracks = true; trackView.setTag(Pair.create(groupIndex, trackIndex)); trackView.setOnClickListener(this); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index 5a2bfb14f4..fa1fa263f2 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -15,12 +15,12 @@ */ package com.google.android.exoplayer2.ext.vp9; +import com.google.android.exoplayer2.BaseRenderer; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; -import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.util.MimeTypes; @@ -37,7 +37,7 @@ import android.view.Surface; /** * Decodes and renders video using the native VP9 decoder. */ -public final class LibvpxVideoRenderer extends Renderer { +public final class LibvpxVideoRenderer extends BaseRenderer { /** * The type of a message that can be passed to an instance of this class via @@ -150,7 +150,7 @@ public final class LibvpxVideoRenderer extends Renderer { } @Override - protected void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { + public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { if (outputStreamEnded) { return; } @@ -241,8 +241,7 @@ public final class LibvpxVideoRenderer extends Renderer { return false; } - if (getState() == Renderer.STATE_STARTED - && outputBuffer.timestampUs <= positionUs + 30000) { + if (getState() == STATE_STARTED && outputBuffer.timestampUs <= positionUs + 30000) { renderBuffer(); } return false; @@ -330,12 +329,12 @@ public final class LibvpxVideoRenderer extends Renderer { } @Override - protected boolean isEnded() { + public boolean isEnded() { return outputStreamEnded; } @Override - protected boolean isReady() { + public boolean isReady() { if (format != null && (isSourceReady() || outputBuffer != null) && renderedFirstFrame) { // Ready. If we were joining then we've now joined, so clear the joining deadline. joiningDeadlineMs = -1; diff --git a/library/src/main/java/com/google/android/exoplayer2/BaseRenderer.java b/library/src/main/java/com/google/android/exoplayer2/BaseRenderer.java new file mode 100644 index 0000000000..2335ec9901 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer2/BaseRenderer.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 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.exoplayer2; + +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MediaClock; + +import java.io.IOException; + +/** + * An abstract base class suitable for most {@link Renderer} implementations. + */ +public abstract class BaseRenderer implements Renderer { + + private int index; + private int state; + private SampleStream stream; + private long streamOffsetUs; + private boolean readEndOfStream; + private boolean streamIsFinal; + + public BaseRenderer() { + readEndOfStream = true; + } + + @Override + public final void setIndex(int index) { + this.index = index; + } + + @Override + public final int getIndex() { + return index; + } + + @Override + public MediaClock getMediaClock() { + return null; + } + + @Override + public final int getState() { + return state; + } + + @Override + public final void enable(Format[] formats, SampleStream stream, long positionUs, + boolean joining, long offsetUs) throws ExoPlaybackException { + Assertions.checkState(state == STATE_DISABLED); + state = STATE_ENABLED; + onEnabled(joining); + replaceStream(formats, stream, offsetUs); + onReset(positionUs, joining); + } + + /** + * Called when the renderer is enabled. + *
+ * The default implementation is a no-op. + * + * @param joining Whether this renderer is being enabled to join an ongoing playback. + * @throws ExoPlaybackException If an error occurs. + */ + protected void onEnabled(boolean joining) throws ExoPlaybackException { + // Do nothing. + } + + @Override + public final void replaceStream(Format[] formats, SampleStream stream, long offsetUs) + throws ExoPlaybackException { + Assertions.checkState(!streamIsFinal); + this.stream = stream; + readEndOfStream = false; + streamOffsetUs = offsetUs; + onStreamChanged(formats); + } + + /** + * Called when the renderer's stream has changed. + *
+ * The default implementation is a no-op. + * + * @param formats The enabled formats. + * @throws ExoPlaybackException Thrown if an error occurs. + */ + protected void onStreamChanged(Format[] formats) throws ExoPlaybackException { + // Do nothing. + } + + @Override + public final void reset(long positionUs) throws ExoPlaybackException { + streamIsFinal = false; + onReset(positionUs, false); + } + + /** + * Invoked when a reset is encountered, and also when the renderer is enabled. + *
+ * This method may be called when the renderer is in the following states: + * {@link #STATE_ENABLED}, {@link #STATE_STARTED}. + * + * @param positionUs The playback position in microseconds. + * @param joining Whether this renderer is being enabled to join an ongoing playback. + * @throws ExoPlaybackException If an error occurs handling the reset. + */ + protected void onReset(long positionUs, boolean joining) throws ExoPlaybackException { + // Do nothing. + } + + @Override + public final boolean hasReadStreamToEnd() { + return readEndOfStream; + } + + @Override + public final void setCurrentStreamIsFinal() { + streamIsFinal = true; + } + + @Override + public final void start() throws ExoPlaybackException { + Assertions.checkState(state == STATE_ENABLED); + state = STATE_STARTED; + onStarted(); + } + + /** + * Called when the renderer is started. + *
+ * The default implementation is a no-op. + * + * @throws ExoPlaybackException If an error occurs. + */ + protected void onStarted() throws ExoPlaybackException { + // Do nothing. + } + + @Override + public final void stop() throws ExoPlaybackException { + Assertions.checkState(state == STATE_STARTED); + state = STATE_ENABLED; + onStopped(); + } + + /** + * Called when the renderer is stopped. + *
+ * The default implementation is a no-op. + * + * @throws ExoPlaybackException If an error occurs. + */ + protected void onStopped() throws ExoPlaybackException { + // Do nothing. + } + + @Override + public final void disable() { + Assertions.checkState(state == STATE_ENABLED); + state = STATE_DISABLED; + onDisabled(); + stream = null; + streamIsFinal = false; + } + + /** + * Called when the renderer is disabled. + *
+ * The default implementation is a no-op. + */ + protected void onDisabled() { + // Do nothing. + } + + @Override + public final void maybeThrowStreamError() throws IOException { + stream.maybeThrowError(); + } + + // RendererCapabilities implementation. + + @Override + public int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException { + return ADAPTIVE_NOT_SUPPORTED; + } + + // ExoPlayerComponent implementation. + + @Override + public void handleMessage(int what, Object object) throws ExoPlaybackException { + // Do nothing. + } + + // Methods to be called by subclasses. + + /** + * Reads from the enabled upstream source. + * + * @see SampleStream#readData(FormatHolder, DecoderInputBuffer) + */ + protected final int readSource(FormatHolder formatHolder, DecoderInputBuffer buffer) { + int result = stream.readData(formatHolder, buffer); + if (result == C.RESULT_BUFFER_READ) { + if (buffer.isEndOfStream()) { + readEndOfStream = true; + return streamIsFinal ? C.RESULT_BUFFER_READ : C.RESULT_NOTHING_READ; + } + buffer.timeUs += streamOffsetUs; + } + return result; + } + + /** + * Returns whether the upstream source is ready. + * + * @return True if the source is ready. False otherwise. + */ + protected final boolean isSourceReady() { + return readEndOfStream ? streamIsFinal : stream.isReady(); + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 88d9e38c89..bf66b6275a 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -717,12 +717,12 @@ import java.util.ArrayList; for (int j = 0; j < formats.length; j++) { formats[j] = groups.get(newSelection.group).getFormat(newSelection.getTrack(j)); } - renderer.replaceSampleStream(formats, readingPeriod.sampleStreams[i], + renderer.replaceStream(formats, readingPeriod.sampleStreams[i], readingPeriod.offsetUs); } else { // The renderer will be disabled when transitioning to playing the next period. Mark // the SampleStream as final to play out any remaining data. - renderer.setCurrentSampleStreamIsFinal(); + renderer.setCurrentStreamIsFinal(); } } } @@ -731,7 +731,7 @@ import java.util.ArrayList; readingPeriod = null; // This is the last period, so signal the renderers to read the end of the stream. for (Renderer renderer : enabledRenderers) { - renderer.setCurrentSampleStreamIsFinal(); + renderer.setCurrentStreamIsFinal(); } } } diff --git a/library/src/main/java/com/google/android/exoplayer2/Renderer.java b/library/src/main/java/com/google/android/exoplayer2/Renderer.java index 14cb29640e..b590875e2c 100644 --- a/library/src/main/java/com/google/android/exoplayer2/Renderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/Renderer.java @@ -16,9 +16,7 @@ package com.google.android.exoplayer2; import com.google.android.exoplayer2.ExoPlayer.ExoPlayerComponent; -import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.source.SampleStream; -import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MediaClock; import java.io.IOException; @@ -34,50 +32,35 @@ import java.io.IOException; * alt="Renderer state transitions" * border="0"/>
*/ -public abstract class Renderer implements ExoPlayerComponent, RendererCapabilities { +public interface Renderer extends ExoPlayerComponent, RendererCapabilities { /** * The renderer is disabled. */ - protected static final int STATE_DISABLED = 0; + int STATE_DISABLED = 0; /** * The renderer is enabled but not started. A renderer in this state will typically hold any * resources that it requires for rendering (e.g. media decoders). */ - protected static final int STATE_ENABLED = 1; + int STATE_ENABLED = 1; /** * The renderer is started. Calls to {@link #render(long, long)} will cause media to be rendered. */ - protected static final int STATE_STARTED = 2; - - private int index; - private int state; - private SampleStream stream; - private long streamOffsetUs; - private boolean readEndOfStream; - private boolean streamIsFinal; - - public Renderer() { - readEndOfStream = true; - } + int STATE_STARTED = 2; /** * Sets the index of this renderer within the player. * * @param index The renderer index. */ - /* package */ final void setIndex(int index) { - this.index = index; - } + void setIndex(int index); /** * Returns the index of the renderer within the player. * * @return The index of the renderer within the player. */ - protected final int getIndex() { - return index; - } + int getIndex(); /** * If the renderer advances its own playback position then this method returns a corresponding @@ -87,18 +70,14 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti * * @return The {@link MediaClock} tracking the playback position of the renderer, or null. */ - protected MediaClock getMediaClock() { - return null; - } + MediaClock getMediaClock(); /** * Returns the current state of the renderer. * * @return The current state (one of the {@code STATE_*} constants). */ - protected final int getState() { - return state; - } + int getState(); /** * Enable the renderer to consume from the specified {@link SampleStream}. @@ -111,26 +90,8 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti * before they are rendered. * @throws ExoPlaybackException If an error occurs. */ - /* package */ final void enable(Format[] formats, SampleStream stream, long positionUs, - boolean joining, long offsetUs) throws ExoPlaybackException { - Assertions.checkState(state == STATE_DISABLED); - state = STATE_ENABLED; - onEnabled(joining); - replaceSampleStream(formats, stream, offsetUs); - onReset(positionUs, joining); - } - - /** - * Called when the renderer is enabled. - *- * The default implementation is a no-op. - * - * @param joining Whether this renderer is being enabled to join an ongoing playback. - * @throws ExoPlaybackException If an error occurs. - */ - protected void onEnabled(boolean joining) throws ExoPlaybackException { - // Do nothing. - } + void enable(Format[] formats, SampleStream stream, long positionUs, boolean joining, + long offsetUs) throws ExoPlaybackException; /** * Sets the {@link SampleStream} from which samples will be consumed. @@ -141,26 +102,8 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti * they are rendered. * @throws ExoPlaybackException If an error occurs. */ - /* package */ final void replaceSampleStream(Format[] formats, SampleStream stream, long offsetUs) - throws ExoPlaybackException { - Assertions.checkState(!streamIsFinal); - this.stream = stream; - readEndOfStream = false; - streamOffsetUs = offsetUs; - onStreamChanged(formats); - } - - /** - * Called when the renderer's stream has changed. - *
- * The default implementation is a no-op. - * - * @param formats The enabled formats. - * @throws ExoPlaybackException Thrown if an error occurs. - */ - protected void onStreamChanged(Format[] formats) throws ExoPlaybackException { - // Do nothing. - } + void replaceStream(Format[] formats, SampleStream stream, long offsetUs) + throws ExoPlaybackException; /** * Called when a reset is encountered. @@ -168,39 +111,18 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti * @param positionUs The playback position in microseconds. * @throws ExoPlaybackException If an error occurs handling the reset. */ - /* package */ final void reset(long positionUs) throws ExoPlaybackException { - streamIsFinal = false; - onReset(positionUs, false); - } - - /** - * Invoked when a reset is encountered, and also when the renderer is enabled. - *
- * This method may be called when the renderer is in the following states: - * {@link #STATE_ENABLED}, {@link #STATE_STARTED}. - * - * @param positionUs The playback position in microseconds. - * @param joining Whether this renderer is being enabled to join an ongoing playback. - * @throws ExoPlaybackException If an error occurs handling the reset. - */ - protected void onReset(long positionUs, boolean joining) throws ExoPlaybackException { - // Do nothing. - } + void reset(long positionUs) throws ExoPlaybackException; /** * Returns whether the renderer has read the current {@link SampleStream} to the end. */ - /* package */ final boolean hasReadStreamToEnd() { - return readEndOfStream; - } + boolean hasReadStreamToEnd(); /** * Signals to the renderer that the current {@link SampleStream} will be the final one supplied * before it is next disabled or reset. */ - /* package */ final void setCurrentSampleStreamIsFinal() { - streamIsFinal = true; - } + void setCurrentStreamIsFinal(); /** * Starts the renderer, meaning that calls to {@link #render(long, long)} will cause media to be @@ -208,66 +130,19 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti * * @throws ExoPlaybackException If an error occurs. */ - /* package */ final void start() throws ExoPlaybackException { - Assertions.checkState(state == STATE_ENABLED); - state = STATE_STARTED; - onStarted(); - } - - /** - * Called when the renderer is started. - *
- * The default implementation is a no-op. - * - * @throws ExoPlaybackException If an error occurs. - */ - protected void onStarted() throws ExoPlaybackException { - // Do nothing. - } + void start() throws ExoPlaybackException; /** * Stops the renderer. * * @throws ExoPlaybackException If an error occurs. */ - /* package */ final void stop() throws ExoPlaybackException { - Assertions.checkState(state == STATE_STARTED); - state = STATE_ENABLED; - onStopped(); - } - - /** - * Called when the renderer is stopped. - *
- * The default implementation is a no-op. - * - * @throws ExoPlaybackException If an error occurs. - */ - protected void onStopped() throws ExoPlaybackException { - // Do nothing. - } + void stop() throws ExoPlaybackException; /** * Disable the renderer. */ - /* package */ final void disable() { - Assertions.checkState(state == STATE_ENABLED); - state = STATE_DISABLED; - onDisabled(); - stream = null; - streamIsFinal = false; - } - - /** - * Called when the renderer is disabled. - *
- * The default implementation is a no-op.
- */
- protected void onDisabled() {
- // Do nothing.
- }
-
- // Methods to be called by subclasses.
+ void disable();
/**
* Throws an error that's preventing the renderer from reading from its {@link SampleStream}. Does
@@ -279,37 +154,7 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti
* @throws IOException An error that's preventing the renderer from making progress or buffering
* more data.
*/
- protected final void maybeThrowStreamError() throws IOException {
- stream.maybeThrowError();
- }
-
- /**
- * Reads from the enabled upstream source.
- *
- * @see SampleStream#readData(FormatHolder, DecoderInputBuffer)
- */
- protected final int readSource(FormatHolder formatHolder, DecoderInputBuffer buffer) {
- int result = stream.readData(formatHolder, buffer);
- if (result == C.RESULT_BUFFER_READ) {
- if (buffer.isEndOfStream()) {
- readEndOfStream = true;
- return streamIsFinal ? C.RESULT_BUFFER_READ : C.RESULT_NOTHING_READ;
- }
- buffer.timeUs += streamOffsetUs;
- }
- return result;
- }
-
- /**
- * Returns whether the upstream source is ready.
- *
- * @return True if the source is ready. False otherwise.
- */
- protected final boolean isSourceReady() {
- return readEndOfStream ? streamIsFinal : stream.isReady();
- }
-
- // Abstract methods.
+ void maybeThrowStreamError() throws IOException;
/**
* Incrementally renders the {@link SampleStream}.
@@ -326,8 +171,7 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti
* measured at the start of the current iteration of the rendering loop.
* @throws ExoPlaybackException If an error occurs.
*/
- protected abstract void render(long positionUs, long elapsedRealtimeUs)
- throws ExoPlaybackException;
+ void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException;
/**
* Whether the renderer is able to immediately render media from the current position.
@@ -344,7 +188,7 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti
*
* @return True if the renderer is ready to render media. False otherwise.
*/
- protected abstract boolean isReady();
+ boolean isReady();
/**
* Whether the renderer is ready for the {@link ExoPlayer} instance to transition to
@@ -356,20 +200,6 @@ public abstract class Renderer implements ExoPlayerComponent, RendererCapabiliti
*
* @return Whether the renderer is ready for the player to transition to the ended state.
*/
- protected abstract boolean isEnded();
-
- // RendererCapabilities implementation
-
- @Override
- public int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException {
- return ADAPTIVE_NOT_SUPPORTED;
- }
-
- // ExoPlayerComponent implementation.
-
- @Override
- public void handleMessage(int what, Object object) throws ExoPlaybackException {
- // Do nothing.
- }
+ boolean isEnded();
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
index 35b3086fcd..fc772c9b63 100644
--- a/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
@@ -18,7 +18,6 @@ package com.google.android.exoplayer2.audio;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
-import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
@@ -210,7 +209,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
@Override
- protected MediaClock getMediaClock() {
+ public MediaClock getMediaClock() {
return this;
}
@@ -300,12 +299,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
@Override
- protected boolean isEnded() {
+ public boolean isEnded() {
return super.isEnded() && !audioTrack.hasPendingData();
}
@Override
- protected boolean isReady() {
+ public boolean isReady() {
return audioTrack.hasPendingData() || super.isReady();
}
@@ -351,14 +350,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} catch (AudioTrack.InitializationException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
- if (getState() == Renderer.STATE_STARTED) {
+ if (getState() == STATE_STARTED) {
audioTrack.play();
}
} else {
// Check for AudioTrack underrun.
boolean audioTrackHadData = audioTrackHasData;
audioTrackHasData = audioTrack.hasPendingData();
- if (audioTrackHadData && !audioTrackHasData && getState() == Renderer.STATE_STARTED) {
+ if (audioTrackHadData && !audioTrackHasData && getState() == STATE_STARTED) {
long elapsedSinceLastFeedMs = SystemClock.elapsedRealtime() - lastFeedElapsedRealtimeMs;
long bufferSizeUs = audioTrack.getBufferSizeUs();
long bufferSizeMs = bufferSizeUs == C.UNSET_TIME_US ? -1 : bufferSizeUs / 1000;
diff --git a/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java
index 0f871cd1c3..20fe038f0f 100644
--- a/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java
@@ -15,11 +15,11 @@
*/
package com.google.android.exoplayer2.audio;
+import com.google.android.exoplayer2.BaseRenderer;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
-import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
@@ -37,7 +37,7 @@ import android.os.SystemClock;
/**
* Decodes and renders audio using a {@link SimpleDecoder}.
*/
-public abstract class SimpleDecoderAudioRenderer extends Renderer implements MediaClock {
+public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements MediaClock {
private final EventDispatcher eventDispatcher;
private final FormatHolder formatHolder;
@@ -92,12 +92,12 @@ public abstract class SimpleDecoderAudioRenderer extends Renderer implements Med
}
@Override
- protected MediaClock getMediaClock() {
+ public MediaClock getMediaClock() {
return this;
}
@Override
- protected void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
+ public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
if (outputStreamEnded) {
return;
}
@@ -192,14 +192,14 @@ public abstract class SimpleDecoderAudioRenderer extends Renderer implements Med
onAudioSessionId(audioSessionId);
}
audioTrackHasData = false;
- if (getState() == Renderer.STATE_STARTED) {
+ if (getState() == STATE_STARTED) {
audioTrack.play();
}
} else {
// Check for AudioTrack underrun.
boolean audioTrackHadData = audioTrackHasData;
audioTrackHasData = audioTrack.hasPendingData();
- if (audioTrackHadData && !audioTrackHasData && getState() == Renderer.STATE_STARTED) {
+ if (audioTrackHadData && !audioTrackHasData && getState() == STATE_STARTED) {
long elapsedSinceLastFeedMs = SystemClock.elapsedRealtime() - lastFeedElapsedRealtimeMs;
long bufferSizeUs = audioTrack.getBufferSizeUs();
long bufferSizeMs = bufferSizeUs == C.UNSET_TIME_US ? -1 : bufferSizeUs / 1000;
@@ -270,12 +270,12 @@ public abstract class SimpleDecoderAudioRenderer extends Renderer implements Med
}
@Override
- protected boolean isEnded() {
+ public boolean isEnded() {
return outputStreamEnded && !audioTrack.hasPendingData();
}
@Override
- protected boolean isReady() {
+ public boolean isReady() {
return audioTrack.hasPendingData()
|| (inputFormat != null && (isSourceReady() || outputBuffer != null));
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
index 44a6cfa2c0..4043214e97 100644
--- a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
@@ -15,11 +15,11 @@
*/
package com.google.android.exoplayer2.mediacodec;
+import com.google.android.exoplayer2.BaseRenderer;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
-import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmSession;
@@ -46,10 +46,10 @@ import java.util.ArrayList;
import java.util.List;
/**
- * An abstract {@link Renderer} that uses {@link MediaCodec} to decode samples for rendering.
+ * An abstract renderer that uses {@link MediaCodec} to decode samples for rendering.
*/
@TargetApi(16)
-public abstract class MediaCodecRenderer extends Renderer {
+public abstract class MediaCodecRenderer extends BaseRenderer {
/**
* Thrown when a failure occurs instantiating a decoder.
@@ -361,7 +361,7 @@ public abstract class MediaCodecRenderer extends Renderer {
throwDecoderInitError(new DecoderInitializationException(format, e,
drmSessionRequiresSecureDecoder, codecName));
}
- codecHotswapDeadlineMs = getState() == Renderer.STATE_STARTED
+ codecHotswapDeadlineMs = getState() == STATE_STARTED
? (SystemClock.elapsedRealtime() + MAX_CODEC_HOTSWAP_TIME_MS) : -1;
inputIndex = -1;
outputIndex = -1;
@@ -452,7 +452,7 @@ public abstract class MediaCodecRenderer extends Renderer {
}
@Override
- protected void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
+ public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
if (format == null) {
readFormat();
}
@@ -780,12 +780,12 @@ public abstract class MediaCodecRenderer extends Renderer {
}
@Override
- protected boolean isEnded() {
+ public boolean isEnded() {
return outputStreamEnded;
}
@Override
- protected boolean isReady() {
+ public boolean isReady() {
return format != null && !waitingForKeys && (isSourceReady() || outputIndex >= 0
|| (SystemClock.elapsedRealtime() < codecHotswapDeadlineMs));
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java b/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java
index a35e9931a5..d52a9e1a48 100644
--- a/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java
@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.Renderer;
+import com.google.android.exoplayer2.BaseRenderer;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.util.Assertions;
@@ -35,7 +36,7 @@ import java.nio.ByteBuffer;
*
* @param
* Text is parsed from sample data using {@link SubtitleDecoder} instances obtained from a
* {@link SubtitleDecoderFactory}. The actual rendering of each line of text is delegated to a
* {@link Output}.
*/
@TargetApi(16)
-public final class TextRenderer extends Renderer implements Callback {
+public final class TextRenderer extends BaseRenderer implements Callback {
/**
* An output for the renderer.
@@ -106,7 +106,7 @@ public final class TextRenderer extends Renderer implements Callback {
@Override
public int supportsFormat(Format format) {
- return decoderFactory.supportsFormat(format) ? Renderer.FORMAT_HANDLED
+ return decoderFactory.supportsFormat(format) ? FORMAT_HANDLED
: (MimeTypes.isText(format.sampleMimeType) ? FORMAT_UNSUPPORTED_SUBTYPE
: FORMAT_UNSUPPORTED_TYPE);
}
@@ -137,7 +137,7 @@ public final class TextRenderer extends Renderer implements Callback {
}
@Override
- protected void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
+ public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
if (outputStreamEnded) {
return;
}
@@ -151,7 +151,7 @@ public final class TextRenderer extends Renderer implements Callback {
}
}
- if (getState() != Renderer.STATE_STARTED) {
+ if (getState() != STATE_STARTED) {
return;
}
@@ -237,12 +237,12 @@ public final class TextRenderer extends Renderer implements Callback {
}
@Override
- protected boolean isEnded() {
+ public boolean isEnded() {
return outputStreamEnded;
}
@Override
- protected boolean isReady() {
+ public boolean isReady() {
// Don't block playback whilst subtitles are loading.
// Note: To change this behavior, it will be necessary to consider [Internal: b/12949941].
return true;
diff --git a/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
index 70cbf8ef86..d5209db98e 100644
--- a/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
+++ b/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
@@ -244,7 +244,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
@Override
- protected boolean isReady() {
+ public boolean isReady() {
if (renderedFirstFrame && super.isReady()) {
// Ready. If we were joining then we've now joined, so clear the joining deadline.
joiningDeadlineMs = -1;
diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/gts/DashTest.java b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/gts/DashTest.java
index c48ad9ac9f..14d06aec73 100644
--- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/gts/DashTest.java
+++ b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/gts/DashTest.java
@@ -18,7 +18,6 @@ package com.google.android.exoplayer2.playbacktests.gts;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
-import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
@@ -535,8 +534,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2