Cloudinary Blog

Easy Video Editing and Delivery for the Android ExoPlayer: A Tutorial

ExoPlayer Android Tutorial: Easy Video Delivery and Editing

ExoPlayer, a media player for Android, was developed and is being maintained by Google as an alternative for Android’s default MediaPlayer. Among ExoPlayer’s advantages over MediaPlayer are dynamic adaptive streaming over HTTP (DASH), smooth streaming, and common encryption. A major advantage, however, is ExoPlayer’s easy customization.

Given the mobile constraints for resources, such as videos, ExoPlayer is an excellent choice for playing videos in Android apps because of its video-buffering capability, which downloads videos ahead of time for a seamless experience. You can play videos with ExoPlayer from phone storage or from URLs, as described later in this tutorial.


Sign up for Cloudinary free today!


Through an Android example app for ExoPlayer, this tutorial shows you how to leverage Cloudinary, a cloud-based service platform on which you can upload rich media for cloud storage as well as efficiently and effectively manage and transform them, in order to seamlessly display videos on ExoPlayer.

Note
Here’s a handy reference guide: Media Playback on Android with ExoPlayer: Getting Started

Uploading and Transforming Videos

With Cloudinary, you can transform videos by simply tweaking their URLs. Cloudinary then delivers the videos through fast Content Delivery Networks (CDNs) with advanced caching techniques.

Follow the steps below to upload and transform videos in Cloudinary.

  1. Replace CLOUDINARY_NAME in the AndroidManifest.xml file with your cloud name, which is displayed in the console of your Cloudinary account:

    Copy to clipboard
    <meta-data
    android:name="CLOUDINARY_URL"
    android:value="cloudinary://@CLOUDINARY_NAME"/>
  2. Create an application class to initialize Cloudinary once for the app’s entire lifecycle. Given this one-time initialization, the global variables usually reside in this class.

    Copy to clipboard
    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);
    }
    }
  3. Also in the AndroidManifest.xml file, specify AppController as the name of the application tag:

    Copy to clipboard
    <application
    android:name=".AppController" >

    Note
    Your uploads can be unsigned or signed. Signed uploads, which offer certain benefits, require an API key, which is not recommended for Android clients because it can be easily decompiled. Hence, opt for unsigned upload here.

  4. Enable unsigned uploads in your console: click the Settings icon on your dashboard and then the Upload tab, scroll down to the Upload Presets section, and enable unsigned uploading. Cloudinary then generates a new preset with a random string as its name.

  5. Upload to Cloudinary by calling this function:

    Copy to clipboard
    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();

videoUri is of type Uri, which represents the Uniform Resource Identifier (URI) of the video that resides in your phone, e.g., content://media/external/video/media/3495.

Note
Be sure to replace YOUR_PRESET with the string generated by Cloudinary after you’ve enabled unsigned upload.

On a successful upload, Cloudinary calls the onSuccess method, which contains the details of your upload, such as URL (the URL) and public_url (the public URL), which is the unique name of the video as stored in Cloudinary.

Next, transform the video in the method below by referring to public_url:

Copy to clipboard
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");

You’ve now added three effects to the video:

  • A two-second fade-in. Fade-ins usually have a positive value.
  • A three-second fade-out. Fade-outs usually have a negative value.
  • A drop in the saturation. A negative saturation value results in a faded look of the video.

A printout of transformedUrl reads like this: https://res.cloudinary.com/{CLOUD_NAME}/video/upload/e_fade:2000/e_fade:-3000/e_saturation:-50/{publicUrl}.mp4

For details on Cloudinary’s many transformation capabilities, see this section in a Cloudinary post. To learn about video transformations on Cloudinary, see the related documentation.

Setting Up ExoPlayer for Android Apps

It is assumed that you have developed an Android app, hence this section does not address that process. Follow the steps below to set up ExoPlayer for your app:

  1. Add the Gradle dependency to your build.gradle file to make use of the ExoPlayer library:

    Copy to clipboard
    implementation 'com.google.android.exoplayer:exoplayer:2.6.0'

    Note
    If your Gradle version is below 3.0, replace implementation in the above snippet with compile.

  2. Sync your gradle file to ensure a download of the dependency for the project.

  3. Add SimpleExoPlayerView to your Activity layout:

    Copy to clipboard
    <?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"/>
  4. In the onStart method in the corresponding Activity class, initialize SimpleExoPlayerView and set up SimpleExoPlayer by calling the initializePlayer method:

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

    initializePlayer applies the default configurations for a seamless display of videos in ExoPlayer:

    Copy to clipboard
    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);
    
    }

The above snippet performs these tasks:

  • Initializes the SimpleExoPlayer instance with the default configurations.
  • Creates and initializes an instance of SimpleExoPlayerView and assigns your existing player instance to it.
  • Generates the media source with videoUri parsed from a video URL (URL) from Cloudinary.

Now prepare the player with the video source, after which the video is ready for display. You now have a basic implementation of ExoPlayer.

Note
The SimpleExoPlayer instance is a class variable here, accessible to all the methods in the class.

5. To save resources, add the code below to release the player when it’s not in use:

Copy to clipboard
```java

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

Finally, add the permissions for the app to access the internet in the AndroidManifest.xml file :

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

The app looks like this if you play the transformed URL with ExoPlayer.

ExoPlayer

Exploring Cloudinary Further

You can integrate Cloudinary, which offers robust capabilities for video management, with libraries like ExoPlayer to display videos on Android apps. It’s an intuitive, easy process. For details on optimizing videos with Cloudinary, see this post. Also see the Cloudinary documentation for other media-management features.


Want to Learn More About Video Optimization?

Recent Blog Posts

Automatically Translating Videos for an International Audience

No matter your business focus—public service, B2B integration, recruitment—multimedia, in particular video, is remarkably effective in communicating with the audience. Before, making video accessible to diverse viewers involved tasks galore, such as eliciting the service of production studios to manually dub, transcribe, and add subtitles. Those operations were costly and slow, especially for globally destined content.

Read more
Cloudinary Helps Minted Manage Its Image-Generation Pipeline at Scale

David first shared his thoughts at our ImageCon coverence last October and this case study is an abbreviated version of Minted’s success using Cloudinary.

Over time, Faithful renderings of the creations of the illustrators, textile designers, painters, packaging designers, marketers, and stay-at-home moms, all of whom are core contributors of the Minted world, was getting harder and harder. Legacy technology wasn’t cutting it any more—and it was time for Cloudinary to step in.

Read more
Highlights on ImageCon 2021 and a Preview of ImageCon 2022

New year, same trend! Visual media will continue to play a monumental role in driving online conversions. To keep up with visual-experience trends and best practices, Cloudinary holds an annual conference called ImageCon, a one-of-a-kind event that helps attendees create the most engaging visual experiences possible.

Read more

New for DAM: Media Library Extension for Chrome

By Sharon Yelenik
A New Media Library Chrome Extension for Cloudinary DAM

With the introduction of the Media Library Extension, a Chrome-browser add-on that streamlines the access to, search for, and management of images and videos, Cloudinary offers yet another effective tool for its Digital Asset Management (DAM) solution. Let’s have a look at how most teams are currently working with media assets and how the new add-on not only boosts efficiency, but also renders the process a pleasure to work with.

Read more
New Features Supercharge Cloudinary’s Digital Asset Management Solution.

Today, I’m thrilled to announce the launch of Apps for Digital Asset Management and a Media Library Extension for the Chrome browser, which enables easy, flexible integration with all web-based applications in addition to making asset discovery more robust and accessible to all.

Read more
Scale and Automate Workflows With Modern Digital Asset Management Systems

With building, growing, and maintaining a strong digital presence being a top priority for all brands, high-quality visual content is paramount. In fact, consumers are 40 times more likely to share visual content on social networks than on other forums. Plus, a recent study from Wyzowl found that 84% of consumers made purchase decisions after watching a video, which explains why many brands are adding more and more visual media to their sites.

Read more