From 02e9972630c5df0422d1827044f9b907002d205d Mon Sep 17 00:00:00 2001 From: eguven Date: Tue, 31 Jul 2018 05:53:23 -0700 Subject: [PATCH] Add 360 video samples to the demo app ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=206747144 --- demos/main/src/main/assets/media.exolist.json | 15 ++++++++++ .../exoplayer2/demo/PlayerActivity.java | 25 ++++++++++++++++ .../demo/SampleChooserActivity.java | 21 ++++++++++++-- demos/main/src/main/res/values/strings.xml | 2 ++ demos/main/src/main/res/values/styles.xml | 4 +++ .../android/exoplayer2/ui/spherical/Mesh.java | 29 +++++-------------- .../ui/spherical/SphericalSurfaceView.java | 17 ++++++++++- 7 files changed, 89 insertions(+), 24 deletions(-) diff --git a/demos/main/src/main/assets/media.exolist.json b/demos/main/src/main/assets/media.exolist.json index 0d26f196c1..265eff3aef 100644 --- a/demos/main/src/main/assets/media.exolist.json +++ b/demos/main/src/main/assets/media.exolist.json @@ -589,5 +589,20 @@ "abr_algorithm": "random" } ] + }, + { + "name": "360", + "samples": [ + { + "name": "Congo (360 top-bottom stereo)", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/360/congo.mp4", + "spherical_stereo_mode": "top_bottom" + }, + { + "name": "Iceland (360 top-bottom stereo ts)", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/360/iceland0.ts", + "spherical_stereo_mode": "top_bottom" + } + ] } ] diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index ca3eb079b8..3081b2dc4f 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -73,6 +73,7 @@ import com.google.android.exoplayer2.ui.DebugTextViewHelper; import com.google.android.exoplayer2.ui.PlayerControlView; import com.google.android.exoplayer2.ui.PlayerView; import com.google.android.exoplayer2.ui.TrackSelectionView; +import com.google.android.exoplayer2.ui.spherical.SphericalSurfaceView; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.ErrorMessageProvider; @@ -109,6 +110,11 @@ public class PlayerActivity extends Activity private static final String ABR_ALGORITHM_DEFAULT = "default"; private static final String ABR_ALGORITHM_RANDOM = "random"; + public static final String SPHERICAL_STEREO_MODE_EXTRA = "spherical_stereo_mode"; + public static final String SPHERICAL_STEREO_MODE_MONO = "mono"; + public static final String SPHERICAL_STEREO_MODE_TOP_BOTTOM = "top_bottom"; + public static final String SPHERICAL_STEREO_MODE_LEFT_RIGHT = "left_right"; + // For backwards compatibility only. private static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid"; @@ -151,6 +157,10 @@ public class PlayerActivity extends Activity @Override public void onCreate(Bundle savedInstanceState) { + String sphericalStereoMode = getIntent().getStringExtra(SPHERICAL_STEREO_MODE_EXTRA); + if (sphericalStereoMode != null) { + setTheme(R.style.PlayerTheme_Spherical); + } super.onCreate(savedInstanceState); dataSourceFactory = buildDataSourceFactory(); if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) { @@ -167,6 +177,21 @@ public class PlayerActivity extends Activity playerView.setControllerVisibilityListener(this); playerView.setErrorMessageProvider(new PlayerErrorMessageProvider()); playerView.requestFocus(); + if (sphericalStereoMode != null) { + int stereoMode; + if (SPHERICAL_STEREO_MODE_MONO.equals(sphericalStereoMode)) { + stereoMode = C.STEREO_MODE_MONO; + } else if (SPHERICAL_STEREO_MODE_TOP_BOTTOM.equals(sphericalStereoMode)) { + stereoMode = C.STEREO_MODE_TOP_BOTTOM; + } else if (SPHERICAL_STEREO_MODE_LEFT_RIGHT.equals(sphericalStereoMode)) { + stereoMode = C.STEREO_MODE_LEFT_RIGHT; + } else { + showToast(R.string.error_unrecognized_stereo_mode); + finish(); + return; + } + ((SphericalSurfaceView) playerView.getVideoSurfaceView()).setStereoMode(stereoMode); + } if (savedInstanceState != null) { trackSelectorParameters = savedInstanceState.getParcelable(KEY_TRACK_SELECTOR_PARAMETERS); diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java index d87fca8e58..2b71d7af37 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java @@ -249,6 +249,7 @@ public class SampleChooserActivity extends Activity ArrayList playlistSamples = null; String adTagUri = null; String abrAlgorithm = null; + String sphericalStereoMode = null; reader.beginObject(); while (reader.hasNext()) { @@ -309,6 +310,11 @@ public class SampleChooserActivity extends Activity !insidePlaylist, "Invalid attribute on nested item: abr_algorithm"); abrAlgorithm = reader.nextString(); break; + case "spherical_stereo_mode": + Assertions.checkState( + !insidePlaylist, "Invalid attribute on nested item: spherical_stereo_mode"); + sphericalStereoMode = reader.nextString(); + break; default: throw new ParserException("Unsupported attribute name: " + name); } @@ -325,7 +331,14 @@ public class SampleChooserActivity extends Activity sampleName, preferExtensionDecoders, abrAlgorithm, drmInfo, playlistSamplesArray); } else { return new UriSample( - sampleName, preferExtensionDecoders, abrAlgorithm, drmInfo, uri, extension, adTagUri); + sampleName, + preferExtensionDecoders, + abrAlgorithm, + drmInfo, + uri, + extension, + adTagUri, + sphericalStereoMode); } } @@ -512,6 +525,7 @@ public class SampleChooserActivity extends Activity public final Uri uri; public final String extension; public final String adTagUri; + public final String sphericalStereoMode; public UriSample( String name, @@ -520,11 +534,13 @@ public class SampleChooserActivity extends Activity DrmInfo drmInfo, Uri uri, String extension, - String adTagUri) { + String adTagUri, + String sphericalStereoMode) { super(name, preferExtensionDecoders, abrAlgorithm, drmInfo); this.uri = uri; this.extension = extension; this.adTagUri = adTagUri; + this.sphericalStereoMode = sphericalStereoMode; } @Override @@ -533,6 +549,7 @@ public class SampleChooserActivity extends Activity .setData(uri) .putExtra(PlayerActivity.EXTENSION_EXTRA, extension) .putExtra(PlayerActivity.AD_TAG_URI_EXTRA, adTagUri) + .putExtra(PlayerActivity.SPHERICAL_STEREO_MODE_EXTRA, sphericalStereoMode) .setAction(PlayerActivity.ACTION_VIEW); } diff --git a/demos/main/src/main/res/values/strings.xml b/demos/main/src/main/res/values/strings.xml index eb260e6ffc..beca93cfbc 100644 --- a/demos/main/src/main/res/values/strings.xml +++ b/demos/main/src/main/res/values/strings.xml @@ -23,6 +23,8 @@ Unrecognized ABR algorithm + Unrecognized stereo mode + Protected content not supported on API levels below 18 This device does not support the required DRM scheme diff --git a/demos/main/src/main/res/values/styles.xml b/demos/main/src/main/res/values/styles.xml index 5616bb9869..25d826bdf6 100644 --- a/demos/main/src/main/res/values/styles.xml +++ b/demos/main/src/main/res/values/styles.xml @@ -20,4 +20,8 @@ @android:color/black + + diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/Mesh.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/Mesh.java index dc996b36eb..29bfa92743 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/Mesh.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/Mesh.java @@ -32,7 +32,7 @@ import java.nio.FloatBuffer; /*package*/ final class Mesh { /** Defines the constants identifying the current eye type. */ - public interface EyeType { + /*package*/ interface EyeType { /** Single eye in monocular rendering. */ int MONOCULAR = 0; @@ -43,19 +43,6 @@ import java.nio.FloatBuffer; int RIGHT = 2; } - /** Standard media where a single camera frame takes up the entire media frame. */ - public static final int MEDIA_MONOSCOPIC = 0; - /** - * Stereo media where the left & right halves of the frame are rendered for the left & right eyes, - * respectively. If the stereo media is rendered in a non-VR display, only the left half is used. - */ - public static final int MEDIA_STEREO_LEFT_RIGHT = 1; - /** - * Stereo media where the top & bottom halves of the frame are rendered for the left & right eyes, - * respectively. If the stereo media is rendered in a non-VR display, only the top half is used. - */ - public static final int MEDIA_STEREO_TOP_BOTTOM = 2; - // Basic vertex & fragment shaders to render a mesh with 3D position & 2D texture data. private static final String[] VERTEX_SHADER_CODE = new String[] { @@ -121,7 +108,7 @@ import java.nio.FloatBuffer; * (0, 180]. * @param horizontalFovDegrees Total longitudinal degrees that are covered by the sphere.Must be * in (0, 360]. - * @param mediaFormat A MEDIA_* value. + * @param stereoMode A {@link C.StereoMode} value. * @return Unintialized Mesh. */ public static Mesh createUvSphere( @@ -130,10 +117,10 @@ import java.nio.FloatBuffer; int longitudes, float verticalFovDegrees, float horizontalFovDegrees, - int mediaFormat) { + @C.StereoMode int stereoMode) { return new Mesh( createUvSphereVertexData( - radius, latitudes, longitudes, verticalFovDegrees, horizontalFovDegrees, mediaFormat)); + radius, latitudes, longitudes, verticalFovDegrees, horizontalFovDegrees, stereoMode)); } /** Used by static constructors. */ @@ -219,7 +206,7 @@ import java.nio.FloatBuffer; int longitudes, float verticalFovDegrees, float horizontalFovDegrees, - int mediaFormat) { + @C.StereoMode int stereoMode) { if (radius <= 0 || latitudes < 1 || longitudes < 1 @@ -258,12 +245,12 @@ import java.nio.FloatBuffer; float theta = quadWidthRads * i + (float) Math.PI - horizontalFovRads / 2; // Set vertex position data as Cartesian coordinates. - vertexData[offset + 0] = -(float) (radius * Math.sin(theta) * Math.cos(phi)); + vertexData[offset] = -(float) (radius * Math.sin(theta) * Math.cos(phi)); vertexData[offset + 1] = (float) (radius * Math.sin(phi)); vertexData[offset + 2] = (float) (radius * Math.cos(theta) * Math.cos(phi)); // Set vertex texture.x data. - if (mediaFormat == MEDIA_STEREO_LEFT_RIGHT) { + if (stereoMode == C.STEREO_MODE_LEFT_RIGHT) { // For left-right media, each eye's x coordinate points to the left or right half of the // texture. vertexData[offset + 3] = (i * quadWidthRads / horizontalFovRads) / 2; @@ -275,7 +262,7 @@ import java.nio.FloatBuffer; } // Set vertex texture.y data. The "1 - ..." is due to Canvas vs GL coords. - if (mediaFormat == MEDIA_STEREO_TOP_BOTTOM) { + if (stereoMode == C.STEREO_MODE_TOP_BOTTOM) { // For top-bottom media, each eye's y coordinate points to the top or bottom half of the // texture. vertexData[offset + 4] = 1 - (((j + k) * quadHeightRads / verticalFovRads) / 2 + .5f); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java index c062896dda..f4386a44c9 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java @@ -36,6 +36,7 @@ import android.util.AttributeSet; import android.view.Display; import android.view.Surface; import android.view.WindowManager; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ui.spherical.Mesh.EyeType; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; @@ -129,6 +130,20 @@ public final class SphericalSurfaceView extends GLSurfaceView { setRenderer(renderer); setOnTouchListener(touchTracker); + setStereoMode(C.STEREO_MODE_MONO); + } + + /** + * Sets stereo mode of the media to be played. + * + * @param stereoMode One of {@link C#STEREO_MODE_MONO}, {@link C#STEREO_MODE_TOP_BOTTOM}, {@link + * C#STEREO_MODE_LEFT_RIGHT}. + */ + public void setStereoMode(@C.StereoMode int stereoMode) { + Assertions.checkState( + stereoMode == C.STEREO_MODE_MONO + || stereoMode == C.STEREO_MODE_TOP_BOTTOM + || stereoMode == C.STEREO_MODE_LEFT_RIGHT); Mesh mesh = Mesh.createUvSphere( SPHERE_RADIUS_METERS, @@ -136,7 +151,7 @@ public final class SphericalSurfaceView extends GLSurfaceView { DEFAULT_SPHERE_COLUMNS, DEFAULT_SPHERE_VERTICAL_DEGREES, DEFAULT_SPHERE_HORIZONTAL_DEGREES, - Mesh.MEDIA_MONOSCOPIC); + stereoMode); queueEvent(() -> renderer.scene.setMesh(mesh)); }