diff --git a/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java b/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java index ea72abc877..e236c85a26 100644 --- a/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java +++ b/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java @@ -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.MappingTrackSelector.MappedTrackInfo; 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.DefaultHttpDataSourceFactory; 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_LEFT_RIGHT = "left_right"; - private DataSource.Factory dataSourceFactory; private SimpleExoPlayer player; - private MediaSource mediaSource; private DefaultTrackSelector trackSelector; private TrackGroupArray lastSeenTrackGroupArray; - private boolean startAutoPlay; private int startWindow; private long startPosition; - // Activity lifecycle - @Override public void onCreate(Bundle 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); if (sphericalStereoMode != null) { @@ -92,56 +83,34 @@ public class PlayerActivity extends GvrPlayerActivity { } @Override - public void onResume() { - super.onResume(); - if (Util.SDK_INT <= 23 || player == null) { - initializePlayer(); - } - } + protected Player createPlayer() { + Intent intent = getIntent(); + Uri uri = intent.getData(); + DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this); - @Override - public void onPause() { - super.onPause(); - if (Util.SDK_INT <= 23) { - releasePlayer(); - } - } + trackSelector = new DefaultTrackSelector(/* context= */ this); + lastSeenTrackGroupArray = null; - // Internal methods - - private void initializePlayer() { - if (player == null) { - Intent intent = getIntent(); - Uri uri = intent.getData(); - if (!Util.checkCleartextTrafficPermitted(uri)) { - showToast(R.string.error_cleartext_not_permitted); - 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)); - } + player = + new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory) + .setTrackSelector(trackSelector) + .build(); + player.addListener(new PlayerEventListener()); + player.setPlayWhenReady(startAutoPlay); + player.addAnalyticsListener(new EventLogger(trackSelector)); + MediaSource mediaSource = buildMediaSource(uri, intent.getStringExtra(EXTENSION_EXTRA)); boolean haveStartPosition = startWindow != C.INDEX_UNSET; if (haveStartPosition) { player.seekTo(startWindow, startPosition); } player.prepare(mediaSource, !haveStartPosition, false); + return player; } 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); switch (type) { 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() { if (player != null) { startAutoPlay = player.getPlayWhenReady(); diff --git a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java index 5d465b494d..6722eba843 100644 --- a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java +++ b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java @@ -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.SceneRenderer; 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.sdk.base.AndroidCompat; 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 org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** - * Base activity for VR 360 video playback. Before starting the video playback a player needs to be - * set using {@link #setPlayer(Player)}. - */ +/** Base activity for VR 360 video playback. */ public abstract class GvrPlayerActivity extends GvrActivity { 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 PlayerControlView playerControlView; + @CallSuper @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -103,80 +100,14 @@ public abstract class GvrPlayerActivity extends GvrActivity { // using Daydream's exit transition. gvrView.setOnCloseButtonListener(this::finish); - ControllerManager.EventListener listener = - new ControllerManager.EventListener() { - @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); + controllerManager = + new ControllerManager(/* context= */ this, new ControllerManagerEventListener()); Controller controller = controllerManager.getController(); ControllerEventListener controllerEventListener = new ControllerEventListener(controller, pointerRenderer, glViewGroup); 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 @Override protected void onActivityResult(int requestCode, int resultCode, Intent unused) { @@ -185,25 +116,63 @@ public abstract class GvrPlayerActivity extends GvrActivity { } } + @CallSuper @Override protected void 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 protected void onPause() { - Util.castNonNull(controllerManager).stop(); + Assertions.checkNotNull(controllerManager).stop(); + Assertions.checkNotNull(playerControlView).setPlayer(null); + Assertions.checkNotNull(player).release(); + player = null; super.onPause(); } + @CallSuper @Override protected void onDestroy() { - setPlayer(null); releaseSurface(surfaceTexture, surface); 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. */ @SuppressWarnings("nullness:argument.type.incompatible") protected void exit() { @@ -211,7 +180,7 @@ public abstract class GvrPlayerActivity extends GvrActivity { if (daydreamApi != null) { // Use Daydream's exit transition to avoid disorienting the user. This will cause // 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(); } else { 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()); + } + } }