From 61a86295fd3c798e24083acd228d11f832770b68 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Thu, 12 Feb 2015 17:02:34 +0000 Subject: [PATCH] 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. --- .../exoplayer/demo/PlayerActivity.java | 32 +++++++---------- .../exoplayer/demo/player/DemoPlayer.java | 34 +++++++++++++------ .../exoplayer/MediaCodecTrackRenderer.java | 34 +++++-------------- .../MediaCodecVideoTrackRenderer.java | 2 +- 4 files changed, 44 insertions(+), 58 deletions(-) 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 6c5bb7536a..6f04db8991 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 @@ -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(); } } 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 e20b87c21a..338ec5b1db 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 @@ -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) { 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 6cbd6248a1..dd56d54050 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java @@ -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; diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java index 397f83cb88..685b32eff3 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java @@ -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.