### Build and Install Android App
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/README.md
Use Gradle to build and install the debug version of the application. Then, use ADB to start the main activity.
```bash
$ gradlew installDebug
$ adb shell am start -n com.oculus.sample/.SphericalPlayerActivity
```
--------------------------------
### Install and Launch Application
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Commands to install the debug APK onto an Android device and then launch the SphericalPlayerActivity.
```bash
gradlew installDebug
adb shell am start -n com.oculus.sample/.SphericalPlayerActivity
```
--------------------------------
### Instantiate SphericalVideoPlayer Programmatically
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Example of how to create and set up a SphericalVideoPlayer instance directly in your Activity code.
```java
SphericalVideoPlayer player = new SphericalVideoPlayer(this);
setContentView(player);
```
--------------------------------
### play()
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Starts video playback. Only starts if the MediaPlayer is not already playing.
```APIDOC
## play()
### Description
Starts video playback. Only starts if the MediaPlayer is not already playing.
### Note
Called automatically by the prepared listener after `prepareAsync()` completes.
```
--------------------------------
### playWhenReady()
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Signals that playback should begin once the render surface is ready. Call this before the SurfaceTexture is created to ensure video preparation starts automatically when the display surface is available.
```APIDOC
## playWhenReady()
### Description
Signals that playback should begin once the render surface is ready. Call this before the SurfaceTexture is created to ensure video preparation starts automatically when the display surface is available.
### Request Example
```java
player.setVideoURIPath(videoPath);
player.playWhenReady();
```
```
--------------------------------
### EGLRenderTarget Constructor
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Creates a new EGLRenderTarget instance and initializes the EGL display and rendering context. This is typically called once during setup.
```java
public EGLRenderTarget()
```
```java
EGLRenderTarget eglTarget = new EGLRenderTarget();
// EGL context is now ready
```
--------------------------------
### Projection Matrix Setup
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalSceneRenderer.md
Defines a perspective projection with a 70-degree field of view.
```glsl
projectionMatrix = perspective(
fovy=70°,
aspect=width/height,
near=1.0,
far=1000.0
)
```
--------------------------------
### Multiple Index Buffer Sizes
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Example calculation for distributing indices across multiple buffers. This is useful when the total number of indices exceeds the limit for a single buffer.
```plaintext
indices[0].size = 48,600 (194,400 / 4)
indices[1].size = 48,600
indices[2].size = 48,600
indices[3].size = 48,600
```
--------------------------------
### Single Index Buffer Size
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Example calculation for the size of a single index buffer when all indices fit within one buffer. This is relevant for optimizing buffer management.
```plaintext
indices[0].size = 194,400
```
--------------------------------
### Handle Failed External Texture Creation
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
This example illustrates how to handle the failure of generating an OpenGL external texture. It checks if the returned texture ID is -1, indicating an error, and suggests falling back to an alternative rendering method.
```java
int textureId = GLHelpers.generateExternalTexture();
if (textureId == -1) {
Log.e(TAG, "Failed to generate external texture");
// Fall back to alternative rendering method
}
```
--------------------------------
### onCreate Method Implementation
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalPlayerActivity.md
Initializes the activity, sets up the video player, and requests necessary permissions. Ensures the screen stays on during playback.
```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoPlayer = (SphericalVideoPlayer) findViewById(R.id.spherical_video_player);
videoPlayer.setVideoURIPath(videoPath);
videoPlayer.playWhenReady();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
requestExternalStoragePermission();
}
```
--------------------------------
### onCreate(Bundle)
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalPlayerActivity.md
Initializes the activity, inflates layout, initializes the video player, and requests runtime permissions.
```APIDOC
## onCreate(Bundle)
### Description
Initializes the activity, inflates layout, initializes the video player, and requests runtime permissions.
### Method
`protected void onCreate(Bundle savedInstanceState)`
### Parameters
#### Path Parameters
N/A
#### Query Parameters
N/A
#### Request Body
N/A
### Request Example
```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoPlayer = (SphericalVideoPlayer) findViewById(R.id.spherical_video_player);
videoPlayer.setVideoURIPath(videoPath);
videoPlayer.playWhenReady();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
requestExternalStoragePermission();
}
```
### Response
#### Success Response (void)
N/A
#### Response Example
N/A
```
--------------------------------
### EGL Error Format Example
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
This is an example of the error format produced by EGL when an operation fails. The `abortWithEGLError()` method uses `EGL14.eglGetError()` and `GLUtils.getEGLErrorString()` to generate such messages.
```java
eglCreateContext: EGL error: 0x300c: EGL_BAD_ATTRIBUTE
```
--------------------------------
### init()
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Initializes the EGL display connection, chooses an EGL configuration with RGBA-8888 format, and creates an OpenGL ES 2.0 context. Configures 8-bit color and alpha channels.
```APIDOC
## init()
### Description
Initializes the EGL display connection, chooses an EGL configuration with RGBA-8888 format, and creates an OpenGL ES 2.0 context. Configures 8-bit color and alpha channels.
### Method
`public void init()`
### Parameters
None
### Returns
- `void`
### Throws
- `RuntimeException` - with EGL error details if initialization fails
### Configuration Details
- Red channel: 8 bits
- Green channel: 8 bits
- Blue channel: 8 bits
- Alpha channel: 8 bits
- Renderable type: EGL_OPENGL_ES2_BIT
- OpenGL ES version: 2.0
### Example
```java
EGLRenderTarget target = new EGLRenderTarget();
// Display already initialized via constructor
// Can call again to reinitialize if needed
target.init();
```
```
--------------------------------
### Declare SphericalVideoPlayer in XML Layout
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Example of how to include the SphericalVideoPlayer in an Android layout XML file, specifying its ID and dimensions.
```xml
```
--------------------------------
### Application Level Configuration
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/configuration.md
Sets up core application properties including backup, hardware acceleration, icon, label, RTL support, and the main theme. Enables GPU acceleration by default and uses the AppTheme for Material Design.
```xml
```
--------------------------------
### Gradle Build Process
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Details the steps involved in the Gradle build process for compiling Java sources, resources, packaging the APK, and signing the application.
```bash
gradle build
├─ Compile Java sources (src/main/java)
├─ Compile resources (AndroidManifest.xml, layouts, drawables)
├─ Package APK
└─ Sign with debug/release key
```
--------------------------------
### Get Total Sphere Indices
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Retrieves the total number of indices across all index buffers, calculated as the sum of values returned by `getNumIndices()`.
```java
public int getTotalIndices()
```
--------------------------------
### Initialization Sequence for 360 Video Player
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Details the steps from `onCreate` to `initRenderThread` and `onSurfaceAvailable` in the render thread. This sequence is crucial for setting up the video player and the rendering environment.
```plaintext
1. onCreate() [Main Thread]
│
├─ setContentView(R.layout.activity_main)
├─ Set video path
├─ playWhenReady()
├─ requestExternalStoragePermission()
│
├─ [Permission dialog → User allows]
│
└─ init()
└─ setSurfaceTextureListener()
2. onSurfaceTextureAvailable() [Main Thread, TextureView]
│
└─ initRenderThread(surface, width, height) [Main Thread]
│
├─ Create RenderThread (HandlerThread)
├─ Start render thread
├─ Send MSG_SURFACE_AVAILABLE
│
└─ [RenderThread] onSurfaceAvailable() [RenderThread]
│
├─ EGLRenderTarget.init()
│ └─ Create EGL display, config, context
│
├─ EGLRenderTarget.createRenderSurface(surface)
│ └─ Create EGL window surface
│
├─ Choreographer.postFrameCallback()
│ └─ Register for vsync callbacks
│
├─ glViewport(), matrix setup
├─ SphericalSceneRenderer.init()
│ ├─ Load shaders
│ ├─ Create sphere mesh
│ ├─ Cache attribute/uniform locations
│ └─ Setup vertex attributes
│
└─ prepareVideo(videoPath)
└─ MediaPlayer.setDataSource()
└─ MediaPlayer.prepareAsync()
```
--------------------------------
### Get Sphere Vertex Stride
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Retrieves the stride in bytes between consecutive vertex records. This value is crucial for correctly setting up `glVertexAttribPointer()` calls.
```java
public int getVerticesStride()
```
--------------------------------
### Validate OpenGL State After Operations
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
This example demonstrates how to validate OpenGL state after critical operations like glClear and glDrawElements to catch errors immediately.
```java
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLHelpers.checkGlError("glClear"); // Validates state after each operation
GLES20.glDrawElements(GLES20.GL_TRIANGLES, count, GLES20.GL_UNSIGNED_SHORT, buffer);
GLHelpers.checkGlError("glDrawElements"); // Catches draw errors immediately
```
--------------------------------
### Prepare Model-View-Projection Matrix
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalSceneRenderer.md
Combines the projection-view matrix with the model matrix to create the final MVP matrix.
```glsl
mvpMatrix = pvMatrix * modelMatrix
```
--------------------------------
### Get Sphere Indices
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Retrieves an array of ShortBuffer objects, each containing triangle indices for rendering. The number of buffers corresponds to the `numIndexBuffers` specified during construction.
```java
public ShortBuffer[] getIndices()
```
--------------------------------
### Create Shader Program
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/ShaderProgram.md
Compiles vertex and fragment shaders, attaches them to a new program, and links the program. Returns the linked program handle or 0 on failure.
```java
private static int createProgram(String vertexSource, String fragmentSource)
```
--------------------------------
### Recover from Video Preparation Failure
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
This code demonstrates how to recover from a video preparation failure by attempting to retry loading the video or switching to a different video source.
```java
public void onPrepared(MediaPlayer mp) {
try {
play();
} catch (Exception e) {
Log.e(TAG, "Failed to start playback: " + e.getMessage());
// Attempt to retry or switch to different video
retryVideoLoad();
}
}
```
--------------------------------
### Get Sphere Index Counts
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Returns an array of integers representing the count of indices in each index buffer. The sum of these counts equals the total number of indices.
```java
public int[] getNumIndices()
```
--------------------------------
### Get Sphere Vertices
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Retrieves the direct FloatBuffer containing vertex position and texture coordinate data. Each vertex is composed of 5 floats (x, y, z, s, t).
```java
public FloatBuffer getVertices()
```
--------------------------------
### Play Video When Ready
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Signals that playback should begin once the render surface is ready. This should be called before the SurfaceTexture is created to ensure automatic preparation when the display surface is available.
```java
player.setVideoURIPath(videoPath);
player.playWhenReady();
```
--------------------------------
### Initialize and Render Sphere in SphericalSceneRenderer
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Demonstrates the initialization of a Sphere object and its rendering within the SphericalSceneRenderer. It shows how to set up vertex attributes and draw elements using OpenGL ES.
```java
public class SphericalSceneRenderer {
public SphericalSceneRenderer(Context context) {
sphere = new Sphere(SPHERE_SLICES, 0.f, 0.f, 0.f, SPHERE_RADIUS, SPHERE_INDICES_PER_VERTEX);
// Setup vertex attributes
GLES20.glEnableVertexAttribArray(aPositionLocation);
GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false,
sphere.getVerticesStride(), sphere.getVertices());
GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
GLES20.glVertexAttribPointer(aTextureCoordLocation, 2, GLES20.GL_FLOAT, false,
sphere.getVerticesStride(), sphere.getVertices().duplicate().position(3));
}
public void onDrawFrame(...) {
for (int j = 0; j < sphere.getNumIndices().length; ++j) {
GLES20.glDrawElements(GLES20.GL_TRIANGLES, sphere.getNumIndices()[j],
GLES20.GL_UNSIGNED_SHORT, sphere.getIndices()[j]);
}
}
}
```
--------------------------------
### Initialize and Configure MediaPlayer for Video Playback
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/types.md
Sets up an Android MediaPlayer instance for decoding and playing video. Configures the audio stream, looping, and the video surface, then prepares for asynchronous playback.
```java
videoPlayerInternal = new MediaPlayer();
videoPlayerInternal.setSurface(renderThread.getVideoDecodeSurface());
videoPlayerInternal.setAudioStreamType(AudioManager.STREAM_MUSIC);
videoPlayerInternal.setDataSource(context, Uri.parse(videoPath), null);
videoPlayerInternal.setLooping(true);
videoPlayerInternal.prepareAsync(); // Async preparation
// ... onPrepared callback fires
videoPlayerInternal.start();
// ... playback continues until releaseResources()
videoPlayerInternal.stop();
videoPlayerInternal.release();
```
--------------------------------
### Request External Storage Permission
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalPlayerActivity.md
Checks for and requests READ_EXTERNAL_STORAGE permission if not already granted. If granted, it proceeds to initialize the player.
```java
private void requestExternalStoragePermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
} else {
init();
}
}
```
--------------------------------
### Get Uniform Variable Location
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/ShaderProgram.md
Retrieve the location index for a named uniform variable. This method caches the result of glGetUniformLocation and throws an exception if the uniform is not found in the shader.
```java
ShaderProgram program = new ShaderProgram(vertexSrc, fragmentSrc);
int mvpLoc = program.getUniform("uMVPMatrix");
int texMatrixLoc = program.getUniform("uTextureMatrix");
GLES20.glUniformMatrix4fv(mvpLoc, 1, false, mvpMatrix, 0);
GLES20.glUniformMatrix4fv(texMatrixLoc, 1, false, texMatrix, 0);
```
--------------------------------
### SphericalVideoPlayer Constructor with Context, AttributeSet, and DefStyleAttr
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Creates a new SphericalVideoPlayer instance with custom style attributes. This constructor allows for more advanced styling and theming.
```java
public SphericalVideoPlayer(Context context, AttributeSet attrs, int defStyleAttr)
```
--------------------------------
### Get Vertex Attribute Location
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/ShaderProgram.md
Obtain the location index for a named vertex attribute. This method caches the result of glGetAttribLocation and throws an exception if the attribute is not found in the shader.
```java
ShaderProgram program = new ShaderProgram(vertexSrc, fragmentSrc);
int positionLoc = program.getAttribute("aPosition");
int texCoordLoc = program.getAttribute("aTextureCoord");
GLES20.glEnableVertexAttribArray(positionLoc);
GLES20.glVertexAttribPointer(positionLoc, 3, GLES20.GL_FLOAT, false, stride, vertexBuffer);
```
--------------------------------
### EGLRenderTarget Constructor
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Creates a new EGLRenderTarget and immediately initializes the EGL display and rendering context. Automatically calls init() during construction.
```APIDOC
## EGLRenderTarget()
### Description
Creates a new EGLRenderTarget and immediately initializes the EGL display and rendering context. Automatically calls `init()` during construction.
### Method
Constructor
### Parameters
None
### Returns
- `EGLRenderTarget` - New EGLRenderTarget instance
### Throws
- `RuntimeException` - if EGL initialization fails
### Example
```java
EGLRenderTarget eglTarget = new EGLRenderTarget();
// EGL context is now ready
```
```
--------------------------------
### Get Shader Program Handle
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/ShaderProgram.md
Retrieve the OpenGL ES program object handle for the ShaderProgram. This handle is necessary to activate the shader program for rendering using GLES20.glUseProgram().
```java
ShaderProgram program = new ShaderProgram(vertexSrc, fragmentSrc);
int handle = program.getShaderHandle();
GLES20.glUseProgram(handle);
```
--------------------------------
### ShaderProgram API
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/README.md
A wrapper class for GLSL shader compilation and linking. It provides methods to get attribute and uniform locations, retrieve shader handles, and release shader resources.
```APIDOC
## ShaderProgram Methods
### `getAttribute(String name)`
Gets the location of a vertex attribute.
### `getUniform(String name)`
Gets the location of a uniform variable.
### `getShaderHandle()`
Returns the handle of the compiled shader program.
### `release()`
Releases the shader program resources.
```
--------------------------------
### SphericalVideoPlayer Constructor with Context
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Creates a new SphericalVideoPlayer instance using a single context parameter. This is typically used when instantiating the player programmatically.
```java
public SphericalVideoPlayer(Context context)
```
--------------------------------
### Retrieve Shader Attribute and Uniform Locations
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
Get attribute and uniform locations from a ShaderProgram. This code will throw a RuntimeException if the specified attribute or uniform name is not found in the compiled shader program.
```java
ShaderProgram program = new ShaderProgram(vertexSrc, fragmentSrc);
int posLoc = program.getAttribute("aPosition"); // Throws if "aPosition" not in vertex shader
int mvpLoc = program.getUniform("uMVPMatrix"); // Throws if "uMVPMatrix" not in program
```
--------------------------------
### GLHelpers Static Methods
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Static utility methods for OpenGL operations.
```APIDOC
## GLHelpers
### Description
Provides static utility methods for common OpenGL operations.
### Static Methods
- `generateExternalTexture()`: Create external texture.
- `checkGlError(String)`: Validate GL state.
```
--------------------------------
### Check EGL Context Before Getting Video Decode Surface
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
This code snippet shows how to safely obtain a video decode surface by first checking for a valid EGL context. If the context is not valid, it logs an error and defers surface creation.
```java
if (eglRenderTarget.hasValidContext()) {
Surface decodeSurface = getVideoDecodeSurface();
} else {
Log.e(TAG, "EGL context not ready");
// Defer surface creation
}
```
--------------------------------
### Ensure Correct Call Order for Video Playback
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
This snippet demonstrates the correct sequence of method calls to avoid an IllegalStateException related to render thread initialization. Ensure the video URI is set and playback is signaled before the render thread is available.
```java
// Ensure correct call order:
videoPlayer.setVideoURIPath(path); // Set path first
videoPlayer.playWhenReady(); // Signal ready to play
// Wait for onSurfaceTextureAvailable() to call initRenderThread()
```
--------------------------------
### EGLRenderTarget Lifecycle Integration
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Demonstrates the typical sequence of operations for using EGLRenderTarget within a rendering thread. This includes initialization, surface creation, per-frame rendering, and cleanup.
```java
1. **Construction**: `EGLRenderTarget()` — initializes display and context
2. **Surface available**: `createRenderSurface(surfaceTexture)` — creates window surface
3. **Per frame**: `makeCurrent()`, draw operations, `swapBuffers()`
4. **Cleanup**: `release()` — destroys context and surface
```
--------------------------------
### Prepare Projection-View Matrix
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalSceneRenderer.md
Combines projection and view matrices to form the projection-view matrix.
```glsl
pvMatrix = projectionMatrix * viewMatrix
```
--------------------------------
### SphericalSceneRenderer Constructor
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalSceneRenderer.md
Initializes the renderer, loading shaders, creating geometry, and preparing OpenGL state. Ensure to call release() when done to clean up resources.
```java
public SphericalSceneRenderer(Context context)
```
```java
SphericalSceneRenderer renderer = new SphericalSceneRenderer(context);
// Use renderer in onDrawFrame() each frame
// ...
// Cleanup
renderer.release();
```
--------------------------------
### Initialize Video Player View and Render Thread
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalPlayerActivity.md
Sets up the TextureView's SurfaceTextureListener to manage the render thread and surface availability. This snippet also makes the video player view visible.
```java
private void init() {
videoPlayer.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
videoPlayer.initRenderThread(surface, width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
videoPlayer.releaseResources();
return false;
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
});
videoPlayer.setVisibility(View.VISIBLE);
}
```
--------------------------------
### SphericalVideoPlayer(Context)
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Creates a new SphericalVideoPlayer instance with a single context parameter. This constructor is used when creating the player programmatically.
```APIDOC
## SphericalVideoPlayer(Context)
### Description
Creates a new SphericalVideoPlayer instance with a single context parameter.
### Method
public SphericalVideoPlayer(Context context)
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```java
SphericalVideoPlayer player = new SphericalVideoPlayer(this);
setContentView(player);
```
### Response
#### Success Response (200)
New SphericalVideoPlayer instance
#### Response Example
None
```
--------------------------------
### Handle READ_EXTERNAL_STORAGE Permission Denial
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
This snippet illustrates the error handling for when a user denies READ_EXTERNAL_STORAGE permission. It shows a toast message and prevents video player initialization.
```java
Toast: "Access not granted for reading video file :("
```
--------------------------------
### Configure Vertex Attributes with Sphere Data
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Demonstrates how to use `getVertices()` and `getVerticesStride()` to configure OpenGL ES vertex attribute pointers for position and texture coordinates.
```java
FloatBuffer vertices = sphere.getVertices();
int vertexStride = sphere.getVerticesStride();
GLES20.glEnableVertexAttribArray(aPositionLocation);
GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false,
vertexStride, vertices);
// For texture coordinates, use offset into same buffer
GLES20.glEnableVertexAttribArray(aTexCoordLocation);
GLES20.glVertexAttribPointer(aTexCoordLocation, 2, GLES20.GL_FLOAT, false,
vertexStride, vertices.duplicate().position(3));
```
--------------------------------
### Initialize ShaderProgram
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/ShaderProgram.md
Initializes a ShaderProgram with vertex and fragment shaders. Caches attribute and uniform locations for efficiency and sets up the OpenGL program for use.
```java
public class SphericalSceneRenderer {
private ShaderProgram shaderProgram;
public SphericalSceneRenderer(Context context) {
String vertexSrc = readShaderFile(context, R.raw.video_vertex_shader);
String fragmentSrc = readShaderFile(context, R.raw.video_fragment_shader);
shaderProgram = new ShaderProgram(vertexSrc, fragmentSrc);
// Cache attribute locations for efficiency
aPositionLocation = shaderProgram.getAttribute("aPosition");
aTextureCoordLocation = shaderProgram.getAttribute("aTextureCoord");
uMVPMatrixLocation = shaderProgram.getUniform("uMVPMatrix");
uTextureMatrixLocation = shaderProgram.getUniform("uTextureMatrix");
GLES20.glUseProgram(shaderProgram.getShaderHandle());
GLES20.glEnableVertexAttribArray(aPositionLocation);
GLES20.glEnableVertexAttribArray(aTextureCoordLocation);
}
public void release() {
shaderProgram.release();
}
}
```
--------------------------------
### EGLRenderTarget Initialization
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Initializes the EGL display connection, chooses an EGL configuration, and creates an OpenGL ES 2.0 context. Can be called again to reinitialize.
```java
public void init()
```
```java
EGLRenderTarget target = new EGLRenderTarget();
// Display already initialized via constructor
// Can call again to reinitialize if needed
target.init();
```
--------------------------------
### Activity Intent Filter
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/configuration.md
Defines the main launcher entry point for the application, making this activity the first one to be displayed when the app is launched.
```xml
```
--------------------------------
### Create ShaderProgram
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/ShaderProgram.md
Instantiate a ShaderProgram by providing GLSL source code for vertex and fragment shaders. This constructor handles compilation and linking, throwing a RuntimeException on failure.
```java
String vertexSource = readShaderFile("vertex.glsl");
String fragmentSource = readShaderFile("fragment.glsl");
ShaderProgram program = new ShaderProgram(vertexSource, fragmentSource);
// Use the program
GLES20.glUseProgram(program.getShaderHandle());
```
--------------------------------
### release()
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/ShaderProgram.md
Deletes the shader program and frees GPU resources. Sets the program handle to -1. Call during cleanup or when the program is no longer needed.
```APIDOC
## release()
### Description
Deletes the shader program and frees GPU resources. Sets the program handle to -1. Call during cleanup or when the program is no longer needed.
### Returns
- **void**
### Example
```java
@Override
protected void onDestroy() {
program.release();
super.onDestroy();
}
```
```
--------------------------------
### Touch Input Flow for 360 Video Player
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Describes how touch events are processed, from `onTouchEvent` on the main thread to `onScroll` in the `SimpleOnGestureListener`, and finally queued to the render thread for camera updates.
```plaintext
onTouchEvent() [Main Thread, TextureView]
│
└─ GestureDetector.onTouchEvent()
│
└─ SimpleOnGestureListener.onScroll(e1, e2, distanceX, distanceY)
│
├─ Create Message(MSG_ON_SCROLL)
├─ Wrap deltaX, deltaY in ScrollDeltaHolder
│
└─ handler.sendMessage() [Queue to RenderThread]
│
└─ onScroll(deltaHolder) [RenderThread]
│
├─ lon += deltaX * DRAG_FRICTION
├─ lat -= deltaY * DRAG_FRICTION
│
└─ pendingCameraUpdate = true
└─ Next vsync → updateCamera() recomputes view matrix
```
--------------------------------
### Initialize ShortBuffer for Index Data
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/types.md
Allocates a direct ByteBuffer on the native heap and converts it to a ShortBuffer for storing triangle index data.
```java
ShortBuffer indices = ByteBuffer.allocateDirect(capacity)
.order(ByteOrder.nativeOrder())
.asShortBuffer();
```
--------------------------------
### Spherical Player Activity Configuration
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/configuration.md
Configures the main player activity, enabling hardware acceleration and enforcing landscape screen orientation for an optimal viewing experience.
```xml
```
--------------------------------
### Project Architecture Diagram
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Visual representation of the application's layered architecture, showing the interaction between UI, Video Player, Rendering, and OpenGL Utilities.
```text
┌─────────────────────────────────────────┐
│ User Interface Layer │
│ SphericalPlayerActivity (Entry Point) │
└──────────────────┬──────────────────────┘
│
┌──────────────────┴──────────────────────┐
│ Video Player Layer │
│ SphericalVideoPlayer (TextureView) │
│ + RenderThread (HandlerThread) │
└──────────────────┬──────────────────────┘
│
┌──────────────────┴──────────────────────────────────────┐
│ Rendering Layer │
│ ┌──────────────────┐ ┌────────────────────┐ │
│ │ EGLRenderTarget │ │ SphericalScene │ │
│ │ (EGL context) │ │ Renderer │ │
│ │ │ │ (Shader + sphere) │ │
│ └──────────────────┘ └────────────────────┘ │
└──────────────────┬──────────────────────────────────────┘
│
┌──────────────────┴──────────────────────────────────────┐
│ OpenGL Utilities Layer │
│ ┌─────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ GLHelpers │ │ Shader │ │ Sphere │ │
│ │ (Errors) │ │ Program │ │ (Mesh) │ │
│ └─────────────┘ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────┘
```
--------------------------------
### SphericalPlayerActivity Static Methods
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Static utility methods available on SphericalPlayerActivity.
```APIDOC
## SphericalPlayerActivity
### Description
Entry point activity for the player, with static utility methods.
### Static Methods
- `toast()`: Display a toast message.
- `readRawTextFile()`: Read text from a raw resource file.
```
--------------------------------
### Batched Drawing with Multiple Index Buffers
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalSceneRenderer.md
Demonstrates batched drawing using multiple index buffers for rendering spheres. This approach reduces per-draw-call complexity, especially for larger spheres.
```java
for (int j = 0; j < sphere.getNumIndices().length; ++j) {
GLES20.glDrawElements(GLES20.GL_TRIANGLES,
sphere.getNumIndices()[j], GLES20.GL_UNSIGNED_SHORT,
sphere.getIndices()[j]);
}
```
--------------------------------
### Handle Shader Resource Loading Errors
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
Check for null return values when loading shader source files. If null, it indicates a failure to load the resource, requiring fallback shaders or aborting the process.
```java
String vertexShader = SphericalPlayerActivity.readRawTextFile(context, R.raw.video_vertex_shader);
if (vertexShader == null) {
Log.e(TAG, "Failed to load vertex shader");
// Use fallback shader or abort
}
```
--------------------------------
### initRenderThread(SurfaceTexture surface, int width, int height)
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Initializes the background render thread with the display surface and dimensions. Creates an OpenGL ES rendering context and begins the vsync callback loop. Called when the TextureView surface becomes available.
```APIDOC
## initRenderThread(SurfaceTexture surface, int width, int height)
### Description
Initializes the background render thread with the display surface and dimensions. Creates an OpenGL ES rendering context and begins the vsync callback loop. Called when the TextureView surface becomes available.
### Parameters
#### Path Parameters
- **surface** (SurfaceTexture) - Required - SurfaceTexture from the TextureView
- **width** (int) - Required - Surface width in pixels
- **height** (int) - Required - Surface height in pixels
### Request Example
```java
videoPlayer.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
videoPlayer.initRenderThread(surface, width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
videoPlayer.releaseResources();
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
});
```
```
--------------------------------
### Handle EGL Initialization Errors
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/errors.md
Catch RuntimeExceptions during EGL initialization to handle failures gracefully. This is useful when setting up rendering surfaces or contexts.
```java
try {
EGLRenderTarget eglTarget = new EGLRenderTarget();
eglTarget.createRenderSurface(surfaceTexture);
} catch (RuntimeException e) {
Log.e(TAG, "EGL initialization failed: " + e.getMessage());
// Fall back to software rendering or abort
}
```
--------------------------------
### Direct ByteBuffer Allocation for GPU Data
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/configuration.md
Demonstrates the allocation of direct ByteBuffers for GPU-bound data, ensuring efficient memory management for vertex and index buffers. Direct buffers are not managed by the Java GC and must be handled explicitly if released.
```java
ByteBuffer.allocateDirect(size)
.order(ByteOrder.nativeOrder())
.asFloatBuffer() // or .asShortBuffer()
```
--------------------------------
### Sphere Constructor
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Creates a sphere mesh with specified geometric parameters and organizes indices into multiple buffers for efficient rendering.
```APIDOC
## Sphere(int nSlices, float x, float y, float z, float r, int numIndexBuffers)
### Description
Creates a sphere mesh with specified geometric parameters and organizes indices into multiple buffers for efficient rendering.
### Parameters
#### Path Parameters
- **nSlices** (int) - Required - Number of slices in horizontal direction (>1 and <=180); same count used for vertical direction
- **x** (float) - Required - X coordinate of sphere origin
- **y** (float) - Required - Y coordinate of sphere origin
- **z** (float) - Required - Z coordinate of sphere origin
- **r** (float) - Required - Radius of the sphere
- **numIndexBuffers** (int) - Required - Number of index buffers to distribute indices across
### Returns
New Sphere instance with generated mesh data
### Throws
RuntimeException if nSlices is too large (results in vertex count > Short.MAX_VALUE)
### Example
```java
// Create a sphere centered at origin with radius 500
Sphere sphere = new Sphere(
180, // nSlices: high tessellation for smooth surface
0.0f, // x: origin
0.0f, // y: origin
0.0f, // z: origin
500.0f, // radius: large for immersive rendering
1 // numIndexBuffers: single buffer for simplicity
);
```
```
--------------------------------
### makeCurrent()
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Makes the EGL context current for the calling thread. All subsequent OpenGL ES calls execute on this context and render to the associated surface. Required before issuing any OpenGL commands.
```APIDOC
## makeCurrent()
### Description
Makes the EGL context current for the calling thread. All subsequent OpenGL ES calls execute on this context and render to the associated surface. Required before issuing any OpenGL commands.
### Method
`public void makeCurrent()`
### Parameters
None
### Returns
- `void`
### Throws
- `RuntimeException` - if `eglMakeCurrent` fails
### Example
```java
// On render thread
eglTarget.makeCurrent();
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
eglTarget.swapBuffers();
```
```
--------------------------------
### SphericalVideoPlayer(Context, AttributeSet, int)
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Creates a new SphericalVideoPlayer instance with custom style attributes. This constructor allows for more advanced customization through style attributes defined in themes or styles.
```APIDOC
## SphericalVideoPlayer(Context, AttributeSet, int)
### Description
Creates a new SphericalVideoPlayer instance with custom style attributes.
### Method
public SphericalVideoPlayer(Context context, AttributeSet attrs, int defStyleAttr)
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
None
### Response
#### Success Response (200)
New SphericalVideoPlayer instance
#### Response Example
None
```
--------------------------------
### Configure Vertex Attributes with Stride
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Shows how to use `getVerticesStride()` to specify the byte stride for `glVertexAttribPointer()`, ensuring correct data interpretation for position and texture coordinates.
```java
int stride = sphere.getVerticesStride(); // Returns 20
GLES20.glVertexAttribPointer(positionLoc, 3, GLES20.GL_FLOAT, false, stride, vertices);
GLES20.glVertexAttribPointer(texCoordLoc, 2, GLES20.GL_FLOAT, false,
stride, vertices.duplicate().position(3));
```
--------------------------------
### createRenderSurface(SurfaceTexture)
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Creates an EGL window surface from a SurfaceTexture. Automatically calls makeCurrent() to activate the context for subsequent OpenGL calls. Required before any OpenGL ES drawing operations.
```APIDOC
## createRenderSurface(SurfaceTexture)
### Description
Creates an EGL window surface from a SurfaceTexture. Automatically calls `makeCurrent()` to activate the context for subsequent OpenGL calls. Required before any OpenGL ES drawing operations.
### Method
`public void createRenderSurface(SurfaceTexture surfaceTexture)`
### Parameters
#### Path Parameters
- **surfaceTexture** (SurfaceTexture) - Yes - — - Android SurfaceTexture from TextureView to render to
### Returns
- `void`
### Throws
- `RuntimeException` - if surface creation fails or context is invalid
### Example
```java
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
eglTarget.createRenderSurface(surface);
// OpenGL context is now current and ready
GLES20.glViewport(0, 0, width, height);
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
}
```
```
--------------------------------
### release()
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Destroys the EGL surface and context, releasing all GPU resources. Cleans up EGL state by setting handles to EGL_NO_SURFACE, EGL_NO_CONTEXT, and EGL_NO_DISPLAY. Call during cleanup or when activity is destroyed.
```APIDOC
## release()
### Description
Destroys the EGL surface and context, releasing all GPU resources. Cleans up EGL state by setting handles to EGL_NO_SURFACE, EGL_NO_CONTEXT, and EGL_NO_DISPLAY. Call during cleanup or when activity is destroyed.
### Method
`public void release()`
### Parameters
None
### Returns
- `void`
### Throws
- None
### Example
```java
@Override
protected void onDestroy() {
eglTarget.release();
super.onDestroy();
}
```
```
--------------------------------
### Sphere Constructor
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/Sphere.md
Creates a sphere mesh with specified geometric parameters and organizes indices into multiple buffers for efficient rendering. Ensure nSlices is between 2 and 180, and the resulting vertex count does not exceed Short.MAX_VALUE.
```java
public Sphere(int nSlices, float x, float y, float z, float r, int numIndexBuffers)
```
```java
// Create a sphere centered at origin with radius 500
Sphere sphere = new Sphere(
180, // nSlices: high tessellation for smooth surface
0.0f, // x: origin
0.0f, // y: origin
0.0f, // z: origin
500.0f, // radius: large for immersive rendering
1 // numIndexBuffers: single buffer for simplicity
);
```
--------------------------------
### View Matrix Calculation
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalSceneRenderer.md
Calculates camera position using spherical coordinates (longitude, latitude) and sets up the view matrix.
```glsl
phi = 90 - latitude
theta = longitude
x = 100 * sin(phi) * cos(theta)
y = 100 * cos(phi)
z = 100 * sin(phi) * sin(theta)
viewMatrix = lookAt(x, y, z, 0, 0, 0, 0, 1, 0)
```
--------------------------------
### Render Loop for 360 Video Player
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Illustrates the render loop triggered by VSync events. It covers updating the video texture, camera view, and drawing the frame using OpenGL ES.
```plaintext
[VSync Event]
│
├─ Choreographer.postFrameCallback()
│ └─ onFrame(frameTimeNanos)
│ └─ RenderThread.handler.sendEmptyMessage(MSG_VSYNC)
│
└─ onVSync() [RenderThread]
│
├─ eglTarget.makeCurrent()
│
├─ videoSurfaceTexture.updateTexImage()
│ └─ Latch latest video frame
│
├─ videoSurfaceTexture.getTransformMatrix(matrix)
│
├─ updateCamera()
│ └─ Convert lon/lat to view matrix
│
├─ renderer.onDrawFrame(...)
│ ├─ glClear()
│ ├─ glBindTexture(videoTexture)
│ ├─ Set uniforms (MVP, texture matrix)
│ └─ glDrawElements() [for each index buffer]
│
└─ eglTarget.swapBuffers()
└─ Present frame to TextureView
```
--------------------------------
### onRequestPermissionsResult(int, String[], int[])
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalPlayerActivity.md
Handles the response from Android's runtime permission request. Initializes the renderer if permission is granted, or shows a toast if denied.
```APIDOC
## onRequestPermissionsResult(int, String[], int[])
### Description
Handles the response from Android's runtime permission request. Initializes the renderer if permission is granted, or shows a toast if denied.
### Method
`public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)`
### Parameters
#### Path Parameters
N/A
#### Query Parameters
N/A
#### Request Body
N/A
### Request Example
```java
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode != PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE) {
return;
}
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
init();
} else {
toast(this, "Access not granted for reading video file :(");
}
}
```
### Response
#### Success Response (void)
N/A
#### Response Example
N/A
```
--------------------------------
### ShaderProgram Methods
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Methods for interacting with compiled shader programs.
```APIDOC
## ShaderProgram
### Description
Wrapper for shader compilation, providing access to shader attributes and uniforms.
### Methods
- `getAttribute(String)`: Get attribute location.
- `getUniform(String)`: Get uniform location.
- `getShaderHandle()`: Get program handle.
- `release()`: Cleanup.
```
--------------------------------
### GLHelpers API
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/README.md
Contains utility methods for OpenGL ES operations. This includes functions for generating external textures and checking for OpenGL errors.
```APIDOC
## GLHelpers Methods
### `generateExternalTexture()`
Generates an external texture suitable for video playback.
### `checkGlError(String op)`
Checks for OpenGL errors after an operation and logs them if any occur.
```
--------------------------------
### readRawTextFile(Context, int)
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalPlayerActivity.md
Reads the entire contents of a raw resource file into a String. Used to load shader source code.
```APIDOC
## readRawTextFile(Context, int)
### Description
Reads the entire contents of a raw resource file into a String. Used to load shader source code.
### Method
public static String
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Parameters
- **context** (Context) - Required - Application context for resource access
- **resId** (int) - Required - Raw resource ID (e.g., `R.raw.video_vertex_shader`)
### Response
#### Success Response (String)
String — Full file contents with newlines preserved; null on IOException
### Example
```java
String vertexShaderSrc = SphericalPlayerActivity.readRawTextFile(context, R.raw.video_vertex_shader);
String fragmentShaderSrc = SphericalPlayerActivity.readRawTextFile(context, R.raw.video_fragment_shader);
ShaderProgram program = new ShaderProgram(vertexShaderSrc, fragmentShaderSrc);
```
```
--------------------------------
### SphericalVideoPlayer(Context, AttributeSet)
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Creates a new SphericalVideoPlayer instance initialized from XML layout attributes. This constructor is typically used by the Android layout inflater when the player is declared in an XML file.
```APIDOC
## SphericalVideoPlayer(Context, AttributeSet)
### Description
Creates a new SphericalVideoPlayer instance initialized from XML layout attributes. Used by the Android layout inflater.
### Method
public SphericalVideoPlayer(Context context, AttributeSet attrs)
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```xml
```
### Response
#### Success Response (200)
New SphericalVideoPlayer instance
#### Response Example
None
```
--------------------------------
### Create Render Surface from SurfaceTexture
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/EGLRenderTarget.md
Creates an EGL window surface from a SurfaceTexture and makes the OpenGL context current. This is required before any OpenGL ES drawing operations.
```java
public void createRenderSurface(SurfaceTexture surfaceTexture)
```
```java
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
eglTarget.createRenderSurface(surface);
// OpenGL context is now current and ready
GLES20.glViewport(0, 0, width, height);
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
}
```
--------------------------------
### App Build Configuration
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/configuration.md
Defines essential build settings for the Android application, including SDK versions, build tools, and minimum/target SDKs. Specifies the application ID and configures the release build type.
```gradle
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
```
--------------------------------
### SphericalVideoPlayer Constructor with Context and AttributeSet
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalVideoPlayer.md
Creates a new SphericalVideoPlayer instance initialized from XML layout attributes. This constructor is used by the Android layout inflater when the player is declared in an XML file.
```java
public SphericalVideoPlayer(Context context, AttributeSet attrs)
```
--------------------------------
### SphericalVideoPlayer Methods
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/PROJECT-OVERVIEW.md
Methods for controlling video playback and source.
```APIDOC
## SphericalVideoPlayer
### Description
Provides methods to control video playback and set the video source.
### Methods
- `setVideoURIPath(String)`: Set video source.
- `playWhenReady()`: Signal start on surface ready.
- `initRenderThread(SurfaceTexture, int, int)`: Initialize renderer.
- `play()`: Start playback.
- `releaseResources()`: Cleanup.
```
--------------------------------
### Activity Main Layout XML
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/configuration.md
Defines the layout for the 360 video player activity. The SphericalVideoPlayer is initially hidden and set to fill the screen.
```xml
```
--------------------------------
### Model Matrix Rotation
Source: https://github.com/fbsamples/360-video-player-for-android/blob/master/_autodocs/api-reference/SphericalSceneRenderer.md
Initializes the model matrix with a 90-degree upward rotation.
```glsl
modelMatrix = rotateX(90°)
```