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.
This commit is contained in:
Oliver Woodman 2015-02-12 17:02:34 +00:00
parent 784431f3e0
commit 61a86295fd
4 changed files with 44 additions and 58 deletions

View file

@ -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();
}
}

View file

@ -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) {

View file

@ -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;

View file

@ -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.