Make GvrPlayerActivity call its subclass to instantiate a player
It's more explicit and simpler than having the subclass call up into the activity. PiperOrigin-RevId: 274881350
This commit is contained in:
parent
a2900992c3
commit
7dede17d97
@ -36,7 +36,6 @@ import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
|||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.util.EventLogger;
|
import com.google.android.exoplayer2.util.EventLogger;
|
||||||
@ -52,24 +51,16 @@ public class PlayerActivity extends GvrPlayerActivity {
|
|||||||
public static final String SPHERICAL_STEREO_MODE_TOP_BOTTOM = "top_bottom";
|
public static final String SPHERICAL_STEREO_MODE_TOP_BOTTOM = "top_bottom";
|
||||||
public static final String SPHERICAL_STEREO_MODE_LEFT_RIGHT = "left_right";
|
public static final String SPHERICAL_STEREO_MODE_LEFT_RIGHT = "left_right";
|
||||||
|
|
||||||
private DataSource.Factory dataSourceFactory;
|
|
||||||
private SimpleExoPlayer player;
|
private SimpleExoPlayer player;
|
||||||
private MediaSource mediaSource;
|
|
||||||
private DefaultTrackSelector trackSelector;
|
private DefaultTrackSelector trackSelector;
|
||||||
private TrackGroupArray lastSeenTrackGroupArray;
|
private TrackGroupArray lastSeenTrackGroupArray;
|
||||||
|
|
||||||
private boolean startAutoPlay;
|
private boolean startAutoPlay;
|
||||||
private int startWindow;
|
private int startWindow;
|
||||||
private long startPosition;
|
private long startPosition;
|
||||||
|
|
||||||
// Activity lifecycle
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
String userAgent = Util.getUserAgent(this, "ExoPlayerDemo");
|
|
||||||
dataSourceFactory =
|
|
||||||
new DefaultDataSourceFactory(this, new DefaultHttpDataSourceFactory(userAgent));
|
|
||||||
|
|
||||||
String sphericalStereoMode = getIntent().getStringExtra(SPHERICAL_STEREO_MODE_EXTRA);
|
String sphericalStereoMode = getIntent().getStringExtra(SPHERICAL_STEREO_MODE_EXTRA);
|
||||||
if (sphericalStereoMode != null) {
|
if (sphericalStereoMode != null) {
|
||||||
@ -92,56 +83,34 @@ public class PlayerActivity extends GvrPlayerActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
protected Player createPlayer() {
|
||||||
super.onResume();
|
Intent intent = getIntent();
|
||||||
if (Util.SDK_INT <= 23 || player == null) {
|
Uri uri = intent.getData();
|
||||||
initializePlayer();
|
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
trackSelector = new DefaultTrackSelector(/* context= */ this);
|
||||||
public void onPause() {
|
lastSeenTrackGroupArray = null;
|
||||||
super.onPause();
|
|
||||||
if (Util.SDK_INT <= 23) {
|
|
||||||
releasePlayer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal methods
|
player =
|
||||||
|
new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory)
|
||||||
private void initializePlayer() {
|
.setTrackSelector(trackSelector)
|
||||||
if (player == null) {
|
.build();
|
||||||
Intent intent = getIntent();
|
player.addListener(new PlayerEventListener());
|
||||||
Uri uri = intent.getData();
|
player.setPlayWhenReady(startAutoPlay);
|
||||||
if (!Util.checkCleartextTrafficPermitted(uri)) {
|
player.addAnalyticsListener(new EventLogger(trackSelector));
|
||||||
showToast(R.string.error_cleartext_not_permitted);
|
MediaSource mediaSource = buildMediaSource(uri, intent.getStringExtra(EXTENSION_EXTRA));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this);
|
|
||||||
|
|
||||||
trackSelector = new DefaultTrackSelector(/* context= */ this);
|
|
||||||
lastSeenTrackGroupArray = null;
|
|
||||||
|
|
||||||
player =
|
|
||||||
new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory)
|
|
||||||
.setTrackSelector(trackSelector)
|
|
||||||
.build();
|
|
||||||
player.addListener(new PlayerEventListener());
|
|
||||||
player.setPlayWhenReady(startAutoPlay);
|
|
||||||
player.addAnalyticsListener(new EventLogger(trackSelector));
|
|
||||||
setPlayer(player);
|
|
||||||
|
|
||||||
mediaSource = buildMediaSource(uri, intent.getStringExtra(EXTENSION_EXTRA));
|
|
||||||
}
|
|
||||||
boolean haveStartPosition = startWindow != C.INDEX_UNSET;
|
boolean haveStartPosition = startWindow != C.INDEX_UNSET;
|
||||||
if (haveStartPosition) {
|
if (haveStartPosition) {
|
||||||
player.seekTo(startWindow, startPosition);
|
player.seekTo(startWindow, startPosition);
|
||||||
}
|
}
|
||||||
player.prepare(mediaSource, !haveStartPosition, false);
|
player.prepare(mediaSource, !haveStartPosition, false);
|
||||||
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
|
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
|
||||||
|
String userAgent = Util.getUserAgent(this, "ExoPlayerVrDemo");
|
||||||
|
DefaultDataSourceFactory dataSourceFactory =
|
||||||
|
new DefaultDataSourceFactory(this, new DefaultHttpDataSourceFactory(userAgent));
|
||||||
@ContentType int type = Util.inferContentType(uri, overrideExtension);
|
@ContentType int type = Util.inferContentType(uri, overrideExtension);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case C.TYPE_DASH:
|
case C.TYPE_DASH:
|
||||||
@ -157,16 +126,6 @@ public class PlayerActivity extends GvrPlayerActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releasePlayer() {
|
|
||||||
if (player != null) {
|
|
||||||
updateStartPosition();
|
|
||||||
player.release();
|
|
||||||
player = null;
|
|
||||||
mediaSource = null;
|
|
||||||
trackSelector = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateStartPosition() {
|
private void updateStartPosition() {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
startAutoPlay = player.getPlayWhenReady();
|
startAutoPlay = player.getPlayWhenReady();
|
||||||
|
@ -34,7 +34,6 @@ import com.google.android.exoplayer2.ui.spherical.GlViewGroup;
|
|||||||
import com.google.android.exoplayer2.ui.spherical.PointerRenderer;
|
import com.google.android.exoplayer2.ui.spherical.PointerRenderer;
|
||||||
import com.google.android.exoplayer2.ui.spherical.SceneRenderer;
|
import com.google.android.exoplayer2.ui.spherical.SceneRenderer;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
|
||||||
import com.google.vr.ndk.base.DaydreamApi;
|
import com.google.vr.ndk.base.DaydreamApi;
|
||||||
import com.google.vr.sdk.base.AndroidCompat;
|
import com.google.vr.sdk.base.AndroidCompat;
|
||||||
import com.google.vr.sdk.base.Eye;
|
import com.google.vr.sdk.base.Eye;
|
||||||
@ -48,10 +47,7 @@ import com.google.vr.sdk.controller.Orientation;
|
|||||||
import javax.microedition.khronos.egl.EGLConfig;
|
import javax.microedition.khronos.egl.EGLConfig;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/** Base activity for VR 360 video playback. */
|
||||||
* Base activity for VR 360 video playback. Before starting the video playback a player needs to be
|
|
||||||
* set using {@link #setPlayer(Player)}.
|
|
||||||
*/
|
|
||||||
public abstract class GvrPlayerActivity extends GvrActivity {
|
public abstract class GvrPlayerActivity extends GvrActivity {
|
||||||
|
|
||||||
private static final int EXIT_FROM_VR_REQUEST_CODE = 42;
|
private static final int EXIT_FROM_VR_REQUEST_CODE = 42;
|
||||||
@ -63,6 +59,7 @@ public abstract class GvrPlayerActivity extends GvrActivity {
|
|||||||
private @MonotonicNonNull SceneRenderer sceneRenderer;
|
private @MonotonicNonNull SceneRenderer sceneRenderer;
|
||||||
private @MonotonicNonNull PlayerControlView playerControlView;
|
private @MonotonicNonNull PlayerControlView playerControlView;
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -103,80 +100,14 @@ public abstract class GvrPlayerActivity extends GvrActivity {
|
|||||||
// using Daydream's exit transition.
|
// using Daydream's exit transition.
|
||||||
gvrView.setOnCloseButtonListener(this::finish);
|
gvrView.setOnCloseButtonListener(this::finish);
|
||||||
|
|
||||||
ControllerManager.EventListener listener =
|
controllerManager =
|
||||||
new ControllerManager.EventListener() {
|
new ControllerManager(/* context= */ this, new ControllerManagerEventListener());
|
||||||
@Override
|
|
||||||
public void onApiStatusChanged(int status) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRecentered() {
|
|
||||||
// TODO: If in cardboard mode call gvrView.recenterHeadTracker().
|
|
||||||
runOnUiThread(() -> Util.castNonNull(playerControlView).show());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
controllerManager = new ControllerManager(this, listener);
|
|
||||||
Controller controller = controllerManager.getController();
|
Controller controller = controllerManager.getController();
|
||||||
ControllerEventListener controllerEventListener =
|
ControllerEventListener controllerEventListener =
|
||||||
new ControllerEventListener(controller, pointerRenderer, glViewGroup);
|
new ControllerEventListener(controller, pointerRenderer, glViewGroup);
|
||||||
controller.setEventListener(controllerEventListener);
|
controller.setEventListener(controllerEventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link Player} to use.
|
|
||||||
*
|
|
||||||
* @param newPlayer The {@link Player} to use, or {@code null} to detach the current player.
|
|
||||||
*/
|
|
||||||
protected void setPlayer(@Nullable Player newPlayer) {
|
|
||||||
Assertions.checkNotNull(sceneRenderer);
|
|
||||||
if (player == newPlayer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (player != null) {
|
|
||||||
Player.VideoComponent videoComponent = player.getVideoComponent();
|
|
||||||
if (videoComponent != null) {
|
|
||||||
if (surface != null) {
|
|
||||||
videoComponent.clearVideoSurface(surface);
|
|
||||||
}
|
|
||||||
videoComponent.clearVideoFrameMetadataListener(sceneRenderer);
|
|
||||||
videoComponent.clearCameraMotionListener(sceneRenderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
player = newPlayer;
|
|
||||||
if (player != null) {
|
|
||||||
Player.VideoComponent videoComponent = player.getVideoComponent();
|
|
||||||
if (videoComponent != null) {
|
|
||||||
videoComponent.setVideoFrameMetadataListener(sceneRenderer);
|
|
||||||
videoComponent.setCameraMotionListener(sceneRenderer);
|
|
||||||
videoComponent.setVideoSurface(surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Assertions.checkNotNull(playerControlView).setPlayer(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default stereo mode. If the played video doesn't contain a stereo mode the default one
|
|
||||||
* is used.
|
|
||||||
*
|
|
||||||
* @param stereoMode A {@link C.StereoMode} value.
|
|
||||||
*/
|
|
||||||
protected void setDefaultStereoMode(@C.StereoMode int stereoMode) {
|
|
||||||
Assertions.checkNotNull(sceneRenderer).setDefaultStereoMode(stereoMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the render target scale passed to {@link GvrView#setRenderTargetScale(float)}. Since
|
|
||||||
* videos typically have fewer pixels per degree than the phone displays, the target can normally
|
|
||||||
* be lower than 1 to reduce the amount of work required to render the scene. The default value is
|
|
||||||
* 0.5.
|
|
||||||
*
|
|
||||||
* @return The render target scale passed to {@link GvrView#setRenderTargetScale(float)}.
|
|
||||||
*/
|
|
||||||
protected float getRenderTargetScale() {
|
|
||||||
return 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent unused) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent unused) {
|
||||||
@ -185,25 +116,63 @@ public abstract class GvrPlayerActivity extends GvrActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
Util.castNonNull(controllerManager).start();
|
player = createPlayer();
|
||||||
|
Player.VideoComponent videoComponent = player.getVideoComponent();
|
||||||
|
if (videoComponent != null) {
|
||||||
|
videoComponent.setVideoFrameMetadataListener(Assertions.checkNotNull(sceneRenderer));
|
||||||
|
videoComponent.setCameraMotionListener(sceneRenderer);
|
||||||
|
videoComponent.setVideoSurface(surface);
|
||||||
|
}
|
||||||
|
Assertions.checkNotNull(playerControlView).setPlayer(player);
|
||||||
|
Assertions.checkNotNull(controllerManager).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
Util.castNonNull(controllerManager).stop();
|
Assertions.checkNotNull(controllerManager).stop();
|
||||||
|
Assertions.checkNotNull(playerControlView).setPlayer(null);
|
||||||
|
Assertions.checkNotNull(player).release();
|
||||||
|
player = null;
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
setPlayer(null);
|
|
||||||
releaseSurface(surfaceTexture, surface);
|
releaseSurface(surfaceTexture, surface);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by {@link #onCreate(Bundle)} to get the render target scale value that will be passed to
|
||||||
|
* {@link GvrView#setRenderTargetScale(float)}. Since videos typically have fewer pixels per
|
||||||
|
* degree than the phone displays, the target can normally be lower than 1 to reduce the amount of
|
||||||
|
* work required to render the scene. The default value is 0.5.
|
||||||
|
*
|
||||||
|
* @return The render target scale value that will be passed to {@link
|
||||||
|
* GvrView#setRenderTargetScale(float)}.
|
||||||
|
*/
|
||||||
|
protected float getRenderTargetScale() {
|
||||||
|
return 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called by {@link #onResume()} to create a player instance for this activity to use. */
|
||||||
|
protected abstract Player createPlayer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the stereo mode that will be used for video content that does not specify its own mode.
|
||||||
|
*
|
||||||
|
* @param stereoMode The default {@link C.StereoMode}.
|
||||||
|
*/
|
||||||
|
protected void setDefaultStereoMode(@C.StereoMode int stereoMode) {
|
||||||
|
Assertions.checkNotNull(sceneRenderer).setDefaultStereoMode(stereoMode);
|
||||||
|
}
|
||||||
|
|
||||||
/** Tries to exit gracefully from VR using a VR transition dialog. */
|
/** Tries to exit gracefully from VR using a VR transition dialog. */
|
||||||
@SuppressWarnings("nullness:argument.type.incompatible")
|
@SuppressWarnings("nullness:argument.type.incompatible")
|
||||||
protected void exit() {
|
protected void exit() {
|
||||||
@ -211,7 +180,7 @@ public abstract class GvrPlayerActivity extends GvrActivity {
|
|||||||
if (daydreamApi != null) {
|
if (daydreamApi != null) {
|
||||||
// Use Daydream's exit transition to avoid disorienting the user. This will cause
|
// Use Daydream's exit transition to avoid disorienting the user. This will cause
|
||||||
// onActivityResult to be called.
|
// onActivityResult to be called.
|
||||||
daydreamApi.exitFromVr(/* activity= */ this, EXIT_FROM_VR_REQUEST_CODE, /* intent= */ null);
|
daydreamApi.exitFromVr(/* activity= */ this, EXIT_FROM_VR_REQUEST_CODE, /* data= */ null);
|
||||||
daydreamApi.close();
|
daydreamApi.close();
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
@ -356,4 +325,18 @@ public abstract class GvrPlayerActivity extends GvrActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class ControllerManagerEventListener implements ControllerManager.EventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApiStatusChanged(int status) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRecentered() {
|
||||||
|
// TODO: If in cardboard mode call gvrView.recenterHeadTracker().
|
||||||
|
runOnUiThread(() -> Assertions.checkNotNull(playerControlView).show());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user