mirror of
https://github.com/samsonjs/media.git
synced 2026-04-05 11:15:46 +00:00
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:
parent
784431f3e0
commit
61a86295fd
4 changed files with 44 additions and 58 deletions
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue