mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Support efficient switching between SimpleExoPlayerView instances
Prior to this change, the only way to switch SimpleExoPlayerView was to do: oldView.setPlayer(null); newView.setPlayer(player); This would cause the video renderer to have to transition through oldSurface->noSurface->newSurface, which is inefficient (noSurface requires platform decoders to be fully released). After this change we support: newView.setPlayer(player); oldView.setPlayer(null); This results in direct oldSurface->newSurface transitions, which are seamless on Android M and above. The change also adds some robustness against developers ending up with strange behavior as a result of clearing the player from a view in a different ordering than we expect w.r.t. registering of other listeners. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154044976
This commit is contained in:
parent
4c0b539054
commit
8e8a6a2994
2 changed files with 138 additions and 23 deletions
|
|
@ -239,6 +239,18 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||
setVideoSurfaceInternal(surface, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the {@link Surface} onto which video is being rendered if it matches the one passed.
|
||||
* Else does nothing.
|
||||
*
|
||||
* @param surface The surface to clear.
|
||||
*/
|
||||
public void clearVideoSurface(Surface surface) {
|
||||
if (surface != null && surface == this.surface) {
|
||||
setVideoSurface(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SurfaceHolder} that holds the {@link Surface} onto which video will be
|
||||
* rendered. The player will track the lifecycle of the surface automatically.
|
||||
|
|
@ -256,6 +268,18 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the {@link SurfaceHolder} that holds the {@link Surface} onto which video is being
|
||||
* rendered if it matches the one passed. Else does nothing.
|
||||
*
|
||||
* @param surfaceHolder The surface holder to clear.
|
||||
*/
|
||||
public void clearVideoSurfaceHolder(SurfaceHolder surfaceHolder) {
|
||||
if (surfaceHolder != null && surfaceHolder == this.surfaceHolder) {
|
||||
setVideoSurfaceHolder(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SurfaceView} onto which video will be rendered. The player will track the
|
||||
* lifecycle of the surface automatically.
|
||||
|
|
@ -263,7 +287,17 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||
* @param surfaceView The surface view.
|
||||
*/
|
||||
public void setVideoSurfaceView(SurfaceView surfaceView) {
|
||||
setVideoSurfaceHolder(surfaceView.getHolder());
|
||||
setVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the {@link SurfaceView} onto which video is being rendered if it matches the one passed.
|
||||
* Else does nothing.
|
||||
*
|
||||
* @param surfaceView The texture view to clear.
|
||||
*/
|
||||
public void clearVideoSurfaceView(SurfaceView surfaceView) {
|
||||
clearVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -287,6 +321,18 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the {@link TextureView} onto which video is being rendered if it matches the one passed.
|
||||
* Else does nothing.
|
||||
*
|
||||
* @param textureView The texture view to clear.
|
||||
*/
|
||||
public void clearVideoTextureView(TextureView textureView) {
|
||||
if (textureView != null && textureView == this.textureView) {
|
||||
setVideoTextureView(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stream type for audio playback (see {@link C.StreamType} and
|
||||
* {@link android.media.AudioTrack#AudioTrack(int, int, int, int, int, int)}). If the stream type
|
||||
|
|
@ -404,6 +450,57 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||
videoListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the listener receiving video events if it matches the one passed. Else does nothing.
|
||||
*
|
||||
* @param listener The listener to clear.
|
||||
*/
|
||||
public void clearVideoListener(VideoListener listener) {
|
||||
if (videoListener == listener) {
|
||||
videoListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an output to receive text events.
|
||||
*
|
||||
* @param output The output.
|
||||
*/
|
||||
public void setTextOutput(TextRenderer.Output output) {
|
||||
textOutput = output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the output receiving text events if it matches the one passed. Else does nothing.
|
||||
*
|
||||
* @param output The output to clear.
|
||||
*/
|
||||
public void clearTextOutput(TextRenderer.Output output) {
|
||||
if (textOutput == output) {
|
||||
textOutput = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener to receive metadata events.
|
||||
*
|
||||
* @param output The output.
|
||||
*/
|
||||
public void setMetadataOutput(MetadataRenderer.Output output) {
|
||||
metadataOutput = output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the output receiving metadata events if it matches the one passed. Else does nothing.
|
||||
*
|
||||
* @param output The output to clear.
|
||||
*/
|
||||
public void clearMetadataOutput(MetadataRenderer.Output output) {
|
||||
if (metadataOutput == output) {
|
||||
metadataOutput = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener to receive debug events from the video renderer.
|
||||
*
|
||||
|
|
@ -422,24 +519,6 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||
audioDebugListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an output to receive text events.
|
||||
*
|
||||
* @param output The output.
|
||||
*/
|
||||
public void setTextOutput(TextRenderer.Output output) {
|
||||
textOutput = output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener to receive metadata events.
|
||||
*
|
||||
* @param output The output.
|
||||
*/
|
||||
public void setMetadataOutput(MetadataRenderer.Output output) {
|
||||
metadataOutput = output;
|
||||
}
|
||||
|
||||
// ExoPlayer implementation
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import android.content.res.Resources;
|
|||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -319,6 +321,30 @@ public final class SimpleExoPlayerView extends FrameLayout {
|
|||
hideController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the view targeted by a given {@link SimpleExoPlayer}.
|
||||
*
|
||||
* @param player The player whose target view is being switched.
|
||||
* @param oldPlayerView The old view to detach from the player.
|
||||
* @param newPlayerView The new view to attach to the player.
|
||||
*/
|
||||
public static void switchTargetView(@NonNull SimpleExoPlayer player,
|
||||
@Nullable SimpleExoPlayerView oldPlayerView, @Nullable SimpleExoPlayerView newPlayerView) {
|
||||
if (oldPlayerView == newPlayerView) {
|
||||
return;
|
||||
}
|
||||
// We attach the new view before detaching the old one because this ordering allows the player
|
||||
// to swap directly from one surface to another, without transitioning through a state where no
|
||||
// surface is attached. This is significantly more efficient and achieves a more seamless
|
||||
// transition when using platform provided video decoders.
|
||||
if (newPlayerView != null) {
|
||||
newPlayerView.setPlayer(player);
|
||||
}
|
||||
if (oldPlayerView != null) {
|
||||
oldPlayerView.setPlayer(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the player currently set on this view, or null if no player is set.
|
||||
*/
|
||||
|
|
@ -330,6 +356,12 @@ public final class SimpleExoPlayerView extends FrameLayout {
|
|||
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and
|
||||
* {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous
|
||||
* assignments are overridden.
|
||||
* <p>
|
||||
* To transition a {@link SimpleExoPlayer} from targeting one view to another, it's recommended to
|
||||
* use {@link #switchTargetView(SimpleExoPlayer, SimpleExoPlayerView, SimpleExoPlayerView)} rather
|
||||
* than this method. If you do wish to use this method directly, be sure to attach the player to
|
||||
* the new view <em>before</em> calling {@code setPlayer(null)} to detach it from the old one.
|
||||
* This ordering is significantly more efficient and may allow for more seamless transitions.
|
||||
*
|
||||
* @param player The {@link SimpleExoPlayer} to use.
|
||||
*/
|
||||
|
|
@ -338,10 +370,14 @@ public final class SimpleExoPlayerView extends FrameLayout {
|
|||
return;
|
||||
}
|
||||
if (this.player != null) {
|
||||
this.player.setTextOutput(null);
|
||||
this.player.setVideoListener(null);
|
||||
this.player.removeListener(componentListener);
|
||||
this.player.setVideoSurface(null);
|
||||
this.player.clearTextOutput(componentListener);
|
||||
this.player.clearVideoListener(componentListener);
|
||||
if (surfaceView instanceof TextureView) {
|
||||
this.player.clearVideoTextureView((TextureView) surfaceView);
|
||||
} else if (surfaceView instanceof SurfaceView) {
|
||||
this.player.clearVideoSurfaceView((SurfaceView) surfaceView);
|
||||
}
|
||||
}
|
||||
this.player = player;
|
||||
if (useController) {
|
||||
|
|
@ -357,8 +393,8 @@ public final class SimpleExoPlayerView extends FrameLayout {
|
|||
player.setVideoSurfaceView((SurfaceView) surfaceView);
|
||||
}
|
||||
player.setVideoListener(componentListener);
|
||||
player.addListener(componentListener);
|
||||
player.setTextOutput(componentListener);
|
||||
player.addListener(componentListener);
|
||||
maybeShowController(false);
|
||||
updateForCurrentTrackSelections();
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue