Commit 61a86295 by Oliver Woodman

Fix for video-only playbacks transitioning straight to STATE_ENDED.

The complexity around not enabling the video renderer before it
has a valid surface is because MediaCodecTrackRenderer supports
a "discard" mode where it pulls through and discards samples
without a decoder. This mode means that if the demo app were to
enable the renderer before supplying the surface, the renderer
could discard the first few frames prior to getting the surface,
meaning video rendering wouldn't happen until the following sync
frame.

To get a handle on complexity, I think we're better off just removing
support for this mode, which nicely decouples how the demo app
handles surfaces v.s. how it handles enabling/disabling renderers.
parent 784431f3
......@@ -92,9 +92,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
private DemoPlayer player;
private boolean playerNeedsPrepare;
private boolean autoPlay = true;
private long playerPosition;
private boolean enableBackgroundAudio = false;
private boolean enableBackgroundAudio;
private Uri contentUri;
private int contentType;
......@@ -166,10 +165,10 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
if (!enableBackgroundAudio) {
releasePlayer();
} else {
player.blockingClearSurface();
player.setBackgrounded(true);
}
audioCapabilitiesReceiver.unregister();
shutterView.setVisibility(View.VISIBLE);
}
@Override
......@@ -183,7 +182,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
@Override
public void onClick(View view) {
if (view == retryButton) {
autoPlay = true;
preparePlayer();
}
}
......@@ -192,11 +190,14 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
@Override
public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
this.audioCapabilities = audioCapabilities;
releasePlayer();
autoPlay = true;
preparePlayer();
boolean audioCapabilitiesChanged = !audioCapabilities.equals(this.audioCapabilities);
if (player == null || audioCapabilitiesChanged) {
this.audioCapabilities = audioCapabilities;
releasePlayer();
preparePlayer();
} else if (player != null) {
player.setBackgrounded(false);
}
}
// Internal methods
......@@ -239,15 +240,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
updateButtonVisibilities();
}
player.setSurface(surfaceView.getHolder().getSurface());
maybeStartPlayback();
}
private void maybeStartPlayback() {
if (autoPlay && (player.getSurface().isValid()
|| player.getSelectedTrackIndex(DemoPlayer.TYPE_VIDEO) == DemoPlayer.DISABLED_TRACK)) {
player.setPlayWhenReady(true);
autoPlay = false;
}
player.setPlayWhenReady(true);
}
private void releasePlayer() {
......@@ -468,7 +461,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
public void surfaceCreated(SurfaceHolder holder) {
if (player != null) {
player.setSurface(holder.getSurface());
maybeStartPlayback();
}
}
......
......@@ -179,10 +179,12 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
private Surface surface;
private InternalRendererBuilderCallback builderCallback;
private TrackRenderer videoRenderer;
private int videoTrackToRestore;
private MultiTrackChunkSource[] multiTrackSources;
private String[][] trackNames;
private int[] selectedTracks;
private boolean backgrounded;
private TextListener textListener;
private Id3MetadataListener id3MetadataListener;
......@@ -233,7 +235,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
public void setSurface(Surface surface) {
this.surface = surface;
pushSurfaceAndVideoTrack(false);
pushSurface(false);
}
public Surface getSurface() {
......@@ -242,7 +244,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
public void blockingClearSurface() {
surface = null;
pushSurfaceAndVideoTrack(true);
pushSurface(true);
}
public String[] getTracks(int type) {
......@@ -258,13 +260,23 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
return;
}
selectedTracks[type] = index;
if (type == TYPE_VIDEO) {
pushSurfaceAndVideoTrack(false);
pushTrackSelection(type, true);
if (type == TYPE_TEXT && index == DISABLED_TRACK && textListener != null) {
textListener.onText(null);
}
}
public void setBackgrounded(boolean backgrounded) {
if (this.backgrounded == backgrounded) {
return;
}
this.backgrounded = backgrounded;
if (backgrounded) {
videoTrackToRestore = getSelectedTrackIndex(TYPE_VIDEO);
selectTrack(TYPE_VIDEO, DISABLED_TRACK);
blockingClearSurface();
} else {
pushTrackSelection(type, true);
if (type == TYPE_TEXT && index == DISABLED_TRACK && textListener != null) {
textListener.onText(null);
}
selectTrack(TYPE_VIDEO, videoTrackToRestore);
}
}
......@@ -307,7 +319,8 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
this.trackNames = trackNames;
this.multiTrackSources = multiTrackSources;
rendererBuildingState = RENDERER_BUILDING_STATE_BUILT;
pushSurfaceAndVideoTrack(false);
pushSurface(false);
pushTrackSelection(TYPE_VIDEO, true);
pushTrackSelection(TYPE_AUDIO, true);
pushTrackSelection(TYPE_TEXT, true);
player.prepare(renderers);
......@@ -550,7 +563,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
}
}
private void pushSurfaceAndVideoTrack(boolean blockForSurfacePush) {
private void pushSurface(boolean blockForSurfacePush) {
if (rendererBuildingState != RENDERER_BUILDING_STATE_BUILT) {
return;
}
......@@ -562,7 +575,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
player.sendMessage(
videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
}
pushTrackSelection(TYPE_VIDEO, surface != null && surface.isValid());
}
private void pushTrackSelection(int type, boolean allowRendererEnable) {
......
......@@ -440,17 +440,14 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
checkForDiscontinuity();
if (format == null) {
readFormat();
} else if (codec == null && !shouldInitCodec() && getState() == TrackRenderer.STATE_STARTED) {
discardSamples(positionUs);
} else {
if (codec == null && shouldInitCodec()) {
maybeInitCodec();
}
if (codec != null) {
while (drainOutputBuffer(positionUs, elapsedRealtimeUs)) {}
if (feedInputBuffer(true)) {
while (feedInputBuffer(false)) {}
}
}
if (codec == null && shouldInitCodec()) {
maybeInitCodec();
}
if (codec != null) {
while (drainOutputBuffer(positionUs, elapsedRealtimeUs)) {}
if (feedInputBuffer(true)) {
while (feedInputBuffer(false)) {}
}
}
codecCounters.ensureUpdated();
......@@ -466,21 +463,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
}
private void discardSamples(long positionUs) throws IOException, ExoPlaybackException {
sampleHolder.data = null;
int result = SampleSource.SAMPLE_READ;
while (result == SampleSource.SAMPLE_READ && currentPositionUs <= positionUs) {
result = source.readData(trackIndex, currentPositionUs, formatHolder, sampleHolder, false);
if (result == SampleSource.SAMPLE_READ) {
if (!sampleHolder.decodeOnly) {
currentPositionUs = sampleHolder.timeUs;
}
} else if (result == SampleSource.FORMAT_READ) {
onInputFormatChanged(formatHolder);
}
}
}
private void checkForDiscontinuity() throws IOException, ExoPlaybackException {
if (codec == null) {
return;
......
......@@ -353,7 +353,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
@Override
protected boolean shouldInitCodec() {
return super.shouldInitCodec() && surface != null;
return super.shouldInitCodec() && surface != null && surface.isValid();
}
// Override configureCodec to provide the surface.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment