Xamarin Forms Android – using ExoPlayer in your app

Playing a video on a Xamarin Forms Android app is something that can be achieved without a lot of trouble.
There is the VideoView control, which you can very easily use in your app.

But what about playing some less standard formats?
How about DASH format? Or Smooth Streaming?

 

Introduction

Google is providing us with a very useful and nice library, called ExoPlayer.
From GitHub documentation:

ExoPlayer is an application level media player for Android. It provides an alternative to Android’s MediaPlayer API for playing audio and video both locally and over the Internet. ExoPlayer supports features not currently supported by Android’s MediaPlayer API, including DASH and SmoothStreaming adaptive playbacks. Unlike the MediaPlayer API, ExoPlayer is easy to customize and extend, and can be updated through Play Store application updates.

Looks like exactly what we need.

So where is the catch?
Well, the library is written in Java.

 


TL;DR Version

If all you want is the code and you can handle it yourself,
Feel free to check the example on my GitHub.


 

Java library binding

For these purposes, Xamarin provides us with an option to create a DLL from a Java library.
This is basically a wrapper around a Java library, which provides access to the library with a C# like feel.

You can read more about how this can be achieved in the official Xamarin guide on Binding a Java Library.

If you are interested in how this works, you can go ahead and give it a try.
However, lucky for us, Martijn van Dijk already created this binding for us.
Check the GitHub repo. It has all the code, examples and more.
Thank you Martijn! 🙂

If you know your way around Xamarin, this should be enough for you to already start coding.
If you need a more step-by-step example, keep reading. 😉

 


Make it happen

 

Create the skeleton

Let’s start from the basics.
We need two things here:

  1. A video player control in our PCL project.
  2. A custom renderer for our control in our Android project.

If you are not familiar with renderers, I strongly recommend that you first read the official Xamarin guide about Custom Renderers.

The control

Our control will be a very simple one, just for the purpose of keeping the demo simple.
You could, of course, extend it for your own needs.

All we are going to have in our control is a Bindable Property for our video source url.

public class VideoPlayer : View
{
    public static readonly BindableProperty SourceUrlProperty = 
        BindableProperty.Create("SourceUrl", typeof(string), typeof(VideoPlayer));

    public string SourceUrl
    {
        get => (string)GetValue(SourceUrlProperty);
        set => SetValue(SourceUrlProperty, value);
    }
}

This will allow us to keep the example simple and straight to the point.

The NuGet

Now would be a good time to get the Xam.Plugins.Android.ExoPlayer NuGet pacakge by Martijn.
The package should be installed only in your Android project.

The custom renderer

For the custom renderer, we are going to use the generic ViewRenderer:

public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, SimpleExoPlayerView>
{
    public VideoPlayerRenderer(Context context) : base(context) { }
}

As you can see, we are setting our native control to be of the type SimpleExoPlayerView, which is available from the NuGet package we are using.

 

Let’s use the ExoPlayer

I’ve divided the whole logic into two methods:

  1. InitializeControl
  2. Play

Each method speaks for itself.
So for starters, let’s add our private members and our OnElementChange override:

private SimpleExoPlayerView _playerView;
private SimpleExoPlayer _player;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> e)
{
    base.OnElementChanged(e);

    if (_player == null)
        InitializePlayer();

    Play();
}

Nothing interesting is going on here. Pretty standard code.
So let’s dig in.

InitializePlayer

Now it is getting serious.

For initialization, we have two parts:

  1. The visual element for our player: SimpleExoPlayerView
  2. The logical element for our player: SimpleExoPlayer

Let’s initialize them!

private void InitializePlayer()
{
    _player = ExoPlayerFactory.NewSimpleInstance(Context, new DefaultTrackSelector());
    _player.PlayWhenReady = true;
    _playerView = new SimpleExoPlayerView(Context) { Player = _player };
    SetNativeControl(_playerView);
}

Without going too much into details, here is what happening here:

  1. We initialize our player.
  2. We set it to start playing the video once the video is ready to be played.
  3. We initialize our view element and set it’s logical player to the one we just created.
  4. We set the native control of our custom control to be the SimpleExoPlayerView.

You can go over the ExoPlayer documentation to learn more about what options you have. In this demo, I’m trying to keep it as simple as possible.

Play

Now comes the part where we initialize the video itself.
The format I’m going to use is Microsoft`s Smooth Streaming.
So let’s see how our Play method looks like:

private void Play()
{
    Uri sourceUri = Uri.Parse(Element.SourceUrl);
    DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory("1");
    DefaultSsChunkSource.Factory ssChunkFactory = new DefaultSsChunkSource.Factory(httpDataSourceFactory);
    Handler emptyHandler = new Handler();

    SsMediaSource ssMediaSource = new SsMediaSource(sourceUri, httpDataSourceFactory, ssChunkFactory, emptyHandler, this);
    _player.Prepare(ssMediaSource);
}

Now let’s break this down.

  1. Create a Uri from our source in the PCL element.
  2. Create a default http data source.
  3. Create a smooth streaming chunk factory.
  4. Create an empty handler.
  5. Initialize a smooth streaming media source.
    Note
    As our last parameter, we are passing the current renderer class.
    For this to work, our renderer class has to implement the IAdaptiveMediaSourceEventListener interface,
    Which provides us with methods on different states of the player.
    For this demo, I’ve left all the methods empty, with no implementation.
  6. Prepare the player with the media source.

I’m not going to deep dive into all those different classes. If you are willing to learn more about them, about how to initialize other formats or use other features of the ExoPlayer library, you can always check the ExoPlayer official website, which has a lot of reading materials about it.

 

Final Touch

Now, all is left to do is to provide our custom control with a stream URL.
For this demo I’m using a sample video, provided by Microsoft, of Big Buck Bunny by Blender Institute.
(c) Copyright 2008, Blender Foundation | www.bigbuckbunny.org

This is how our MainPage.xaml in the PCL looks like:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:ExoPlayerDemo" x:Class="ExoPlayerDemo.MainPage">

    <!-- Azure Media Services Sample -->
    <!-- Read more at http://playready.azurewebsites.net/Home/AdaptiveTests -->
    <!-- (c) Copyright 2008, Blender Foundation | www.bigbuckbunny.org -->
    <local:VideoPlayer SourceUrl="http://amssamples.streaming.mediaservices.windows.net/683f7e47-bd83-4427-b0a3-26a6c4547782/BigBuckBunny.ism/manifest"/>

</ContentPage>

That is it!
If everything went as planned, you should be able to see the following result:

There is a lot more to do with the ExoPlayer library!
This is just a very simple sample code for an easy start.

Feel free to see the whole code sample on my GitHub.

6 thoughts on “Xamarin Forms Android – using ExoPlayer in your app”

  1. Getting following error,
    **Java.Lang.AbstractMethodError:** ‘abstract method “void com.google.android.exoplayer2.source.MediaSourceEventListener.onLoadStarted(int, com.google.android.exoplayer2.source.MediaSource$MediaPeriodId, com.google.android.exoplayer2.source.MediaSourceEventListener$LoadEventInfo, com.google.android.exoplayer2.source.MediaSourceEventListener$MediaLoadData)”‘

    [eglCodecCommon] allocate: Ask for block of size 0x152000
    [eglCodecCommon] allocate: ioctl allocate returned offset 0x3ff4c6000 size 0x153000
    [SoftwareRenderer] setting dataspace on output surface to #104
    [e.ExoPlayerDem] Background concurrent copying GC freed 65(48KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 5519KB/10MB, paused 690us total 225.081ms
    [AudioTrack] getTimestamp_l(20): device stall time corrected using current time 32478012982780
    [AudioTrack] getTimestamp_l(20): stale timestamp time corrected, currentTimeNanos: 21686177838700 < limitNs: 32477728832580 < mStartNs: 32477789832580
    [AudioTrack] getTimestamp_l(20): retrograde timestamp time corrected, 32477728832580 < 32478012982780
    [eglCodecCommon] allocate: Ask for block of size 0x2f8000
    [eglCodecCommon] allocate: ioctl allocate returned offset 0x3ff320000 size 0x2f9000

  2. Any updates for this ?
    a lot of the stuff here are now Obsolete and the viewPlayer.Player property is totally removed since v 2.11.3
    this example is great but by the time i found it the v 2.11.3 came out and crippled this example

  3. Hi bro! Have you build this project with net standard or pcl? I tried install the nugget package on my net standard solution xamarin forms and crash it! I didnt install it, Do you know if this example work with net standard? Thank you ver much!

    1. Hi Franco,
      Just to make sure, I’ve double checked my repo on GitHub. The Xamarin.Forms project is set to target .net standard 2.0.

      I’m not sure what crash you are experiencing, so feel free to post some more details about the crash and I’ll do my best to help you out. 🙂

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top