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, ...@@ -92,9 +92,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
private DemoPlayer player; private DemoPlayer player;
private boolean playerNeedsPrepare; private boolean playerNeedsPrepare;
private boolean autoPlay = true;
private long playerPosition; private long playerPosition;
private boolean enableBackgroundAudio = false; private boolean enableBackgroundAudio;
private Uri contentUri; private Uri contentUri;
private int contentType; private int contentType;
...@@ -166,10 +165,10 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -166,10 +165,10 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
if (!enableBackgroundAudio) { if (!enableBackgroundAudio) {
releasePlayer(); releasePlayer();
} else { } else {
player.blockingClearSurface(); player.setBackgrounded(true);
} }
audioCapabilitiesReceiver.unregister(); audioCapabilitiesReceiver.unregister();
shutterView.setVisibility(View.VISIBLE);
} }
@Override @Override
...@@ -183,7 +182,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -183,7 +182,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (view == retryButton) { if (view == retryButton) {
autoPlay = true;
preparePlayer(); preparePlayer();
} }
} }
...@@ -192,11 +190,14 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -192,11 +190,14 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
@Override @Override
public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) { public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
boolean audioCapabilitiesChanged = !audioCapabilities.equals(this.audioCapabilities);
if (player == null || audioCapabilitiesChanged) {
this.audioCapabilities = audioCapabilities; this.audioCapabilities = audioCapabilities;
releasePlayer(); releasePlayer();
autoPlay = true;
preparePlayer(); preparePlayer();
} else if (player != null) {
player.setBackgrounded(false);
}
} }
// Internal methods // Internal methods
...@@ -239,15 +240,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -239,15 +240,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
updateButtonVisibilities(); updateButtonVisibilities();
} }
player.setSurface(surfaceView.getHolder().getSurface()); 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); player.setPlayWhenReady(true);
autoPlay = false;
}
} }
private void releasePlayer() { private void releasePlayer() {
...@@ -468,7 +461,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -468,7 +461,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) {
if (player != null) { if (player != null) {
player.setSurface(holder.getSurface()); player.setSurface(holder.getSurface());
maybeStartPlayback();
} }
} }
......
...@@ -179,10 +179,12 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi ...@@ -179,10 +179,12 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
private Surface surface; private Surface surface;
private InternalRendererBuilderCallback builderCallback; private InternalRendererBuilderCallback builderCallback;
private TrackRenderer videoRenderer; private TrackRenderer videoRenderer;
private int videoTrackToRestore;
private MultiTrackChunkSource[] multiTrackSources; private MultiTrackChunkSource[] multiTrackSources;
private String[][] trackNames; private String[][] trackNames;
private int[] selectedTracks; private int[] selectedTracks;
private boolean backgrounded;
private TextListener textListener; private TextListener textListener;
private Id3MetadataListener id3MetadataListener; private Id3MetadataListener id3MetadataListener;
...@@ -233,7 +235,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi ...@@ -233,7 +235,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
public void setSurface(Surface surface) { public void setSurface(Surface surface) {
this.surface = surface; this.surface = surface;
pushSurfaceAndVideoTrack(false); pushSurface(false);
} }
public Surface getSurface() { public Surface getSurface() {
...@@ -242,7 +244,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi ...@@ -242,7 +244,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
public void blockingClearSurface() { public void blockingClearSurface() {
surface = null; surface = null;
pushSurfaceAndVideoTrack(true); pushSurface(true);
} }
public String[] getTracks(int type) { public String[] getTracks(int type) {
...@@ -258,14 +260,24 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi ...@@ -258,14 +260,24 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
return; return;
} }
selectedTracks[type] = index; selectedTracks[type] = index;
if (type == TYPE_VIDEO) {
pushSurfaceAndVideoTrack(false);
} else {
pushTrackSelection(type, true); pushTrackSelection(type, true);
if (type == TYPE_TEXT && index == DISABLED_TRACK && textListener != null) { if (type == TYPE_TEXT && index == DISABLED_TRACK && textListener != null) {
textListener.onText(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 {
selectTrack(TYPE_VIDEO, videoTrackToRestore);
}
} }
public void prepare() { public void prepare() {
...@@ -307,7 +319,8 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi ...@@ -307,7 +319,8 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
this.trackNames = trackNames; this.trackNames = trackNames;
this.multiTrackSources = multiTrackSources; this.multiTrackSources = multiTrackSources;
rendererBuildingState = RENDERER_BUILDING_STATE_BUILT; rendererBuildingState = RENDERER_BUILDING_STATE_BUILT;
pushSurfaceAndVideoTrack(false); pushSurface(false);
pushTrackSelection(TYPE_VIDEO, true);
pushTrackSelection(TYPE_AUDIO, true); pushTrackSelection(TYPE_AUDIO, true);
pushTrackSelection(TYPE_TEXT, true); pushTrackSelection(TYPE_TEXT, true);
player.prepare(renderers); player.prepare(renderers);
...@@ -550,7 +563,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi ...@@ -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) { if (rendererBuildingState != RENDERER_BUILDING_STATE_BUILT) {
return; return;
} }
...@@ -562,7 +575,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi ...@@ -562,7 +575,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
player.sendMessage( player.sendMessage(
videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface); videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
} }
pushTrackSelection(TYPE_VIDEO, surface != null && surface.isValid());
} }
private void pushTrackSelection(int type, boolean allowRendererEnable) { private void pushTrackSelection(int type, boolean allowRendererEnable) {
......
...@@ -440,9 +440,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { ...@@ -440,9 +440,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
checkForDiscontinuity(); checkForDiscontinuity();
if (format == null) { if (format == null) {
readFormat(); readFormat();
} else if (codec == null && !shouldInitCodec() && getState() == TrackRenderer.STATE_STARTED) { }
discardSamples(positionUs);
} else {
if (codec == null && shouldInitCodec()) { if (codec == null && shouldInitCodec()) {
maybeInitCodec(); maybeInitCodec();
} }
...@@ -452,7 +450,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { ...@@ -452,7 +450,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
while (feedInputBuffer(false)) {} while (feedInputBuffer(false)) {}
} }
} }
}
codecCounters.ensureUpdated(); codecCounters.ensureUpdated();
} catch (IOException e) { } catch (IOException e) {
throw new ExoPlaybackException(e); throw new ExoPlaybackException(e);
...@@ -466,21 +463,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { ...@@ -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 { private void checkForDiscontinuity() throws IOException, ExoPlaybackException {
if (codec == null) { if (codec == null) {
return; return;
......
...@@ -353,7 +353,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { ...@@ -353,7 +353,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
@Override @Override
protected boolean shouldInitCodec() { protected boolean shouldInitCodec() {
return super.shouldInitCodec() && surface != null; return super.shouldInitCodec() && surface != null && surface.isValid();
} }
// Override configureCodec to provide the surface. // 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