mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
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:
parent
9ec14d1ada
commit
02e9972630
7 changed files with 89 additions and 24 deletions
|
|
@ -589,5 +589,20 @@
|
||||||
"abr_algorithm": "random"
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ import com.google.android.exoplayer2.ui.DebugTextViewHelper;
|
||||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
import com.google.android.exoplayer2.ui.PlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
import com.google.android.exoplayer2.ui.TrackSelectionView;
|
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.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||||
import com.google.android.exoplayer2.util.ErrorMessageProvider;
|
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_DEFAULT = "default";
|
||||||
private static final String ABR_ALGORITHM_RANDOM = "random";
|
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.
|
// For backwards compatibility only.
|
||||||
private static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";
|
private static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";
|
||||||
|
|
||||||
|
|
@ -151,6 +157,10 @@ public class PlayerActivity extends Activity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
String sphericalStereoMode = getIntent().getStringExtra(SPHERICAL_STEREO_MODE_EXTRA);
|
||||||
|
if (sphericalStereoMode != null) {
|
||||||
|
setTheme(R.style.PlayerTheme_Spherical);
|
||||||
|
}
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
dataSourceFactory = buildDataSourceFactory();
|
dataSourceFactory = buildDataSourceFactory();
|
||||||
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
|
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
|
||||||
|
|
@ -167,6 +177,21 @@ public class PlayerActivity extends Activity
|
||||||
playerView.setControllerVisibilityListener(this);
|
playerView.setControllerVisibilityListener(this);
|
||||||
playerView.setErrorMessageProvider(new PlayerErrorMessageProvider());
|
playerView.setErrorMessageProvider(new PlayerErrorMessageProvider());
|
||||||
playerView.requestFocus();
|
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) {
|
if (savedInstanceState != null) {
|
||||||
trackSelectorParameters = savedInstanceState.getParcelable(KEY_TRACK_SELECTOR_PARAMETERS);
|
trackSelectorParameters = savedInstanceState.getParcelable(KEY_TRACK_SELECTOR_PARAMETERS);
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,7 @@ public class SampleChooserActivity extends Activity
|
||||||
ArrayList<UriSample> playlistSamples = null;
|
ArrayList<UriSample> playlistSamples = null;
|
||||||
String adTagUri = null;
|
String adTagUri = null;
|
||||||
String abrAlgorithm = null;
|
String abrAlgorithm = null;
|
||||||
|
String sphericalStereoMode = null;
|
||||||
|
|
||||||
reader.beginObject();
|
reader.beginObject();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
|
|
@ -309,6 +310,11 @@ public class SampleChooserActivity extends Activity
|
||||||
!insidePlaylist, "Invalid attribute on nested item: abr_algorithm");
|
!insidePlaylist, "Invalid attribute on nested item: abr_algorithm");
|
||||||
abrAlgorithm = reader.nextString();
|
abrAlgorithm = reader.nextString();
|
||||||
break;
|
break;
|
||||||
|
case "spherical_stereo_mode":
|
||||||
|
Assertions.checkState(
|
||||||
|
!insidePlaylist, "Invalid attribute on nested item: spherical_stereo_mode");
|
||||||
|
sphericalStereoMode = reader.nextString();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ParserException("Unsupported attribute name: " + name);
|
throw new ParserException("Unsupported attribute name: " + name);
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +331,14 @@ public class SampleChooserActivity extends Activity
|
||||||
sampleName, preferExtensionDecoders, abrAlgorithm, drmInfo, playlistSamplesArray);
|
sampleName, preferExtensionDecoders, abrAlgorithm, drmInfo, playlistSamplesArray);
|
||||||
} else {
|
} else {
|
||||||
return new UriSample(
|
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 Uri uri;
|
||||||
public final String extension;
|
public final String extension;
|
||||||
public final String adTagUri;
|
public final String adTagUri;
|
||||||
|
public final String sphericalStereoMode;
|
||||||
|
|
||||||
public UriSample(
|
public UriSample(
|
||||||
String name,
|
String name,
|
||||||
|
|
@ -520,11 +534,13 @@ public class SampleChooserActivity extends Activity
|
||||||
DrmInfo drmInfo,
|
DrmInfo drmInfo,
|
||||||
Uri uri,
|
Uri uri,
|
||||||
String extension,
|
String extension,
|
||||||
String adTagUri) {
|
String adTagUri,
|
||||||
|
String sphericalStereoMode) {
|
||||||
super(name, preferExtensionDecoders, abrAlgorithm, drmInfo);
|
super(name, preferExtensionDecoders, abrAlgorithm, drmInfo);
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.extension = extension;
|
this.extension = extension;
|
||||||
this.adTagUri = adTagUri;
|
this.adTagUri = adTagUri;
|
||||||
|
this.sphericalStereoMode = sphericalStereoMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -533,6 +549,7 @@ public class SampleChooserActivity extends Activity
|
||||||
.setData(uri)
|
.setData(uri)
|
||||||
.putExtra(PlayerActivity.EXTENSION_EXTRA, extension)
|
.putExtra(PlayerActivity.EXTENSION_EXTRA, extension)
|
||||||
.putExtra(PlayerActivity.AD_TAG_URI_EXTRA, adTagUri)
|
.putExtra(PlayerActivity.AD_TAG_URI_EXTRA, adTagUri)
|
||||||
|
.putExtra(PlayerActivity.SPHERICAL_STEREO_MODE_EXTRA, sphericalStereoMode)
|
||||||
.setAction(PlayerActivity.ACTION_VIEW);
|
.setAction(PlayerActivity.ACTION_VIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
<string name="error_unrecognized_abr_algorithm">Unrecognized ABR algorithm</string>
|
<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_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>
|
<string name="error_drm_unsupported_scheme">This device does not support the required DRM scheme</string>
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,8 @@
|
||||||
<item name="android:windowBackground">@android:color/black</item>
|
<item name="android:windowBackground">@android:color/black</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="PlayerTheme.Spherical">
|
||||||
|
<item name="surface_type">spherical_view</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import java.nio.FloatBuffer;
|
||||||
/*package*/ final class Mesh {
|
/*package*/ final class Mesh {
|
||||||
|
|
||||||
/** Defines the constants identifying the current eye type. */
|
/** Defines the constants identifying the current eye type. */
|
||||||
public interface EyeType {
|
/*package*/ interface EyeType {
|
||||||
/** Single eye in monocular rendering. */
|
/** Single eye in monocular rendering. */
|
||||||
int MONOCULAR = 0;
|
int MONOCULAR = 0;
|
||||||
|
|
||||||
|
|
@ -43,19 +43,6 @@ import java.nio.FloatBuffer;
|
||||||
int RIGHT = 2;
|
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.
|
// Basic vertex & fragment shaders to render a mesh with 3D position & 2D texture data.
|
||||||
private static final String[] VERTEX_SHADER_CODE =
|
private static final String[] VERTEX_SHADER_CODE =
|
||||||
new String[] {
|
new String[] {
|
||||||
|
|
@ -121,7 +108,7 @@ import java.nio.FloatBuffer;
|
||||||
* (0, 180].
|
* (0, 180].
|
||||||
* @param horizontalFovDegrees Total longitudinal degrees that are covered by the sphere.Must be
|
* @param horizontalFovDegrees Total longitudinal degrees that are covered by the sphere.Must be
|
||||||
* in (0, 360].
|
* in (0, 360].
|
||||||
* @param mediaFormat A MEDIA_* value.
|
* @param stereoMode A {@link C.StereoMode} value.
|
||||||
* @return Unintialized Mesh.
|
* @return Unintialized Mesh.
|
||||||
*/
|
*/
|
||||||
public static Mesh createUvSphere(
|
public static Mesh createUvSphere(
|
||||||
|
|
@ -130,10 +117,10 @@ import java.nio.FloatBuffer;
|
||||||
int longitudes,
|
int longitudes,
|
||||||
float verticalFovDegrees,
|
float verticalFovDegrees,
|
||||||
float horizontalFovDegrees,
|
float horizontalFovDegrees,
|
||||||
int mediaFormat) {
|
@C.StereoMode int stereoMode) {
|
||||||
return new Mesh(
|
return new Mesh(
|
||||||
createUvSphereVertexData(
|
createUvSphereVertexData(
|
||||||
radius, latitudes, longitudes, verticalFovDegrees, horizontalFovDegrees, mediaFormat));
|
radius, latitudes, longitudes, verticalFovDegrees, horizontalFovDegrees, stereoMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used by static constructors. */
|
/** Used by static constructors. */
|
||||||
|
|
@ -219,7 +206,7 @@ import java.nio.FloatBuffer;
|
||||||
int longitudes,
|
int longitudes,
|
||||||
float verticalFovDegrees,
|
float verticalFovDegrees,
|
||||||
float horizontalFovDegrees,
|
float horizontalFovDegrees,
|
||||||
int mediaFormat) {
|
@C.StereoMode int stereoMode) {
|
||||||
if (radius <= 0
|
if (radius <= 0
|
||||||
|| latitudes < 1
|
|| latitudes < 1
|
||||||
|| longitudes < 1
|
|| longitudes < 1
|
||||||
|
|
@ -258,12 +245,12 @@ import java.nio.FloatBuffer;
|
||||||
float theta = quadWidthRads * i + (float) Math.PI - horizontalFovRads / 2;
|
float theta = quadWidthRads * i + (float) Math.PI - horizontalFovRads / 2;
|
||||||
|
|
||||||
// Set vertex position data as Cartesian coordinates.
|
// 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 + 1] = (float) (radius * Math.sin(phi));
|
||||||
vertexData[offset + 2] = (float) (radius * Math.cos(theta) * Math.cos(phi));
|
vertexData[offset + 2] = (float) (radius * Math.cos(theta) * Math.cos(phi));
|
||||||
|
|
||||||
// Set vertex texture.x data.
|
// 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
|
// For left-right media, each eye's x coordinate points to the left or right half of the
|
||||||
// texture.
|
// texture.
|
||||||
vertexData[offset + 3] = (i * quadWidthRads / horizontalFovRads) / 2;
|
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.
|
// 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
|
// For top-bottom media, each eye's y coordinate points to the top or bottom half of the
|
||||||
// texture.
|
// texture.
|
||||||
vertexData[offset + 4] = 1 - (((j + k) * quadHeightRads / verticalFovRads) / 2 + .5f);
|
vertexData[offset + 4] = 1 - (((j + k) * quadHeightRads / verticalFovRads) / 2 + .5f);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import android.util.AttributeSet;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ui.spherical.Mesh.EyeType;
|
import com.google.android.exoplayer2.ui.spherical.Mesh.EyeType;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
@ -129,6 +130,20 @@ public final class SphericalSurfaceView extends GLSurfaceView {
|
||||||
setRenderer(renderer);
|
setRenderer(renderer);
|
||||||
setOnTouchListener(touchTracker);
|
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 mesh =
|
||||||
Mesh.createUvSphere(
|
Mesh.createUvSphere(
|
||||||
SPHERE_RADIUS_METERS,
|
SPHERE_RADIUS_METERS,
|
||||||
|
|
@ -136,7 +151,7 @@ public final class SphericalSurfaceView extends GLSurfaceView {
|
||||||
DEFAULT_SPHERE_COLUMNS,
|
DEFAULT_SPHERE_COLUMNS,
|
||||||
DEFAULT_SPHERE_VERTICAL_DEGREES,
|
DEFAULT_SPHERE_VERTICAL_DEGREES,
|
||||||
DEFAULT_SPHERE_HORIZONTAL_DEGREES,
|
DEFAULT_SPHERE_HORIZONTAL_DEGREES,
|
||||||
Mesh.MEDIA_MONOSCOPIC);
|
stereoMode);
|
||||||
queueEvent(() -> renderer.scene.setMesh(mesh));
|
queueEvent(() -> renderer.scene.setMesh(mesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue