Cloudinary Blog

ExoPlayer Android Tutorial: Easy Video Delivery and Editing

ExoPlayer Android Tutorial: Easy Video Delivery and Editing

ExoPlayer is a media player library for Android developed and maintained by Google, which provides an alternative to the Android’s MediaPlayer. It comes with some added advantages over the default MediaPlayer, including dynamic adaptive streaming over HTTP (DASH), smooth streaming and common Encryption. One of its greatest advantage, however, is its easy customization.

Considering the mobile constraints related to resources such as videos, Exoplayer is an excellent choice for handling videos in your Android application. ExoPlayer offers video buffering, in which the video is downloaded ahead of time so as to give the user a seamless experience. With ExoPlayer, we can play videos either from our phone storage or from direct URLs, as we will see later on.

In this ExoPlayer android tutorial article, we will show how ExoPlayer provide a display solution in combination with Cloudinary, which supports video management and transformation.

Uploading Videos & Manipulations

Cloudinary helps us manage our video resources in the cloud with a high-performance cloud-based storage. With Cloudinary, we can comfortably upload videos and transform them by just tweaking URLs. Your videos are then delivered through fast Content Delivery Networks(CDNs) with advanced caching techniques. Let's take a look at how we can upload and manipulate videos with Cloudinary.

In our AndroidManifest.xml, we insert our cloud_name:

<meta-data
    android:name="CLOUDINARY_URL"
    android:value="cloudinary://@CLOUDINARY_NAME"/>

You should replace CLOUDINARY_NAME with the Cloudinary name found on your console. We then create an application class to initialize Cloudinary once throughout the app’s lifecycle. Since the AppController class is just initialized once, global variables are usually stored here.

import android.app.Application;
import com.cloudinary.android.MediaManager;
public class AppController extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // Initialize Cloudinary
        MediaManager.init(this);
    }
}

In our AndroidManifest.xml file, then we add our AppController class as the name of the application tag:

<application
    android:name=".AppController" >

Cloudinary offers unsigned and signed uploads. Signed uploads come with some added advantages, which require an API key. However, using an API key in an Android client is not recommended since it can easily be decompiled. For this reason, we will make use of the unsigned upload for this exoplayer android tutorial.

We first have to enable unsigned uploads in our console. Select settings on your dashboard, select the upload tab, scroll down to where you have upload preset, and enable unsigned uploading. A new preset will be generated with a random string as its name.

We then upload to Cloudinary by calling this:

MediaManager.get()
        .upload(videoUri)
        .unsigned("YOUR_PRESET")
        .option("resource_type", "video")
        .callback(new UploadCallback() {
            @Override
            public void onStart(String requestId) {

            }

            @Override
            public void onProgress(String requestId, long bytes, long totalBytes) {

            }

            @Override
            public void onSuccess(String requestId, Map resultData) {

            }

            @Override
            public void onError(String requestId, ErrorInfo error) {

            }

            @Override
            public void onReschedule(String requestId, ErrorInfo error) {

            }
        }).dispatch();

The videoUri is of type Uri. It represents the Uri of a video stored in your phone, which looks like this: content://media/external/video/media/3495

YOUR_PRESET should be replaced with the string that was generated after enabling unsigned upload.

When an upload is successful, the onSuccess method is called. This method provides us with the details of our upload, such as the URL, the public_url, which is the unique name of how the video is stored in Cloudinary. We will use the public_url to make our transformations in this method. Here is our transformation snippet:

String publicUrl = = (String) resultData.get("public_url");
String transformedUrl = MediaManager.get().url()
        .transformation(new Transformation()
                .effect("fade:2000").chain()
                .effect("fade:-3000").chain()
                .effect("saturation:-50")
        .resourceType("video").generate(publicUrl+".mp4");

We added three effects to our video: a two second fade-in, a three-second fade-out, and finally, a drop in the saturation of the video. The fade-in is usually represented with a positive value and the fade-out with a negative value. A negative saturation value means our video will have a faded look. If we print out our transformedUrl, it should look like this https://res.cloudinary.com/{CLOUD_NAME}/video/upload/e_fade:2000/e_fade:-3000/e_saturation:-50/{publicUrl}.mp4

Cloudinary offers many more transformations for our videos that you can learn about here.

Setting up ExoPlayer for your Android app

It is expected that you must have created an Android application, and for brevity, we won’t go through the process of doing that here. To make use of the ExoPlayer library, we first insert the gradle dependency in our build.gradle file:

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

If your gradle version is below 3.0, you should use the compile keyword instead of implementation to add dependencies.

Sync your gradle file so that the dependency will be downloaded and made available for the project. After that, we add the SimpleExoPlayerView to our Activity layout file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="180dp"
    android:layout_margin="16dp">

    <com.google.android.exoplayer2.ui.SimpleExoPlayerView
        android:id="@+id/exoplayer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

In the corresponding Activity class, in the onStart method, we will initialize our SimpleExoPlayerView and setup the SimpleExoPlayer by calling the initializePlayer method:

@Override
protected void onStart() {
    super.onStart();
    initializePlayer();
}

The initializePlayer method initializes our player with some standard default configurations to display videos seamlessly :

private void initializePlayer(){
    // Create a default TrackSelector
    BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory videoTrackSelectionFactory =
            new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector =
            new DefaultTrackSelector(videoTrackSelectionFactory);

    //Initialize the player
    player = ExoPlayerFactory.newSimpleInstance(this, trackSelector);

    //Initialize simpleExoPlayerView
    SimpleExoPlayerView simpleExoPlayerView = findViewById(R.id.exoplayer);
    simpleExoPlayerView.setPlayer(player);

    // Produces DataSource instances through which media data is loaded.
    DataSource.Factory dataSourceFactory =
            new DefaultDataSourceFactory(this, Util.getUserAgent(this, "CloudinaryExoplayer"));

    // Produces Extractor instances for parsing the media data.
    ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

    // This is the MediaSource representing the media to be played.
    Uri videoUri = Uri.parse("any Cloudinary URL");
    MediaSource videoSource = new ExtractorMediaSource(videoUri,
            dataSourceFactory, extractorsFactory, null, null);

    // Prepare the player with the source.
    player.prepare(videoSource);

}

From the above snippet;

  • We initialized the SimpleExoPlayer instance with some default configurations.
  • We created and initialized an instance of SimpleExoPlayerView. We then assigned our existing player instance to it.
  • We generated our media source using a videoUri parsed from a video URL from Cloudinary.

We then prepare the player with our video source and our video is ready to be displayed. This gives us a basic implementation of ExoPlayer.

We created the SimpleExoPlayer instance as a class variable to make it accessible to all methods in the class.

We have to release our player when no longer in use to save resources :

@Override
public void onPause() {
    super.onPause();
    if (player!=null) {
        player.release();
        player = null;
    }
}

Finally, we need to provide the app permissions to access the internet. We add the internet permission in our AndroidManifest.xml file :

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

This is how our app should look like if we play the transformed URL with ExoPlayer.

ExoPlayer

Conclusion

Cloudinary provides us with an excellent video management solution and integrating it with libraries, such as ExoPlayer, to display videos on our Android app is very easy. In this exoplayer android tutorial, we have shown how we can upload and transform videos, then display them. Cloudinary offers many more features and functionalities, which you can checkout here in the docs.

Code Source on Github

Recent Blog Posts

An Eye-Opening Talk: Building Apps for the Next Billion Users in Africa

William (iChuloo) Imoh, who hails from Lagos, Nigeria, recently embarked on a U.S. speaking tour, February 20-March 12, during which he powwowed with technical and product teams and communities at such renowned enterprises as Netlify, Pluralsight, Lucidchart, Twilio, and more in Salt Lake City, Dallas, Las Vegas, and San Francisco. On March 5, he gave an enlightening talk, entitled International Developers and Development: Building for the Next Billion Users at Cloudinary in Santa Clara, California. Below is a synopsis. For details, see the related slides.

Read more
The Debut of the Cloudinary Customer Advisory Board

Focus on customers has always been Cloudinary’s mantra. Because we owe them our success, we are constantly reaching out to our customers, not just for feedback on our offerings, but also for their vision, wish list, and buy-in of what Cloudinary can do to meet their needs and make them succeed. About six months ago, it occurred to us that it would be beneficial if we could meet regularly with those who are behind innovation at our key customers—executives, product gurus, developers, content managers—to swap strategies, product roadmaps, best practices, and such. In particular, we’d like to solicit actionable feedback as a foundation for our plans of product enhancements.

Read more
Media Management With the Cloudinary-Netlify CMS Integration

Static sites and the JAMstack are quickly becoming a standard for developing safe and performant websites with an optimal workflow for developers. Netlify CMS (not to be confused with the company that created it, Netlify) is an open source content management solution that works especially with static site generators such as Gatsby, Hugo, etc... enabling content storage in your Git repository along with your code for easier versioning, multichannel publishing, and direct content updates in Git.

Read more
Vitaly Friedman's Insights on Media Conferences

Vitaly Friedman is a die-hard devotee of beautiful content. Born in Minsk, Belarus, he studied Computer Science and Mathematics in Germany, unearthing in himself a passion for typography, writing, and design in the interim. After a six-year stint as a freelance designer and developer, he co-founded Smashing Magazine, a leading online publication on web design and development. You can follow SmashingMag on Twitter @SmashingMag.

Read more