Add 360 video samples to the demo app

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=206747144
This commit is contained in:
eguven 2018-07-31 05:53:23 -07:00 committed by Oliver Woodman
parent 9ec14d1ada
commit 02e9972630
7 changed files with 89 additions and 24 deletions

View file

@ -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"
}
]
}
]

View file

@ -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);

View file

@ -249,6 +249,7 @@ public class SampleChooserActivity extends Activity
ArrayList<UriSample> 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);
}

View file

@ -23,6 +23,8 @@
<string name="error_unrecognized_abr_algorithm">Unrecognized ABR algorithm</string>
<string name="error_unrecognized_stereo_mode">Unrecognized stereo mode</string>
<string name="error_drm_not_supported">Protected content not supported on API levels below 18</string>
<string name="error_drm_unsupported_scheme">This device does not support the required DRM scheme</string>

View file

@ -20,4 +20,8 @@
<item name="android:windowBackground">@android:color/black</item>
</style>
<style name="PlayerTheme.Spherical">
<item name="surface_type">spherical_view</item>
</style>
</resources>

View file

@ -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);

View file

@ -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));
}