Play SBS Videos in 4V

Learn to play a SBS (2x1) video on a QuadView using ExoPlayer

In the previous section, we seen how to play a Quad video in 4V using the ExoPlayer. Playing a SBS video is very similar to playing a Quad video using the SDK.

For this section, we will stream a 2x1 video using ExoPlayer.

Resources

For this section, we will be working with a SBS video. We will be streaming the video using this url

As we are going to be streaming the 2x1 video from the internet, you need to add the Internet permission in your app's manifest file.

<uses-permission android:name="android.permission.INTERNET"/>

Setup Environment

Setup the Android SDK in your Android project by following the steps outlined in the Getting Started Section.

We will also need to add the ExoPlayer dependency to our project. Add the following dependency to your app's build.gradle file.

implementation 'com.google.android.exoplayer:exoplayer:2.11.7'

Add the QuadView to your XML Layout file

<com.leiainc.androidsdk.core.QuadView
android:id="@+id/quad_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

The QuadView is a reusable Android view which allows you to easily render a quad with just one line of code.

Obtain the reference to the QuadView in your Activity or Fragment using findViewById()

Kotlin
Java
Kotlin
val quadView: QuadView = findViewById(R.id.quad_view)
Java
QuadView quadView = findViewById(R.id.quad_view);

Implement SurfaceTextureReady Callbacks

In order to play videos on the QuadView, you need to obtain the SurfaceTexture when it becomes available. You can do so by implementing the SurfaceTextureReadyCallback which will notify you when the Surface Texture becomes available via callbacks.

Kotlin
Java
Kotlin
class VideoActivity : AppCompatActivity(), SurfaceTextureReadyCallback {
// rest of activity code
override fun onSurfaceTextureReady(surfaceTexture: SurfaceTexture?) {
TODO("Not yet implemented")
}
}
Java
public class VideoActivity extends AppCompatActivity implements SurfaceTextureReadyCallback {
// rest of activity code
@Override
public void onSurfaceTextureReady(SurfaceTexture surfaceTexture) {
// TODO
}
}

Attach Callbacks to QuadView

We now have to attach the callback to the QuadView. This registers the callback so the QuadView can notify us when the surface texture becomes available. We can do this by calling getInputSurfaceTexture() as shown below

Kotlin
Java
Kotlin
val quadView: QuadView = findViewById(R.id.quad_view)
quadView.getInputSurfaceTexture(this)
Java
QuadView quadView = findViewById(R.id.quad_view);
quadView.getInputSurfaceTexture(this);

Initialize ExoPlayer

Initialize the ExoPlayer in your Activity's onCreate() function. Add exoPlayer as a global variable so it can be accessed in other functions as well.

Kotlin
Java
Kotlin
private lateinit var exoPlayer: SimpleExoPlayer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_video)
val quadView: QuadView = findViewById(R.id.quad_view)
quadView.getInputSurfaceTexture(this)
// Initialize ExoPlayer
exoPlayer = SimpleExoPlayer.Builder(this).build()
}
Java
private SimpleExoPlayer exoPlayer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
QuadView quadView = findViewById(R.id.quad_view);
quadView.getInputSurfaceTexture(this);
// Initialize ExoPlayer
exoPlayer = SimpleExoPlayer.Builder(this).build();
}

Initialize SBS Video Surface Renderer

This step is where it gets a bit different from playing a regular Quad video. For SBS videos, we need to first pass the surface to the SBS Surface Renderer. The SBS Surface renderer performs real time conversion from 2x1 to 2x2.

You can obtain the converted surface texture via callbacks. Pass this surface to the ExoPlayer to play the video in 4V.

Kotlin
Java
Kotlin
class VideoActivity : AppCompatActivity(), SurfaceTextureReadyCallback {
// rest of activity code
private lateinit var sbsVideoSurfaceRenderer: SbsVideoSurfaceRenderer
override fun onSurfaceTextureReady(surfaceTexture: SurfaceTexture?) {
// Initialize and pass in surface texture to the SBSVideoSurfaceRenderer
if (sbsVideoSurfaceRenderer == null) {
sbsVideoSurfaceRenderer = SbsVideoSurfaceRenderer(
this,
Surface(surfaceTexture),
TextureShape.LANDSCAPE,
) {
configureExoplayer(it)
}
}
}
}
private fun configureExoplayer(surfaceTexture: SurfaceTexture) {
// Note: This is appropriate for 2x2 textures on Hydrogen One.
exoPlayer.setVideoSurface(Surface(surfaceTexture))
val userAgent = Util.getUserAgent(this, "exoplayer2example")
val uri = Uri.parse(
"https://dev.streaming.leialoft.com/out/v1/08cd49f09fbc4a1e9c063424fa0bfc00/7845cda1bdd5494db13a24f5d13374ea/adacb4edf0434177ae441f124d989fe7/index.mpd"
)
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSourceFactory(userAgent)
val videoSource: MediaSource =
DashMediaSource.Factory(dataSourceFactory).createMediaSource(uri)
val loopingSource = LoopingMediaSource(videoSource)
exoPlayer.prepare(loopingSource)
}
Java
public class VideoActivity extends AppCompatActivity implements SurfaceTextureReadyCallback {
private SbsVideoSurfaceRenderer sbsVideoSurfaceRenderer = null;
@Override
public void onSurfaceTextureReady(SurfaceTexture surfaceTexture) {
if (sbsVideoSurfaceRenderer == null) {
sbsVideoSurfaceRenderer = SbsVideoSurfaceRenderer(
this,
new Surface(surfaceTexture),
TextureShape.LANDSCAPE,
(surfaceTexure) -> {
configureExoplayer(surfaceTexture);
});
}
}
private void configureExoplayer(SurfaceTexture surfaceTexture) {
exoPlayer.setVideoSurface(new Surface(surfaceTexture));
String userAgent = Util.getUserAgent(this, "exoplayer2example");
Uri uri = Uri.parse(
"https://dev.streaming.leialoft.com/out/v1/08cd49f09fbc4a1e9c063424fa0bfc00/7845cda1bdd5494db13a24f5d13374ea/adacb4edf0434177ae441f124d989fe7/index.mpd"
);
DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory(userAgent);
MediaSource videoSource =
DashMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource);
exoPlayer.prepare(loopingSource);
}
}

Playing the Video

With the ExoPlayer now setup, we can play the video by calling playWhenReady() in your Activity's onResume() function.

Kotlin
Java
Kotlin
override fun onResume() {
super.onResume()
exoPlayer.playWhenReady = true
}
Java
@Override
protected void onResume() {
super.onResume();
exoPlayer.setPlayWhenReady(true);
}

Pause playing the video when the activity's onPause() is called.

Kotlin
Java
Kotlin
override fun onPause() {
super.onPause()
exoPlayer.playWhenReady = false
}
Java
@Override
protected void onPause() {
super.onPause();
exoPlayer.setPlayWhenReady(false);
}

You can learn more about using the ExoPlayer here.

Toggle the Backlight

The last step is to switch on the backlight to view the image in 4V. We can request toggling backlight using the LeiaDisplayManager .

Place the following line of code in your Activity/Fragment's onResume() function.

Kotlin
Java
Kotlin
override fun onResume() {
super.onResume()
exoPlayer.playWhenReady = true
val displayManager: LeiaDisplayManager? = LeiaSDK.getDisplayManager(applicationContext)
displayManager?.requestBacklightMode(LeiaDisplayManager.BacklightMode.MODE_3D)
}
Java
@Override
protected void onResume() {
super.onResume();
exoPlayer.setPlayWhenReady(true);
LeiaDisplayManager displayManager = LeiaSDK.getDisplayManager(applicationContext);
displayManager.requestBacklightMode(LeiaDisplayManager.BacklightMode.MODE_3D);
}

This will turn on the backlight on a Leia Light-field device.

To turn off the backlight, you can call the same line of code with BacklightMode.MODE_2D. Its a good practice to turn off the backlight in your activity's onPause() function. This ensures the backlight is turned off when the user exits the app.

Kotlin
Java
Kotlin
override fun onPause() {
super.onPause()
exoPlayer.playWhenReady = false
val displayManager: LeiaDisplayManager? = LeiaSDK.getDisplayManager(applicationContext)
displayManager?.requestBacklightMode(LeiaDisplayManager.BacklightMode.MODE_2D)
}
Java
@Override
protected void onPause() {
super.onPause();
exoPlayer.setPlayWhenReady(false);
LeiaDisplayManager displayManager = LeiaSDK.getDisplayManager(applicationContext);
displayManager.requestBacklightMode(LeiaDisplayManager.BacklightMode.MODE_2D);
}

You can learn more about the LeiaDisplayManager here.

Build your app

If you followed the steps above correctly, you should be able to play the SBS video in 4V. If you had trouble following the steps, you can checkout the sample app on Github