{"id":12004,"date":"2026-06-28T16:05:12","date_gmt":"2026-06-28T16:05:12","guid":{"rendered":"https:\/\/www.vdocipher.com\/blog\/?p=12004"},"modified":"2026-06-29T10:48:40","modified_gmt":"2026-06-29T10:48:40","slug":"exoplayer","status":"publish","type":"post","link":"https:\/\/www-uat.vdocipher.com\/blog\/exoplayer\/","title":{"rendered":"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android with DRM"},"content":{"rendered":"\r\n<p>If you&#8217;re building an Android application that streams video, choosing the right media player is critical for performance, security, and user experience.<br \/>Google&#8217;s ExoPlayer, now part of AndroidX Media3, is the most widely used media playback library for Android. It supports adaptive streaming formats such as HLS and MPEG-DASH, Widevine DRM, subtitles, offline playback, and advanced customization beyond what the native MediaPlayer API offers.<\/p>\r\n<p>In this guide, you&#8217;ll learn how to integrate Media3 ExoPlayer into your Android application, stream secure videos, implement DRM protection, and optimize playback for production-ready apps.<\/p>\r\n<div class=\"border-box\" style=\"border: 1px solid;\">Table Of Content\r\n<ul>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#exoplayer\">What is an ExoPlayer?<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#advantage\">What are the Advantages of Using Exoplayer?<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#vs\">ExoPlayer vs Android MediaPlayer<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#implement\">How To Implement Exoplayer in Android?<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#customize\">How To Customize Exoplayer<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#drmcontent\">How To Play DRM Content On Exoplayer?<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#adaptive\">Adaptive Bitrate Streaming in Exoplayer<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#vdocipher\">How VdoCipher Streams Video on Android Using ExoPlayer<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#error\">Common ExoPlayer Errors and Solutions<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#conc\">Conclusion<\/a><\/li>\r\n<li><a style=\"color: #069; text-decoration: none;\" href=\"#faqs\">FAQs<\/a><\/li>\r\n<\/ul>\r\n<\/div>\r\n<h1 class=\"wp-block-heading\" id=\"exoplayer\">What is an ExoPlayer?<\/h1>\r\n\r\n\r\n\r\n<p>ExoPlayer is Google&#8217;s open-source media playback library for Android and is now part of the AndroidX Media3 library. It provides a flexible and extensible framework for playing local and streaming media while supporting modern formats such as HLS, MPEG-DASH, and Widevine DRM.<\/p>\r\n\r\n\r\n\r\n<p>ExoPlayer is the recommended media playback library for Android applications that require adaptive streaming, DRM protection, subtitles, and advanced playback customization. It supports various features such as <a href=\"https:\/\/www.vdocipher.com\/blog\/adaptive-bitrate-streaming\" target=\"_blank\" rel=\"noreferrer noopener\" data-type=\"URL\" data-id=\"https:\/\/www.vdocipher.com\/blog\/adaptive-bitrate-streaming\">Dynamic Adaptive Streaming<\/a> over HTTP(<a href=\"https:\/\/www.vdocipher.com\/blog\/mpeg-dash\">DASH<\/a>), <a href=\"https:\/\/www.vdocipher.com\/blog\/2017\/08\/hls-streaming-hls-encryption-secure-hls-drm\/\">HTTP Live Streaming<\/a>(HLS), Smooth Streaming, and Common Encryption. Exoplayer supports playback of both audio and video content from local storage as well as online streaming using modern adaptive streaming protocols.\u00a0<\/p>\r\n<p>We can add features like captions, speed control, forward, rewind, etc. to the player. ExoPlayer supports secure playback of DRM-protected content using technologies such as Widevine DRM and Common Encryption (CENC), making it suitable for premium video streaming applications.<\/p>\r\n<p>In the following sections, we&#8217;ll explore ExoPlayer&#8217;s key features, advantages, and why it is the preferred choice over Android&#8217;s built-in MediaPlayer API for modern video streaming applications.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"advantage\">What are the Advantages of Using Exoplayer?<\/h2>\r\n\r\n\r\n\r\n<p>ExoPlayer has a number of advantages over Android&#8217;s built-in MediaPlayer:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><strong>Consistent Playback Across Devices:<\/strong> ExoPlayer provides a more reliable playback experience with fewer device-specific issues and consistent behavior across different Android versions and manufacturers.<\/li>\r\n<li><strong>Independent Updates:<\/strong> Since ExoPlayer is included as a library within your application (now through AndroidX Media3), you can easily upgrade to the latest version to benefit from new features, performance improvements, and bug fixes without waiting for Android OS updates<\/li>\r\n<li><strong>Wide Format Compatibility:<\/strong> Play a wide range of audio and video formats, including MP4, WebM, MKV, AAC, MP3, FLAC, and more, without relying on device-specific codec support.<\/li>\r\n<li><strong>Highly Customizable:<\/strong> ExoPlayer is designed to be modular and extensible, allowing developers to replace or customize various player components to meet specific application requirements.<\/li>\r\n<li><strong>Built-in Playlist Support<\/strong>: Easily create and manage playlists, enabling seamless playback of multiple media items within your application.<\/li>\r\n<li><strong>Support for Modern Streaming Formats:<\/strong> In addition to MPEG-DASH and SmoothStreaming, ExoPlayer offers comprehensive support for HLS, including advanced features such as handling #EXT-X-DISCONTINUITY tags and seamless media concatenation and looping.<\/li>\r\n<li><strong>Widevine DRM Support:<\/strong> ExoPlayer supports Widevine DRM and Common Encryption (CENC), enabling secure playback of protected content on supported Android devices.\u00a0<\/li>\r\n<li><strong>Easy Integration with Extensions:<\/strong> Extend ExoPlayer&#8217;s capabilities using official extensions such as Google IMA for ad insertion, FFmpeg for additional codec support, and other media-related libraries.<\/li>\r\n<\/ul>\r\n<div style=\"border: 1px solid #DEE2E6!important; border-radius: 0.25rem!important; background-color: #ecf0f1;\">\r\n<p style=\"font-size: 19px !important; font-weight: 600; margin: 0!important; padding: 1rem!important;\">Explore More \u2705<\/p>\r\n<p style=\"font-size: 20px !important; font-weight: 400; margin: 0!important; padding-bottom: 1rem!important; padding-right: 1rem!important; padding-left: 1rem!important;\"><a style=\"color: #0d6efd; text-decoration: underline;\" href=\"https:\/\/www.vdocipher.com\/page\/features\/?utm_source=blog&amp;utm_medium=banner-cta&amp;utm_campaign=feature\">Stream Your Content Securely On Android With VdoCipher<\/a><\/p>\r\n<p style=\"font-size: 18px !important; font-weight: 400; margin: 0!important; padding-bottom: 1rem!important; padding-right: 1rem!important; padding-left: 1rem!important;\">VdoCipher helps provide end-to-end solutions for video, right from hosting, encoding, and encryption to the player. On top of it, you get APIs to manage videos, players, and more.<\/p>\r\n<\/div>\r\n<hr \/>\r\n<h2 id=\"vs\">ExoPlayer vs Android MediaPlayer<\/h2>\r\n<p>While Android&#8217;s built-in MediaPlayer API is suitable for basic media playback, ExoPlayer (Media3) offers significantly more flexibility, better streaming support, and advanced features required for modern video applications. The table below highlights the key differences between the two.<\/p>\r\n\r\n<table>\r\n<thead>\r\n<tr>\r\n<th>Feature<\/th>\r\n<th>Android MediaPlayer<\/th>\r\n<th>ExoPlayer (Media3)<\/th>\r\n<\/tr>\r\n<\/thead>\r\n<tbody>\r\n<tr>\r\n<td>Adaptive Streaming<\/td>\r\n<td>Limited<\/td>\r\n<td>Supported<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>HLS Support<\/td>\r\n<td>Basic<\/td>\r\n<td>Advanced<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>MPEG-DASH Support<\/td>\r\n<td>Not supported natively<\/td>\r\n<td>Supported<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Widevine DRM<\/td>\r\n<td>Limited<\/td>\r\n<td>Supported<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Offline Playback<\/td>\r\n<td>Limited<\/td>\r\n<td>Supported<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Playlist Support<\/td>\r\n<td>Basic<\/td>\r\n<td>Advanced<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Custom UI<\/td>\r\n<td>Limited<\/td>\r\n<td>Highly customizable<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Subtitles<\/td>\r\n<td>Basic<\/td>\r\n<td>Advanced subtitle support<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Regular Updates<\/td>\r\n<td>Depends on Android OS updates<\/td>\r\n<td>Updated through AndroidX Media3<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n\r\n<p>For simple audio or video playback, Android MediaPlayer may be sufficient. However, if your application requires adaptive streaming, DRM protection, subtitles, live streaming, offline playback, or extensive customization, ExoPlayer (Media3) is the recommended solution for modern Android development.<\/p>\r\n<hr \/>\r\n<h2 class=\"wp-block-heading\" id=\"implement\">How To Implement Exoplayer in Android with examples?<\/h2>\r\n\r\n\r\n\r\n<p>We will create a simple exoplayer application to play a video using MediaItem.<\/p>\r\n\r\n\r\n\r\n<p>The steps to implement Exoplayer are as follows:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li>Add exoplayer dependencies in your app level build.gradle<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>    implementation 'com.google.android.exoplayer:exoplayer-core:2.18.0'\r\n    implementation 'com.google.android.exoplayer:exoplayer-dash:2.18.0'\r\n    implementation 'com.google.android.exoplayer:exoplayer-hls:2.18.0'\r\n    implementation 'com.google.android.exoplayer:exoplayer-ui:2.18.0'<\/code><\/pre>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\" start=\"2\">\r\n<li>Add SimpleExoPlayerView in layout file A <code>SimpleExoPlayerView<\/code> can be included in the layout for an Activity belonging to a video application as follows:<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>&lt;FrameLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"&gt;\r\n\r\n&lt;com.google.android.exoplayer2.ui.SimpleExoPlayerView \r\n    android:id=\"@+id\/exoPlayerView\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\/&gt;\r\n\r\n&lt;\/FrameLayout&gt;<\/code><\/pre>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\" start=\"3\">\r\n<li>Create and load the player In your Activity, create an instance of <code>Exoplayer<\/code> and add it to the <code>SimpleExoPlayerView<\/code><br \/><code>MediaItem<\/code> represents a media which can be added to the player at the time of preparation. After the player is prepared you can set set <code>setPlayWhenReady<\/code> to start the playback when media is ready.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>SimpleExoPlayerView playerView = findViewById(R.id.exoPlayerView);\r\nExoPlayer player = new ExoPlayer.Builder(context).build();\r\n\/\/ Bind the player to the view.\r\nplayerView.setPlayer(player);\r\n\/\/ Create and add media item\r\nMediaItem mediaItem = MediaItem.fromUri(video_url);\r\nplayer.addMediaItem(mediaItem);\r\n\/\/ Prepare exoplayer\r\nplayer.prepare();\r\n\/\/ Play media when it is ready\r\nplayer.setPlayWhenReady(true);<\/code><\/pre>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\" start=\"4\">\r\n<li>Handling the player controls Methods on the player can be called to control the player. Below are some of the methods:<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><code>play<\/code> and <code>pause<\/code>: Used to play and pause the video<\/li>\r\n<li><code>seekTo<\/code>: Seeks to a position specified in milliseconds in the current MediaItem<\/li>\r\n<li><code>playWhenReady<\/code>: Whether playback should proceed when ready<\/li>\r\n<li><code>hasNextMediaItem<\/code>, <code>hasPreviousMediaItem<\/code>, <code>seekToPreviousMediaItem<\/code>, <code>seekToNextMediaItem<\/code>: Allows navigating through the playlist<\/li>\r\n<li><code>setPlaybackParameters<\/code>: Attempts to set the playback parameters.Playback parameters changes may cause the player to buffer. <code>Player.Listener.onPlaybackParametersChanged(PlaybackParameters<\/code>) will be called whenever the currently active playback parameters change<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\" start=\"4\">\r\n<li>Release the player Use <code>ExoPlayer.release<\/code> method to release the player after when it is no longer required.<\/li>\r\n<\/ol>\r\n\r\n<p>&nbsp;<\/p>\r\n\r\n<pre class=\"wp-block-code\"><code>if (exoPlayer != null) {\r\n    exoPlayer.release();\r\n}<\/code><\/pre>\r\n\r\n<p><a href=\"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2025\/08\/d91630a7-026d-40bb-81b4-dad61120d639.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-21944\" src=\"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2025\/08\/d91630a7-026d-40bb-81b4-dad61120d639.png\" alt=\"How to Implement ExoPlayer (Media3) in Android\" width=\"1536\" height=\"1024\" srcset=\"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2025\/08\/d91630a7-026d-40bb-81b4-dad61120d639.png 1536w, https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2025\/08\/d91630a7-026d-40bb-81b4-dad61120d639-300x200.png 300w\" sizes=\"auto, (max-width: 1536px) 100vw, 1536px\" \/><\/a><\/p>\r\n<hr \/>\r\n<h2 class=\"wp-block-heading\" id=\"customize\">How to Customize Exoplayer?<\/h2>\r\n\r\n\r\n\r\n<p>ExoPlayer comes with many customizations available such as UI adjusting to match your app, deciding caching mechanism for data loaded from the network, customizing server interaction to intercept HTTP requests and responses, customizing error handling policy, enabling asynchronous buffer queueing, and many more. In this section, we will look at how we can customize UI with ExoPlayer.<\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Customizing ExoPlayer&#8217;s UI components<\/h3>\r\n\r\n\r\n\r\n<p>ExoPlayer V2 includes several out-of-the-box UI components for customization, most notably:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><strong>SimpleExoPlayerView<\/strong> is a high level view for SimpleExoPlayer media playbacks. It displays video, subtitles and album art during playback, and displays playback controls using a PlaybackControlView.<\/li>\r\n<li><strong>PlaybackControlView<\/strong> is a view for controlling ExoPlayer instances. It displays standard playback controls including a play\/pause button, fast-forward and rewind buttons, and a seek bar.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p>Use of this view is optional. You are free to implement your own UI components by yourself at the cost of some extra work. The SimpleExoPlayerView displays video, subtitles, and album art during playback, and displays playback controls using a <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/PlaybackControlView.html\">PlaybackControlView<\/a>.<\/p>\r\n\r\n\r\n\r\n<p>A SimpleExoPlayerView can be customized by setting attributes (or calling corresponding methods), overriding the view&#8217;s layout file or by specifying a custom view layout file, as mentioned below.<\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Setting attributes for SimpleExoPlayerView<\/h3>\r\n\r\n\r\n\r\n<p>A SimpleExoPlayerView can be included in the layout for an Activity belonging to a video application as follows<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>&lt;FrameLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"&gt;\r\n\r\n&lt;com.google.android.exoplayer2.ui.SimpleExoPlayerView \r\n    android:id=\"@+id\/player\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\/&gt;\r\n\r\n&lt;\/FrameLayout&gt;<\/code><\/pre>\r\n\r\n\r\n\r\n<p>Now you can use following attributes on SimpleExoPlayerView to customize it when used in a layout XML file.<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><strong>use_artwork<\/strong> &#8211; Whether artwork is used if available in audio streams.<\/li>\r\n<li><strong>default_artwork<\/strong> &#8211; Default artwork to use if no artwork available in audio streams.<\/li>\r\n<li><strong>use_controller<\/strong> &#8211; Whether the playback controls can be shown.<\/li>\r\n<li><strong>hide_on_touch<\/strong> &#8211; Whether the playback controls are hidden by touch events.<\/li>\r\n<li><strong>auto_show<\/strong> &#8211; Whether the playback controls are automatically shown when playback starts, pauses, ends, or fails. If set to false, the playback controls can also be manually operated with <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/SimpleExoPlayerView.html#showController--\">showController()<\/a> and <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/SimpleExoPlayerView.html#hideController--\">hideController()<\/a>.<\/li>\r\n<li><strong>resize_mode<\/strong> &#8211; Controls how video and album art is resized within the view. Valid values are fit, fixed_width, fixed_height and fill.<\/li>\r\n<li><strong>surface_type<\/strong> &#8211; The type of surface view used for video playbacks. Valid values are surface_view, texture_view and none. Using none is recommended for audio only applications, since creating the surface can be expensive. Using surface_view is recommended for video applications.<\/li>\r\n<li><strong>shutter_background_color<\/strong> &#8211; The background color of the exo_shutter view.<\/li>\r\n<li><strong>player_layout_id<\/strong> &#8211; Specifies the id of the layout to be inflated.<\/li>\r\n<li><strong>controller_layout_id<\/strong> &#8211; Specifies the id of the layout resource to be inflated by the child <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/PlaybackControlView.html\">PlaybackControlView<\/a>.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Overriding the view&#8217;s layout file<\/h3>\r\n\r\n\r\n\r\n<p>To customize the layout of SimpleExoPlayerView throughout your app, or just for certain configurations, you can define <em>exo_simple_player_view.xml<\/em> layout files in your application <em>res\/layout<\/em>* directories. These layouts will override the one provided by the ExoPlayer library, and will be inflated for use by SimpleExoPlayerView. The view identifies and binds its children by looking for the following ids:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><strong>exo_content_frame<\/strong> &#8211; A frame whose aspect ratio is resized based on the video or album art of the media being played, and the configured resize_mode. The video surface view is inflated into this frame as its first child. Type <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/AspectRatioFrameLayout.html\">AspectRatioFrameLayout<\/a><\/li>\r\n<li><strong>exo_shutter<\/strong> &#8211; A view that&#8217;s made visible when video should be hidden. This view is typically an opaque view that covers the video surface view, thereby obscuring it when visible. Type: View<\/li>\r\n<li><strong>exo_subtitles<\/strong> &#8211; Displays subtitles. Type: <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/SubtitleView.html\">SubtitleView<\/a><\/li>\r\n<li><strong>exo_artwork<\/strong> &#8211; Displays album art. Type: ImageView<\/li>\r\n<li><strong>exo_controller_placeholder<\/strong> &#8211; A placeholder that&#8217;s replaced with the inflated <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/PlaybackControlView.html\">PlaybackControlView<\/a>. Ignored if an exo_controller view exists. Type: View<\/li>\r\n<li><strong>exo_controller<\/strong> &#8211; An already inflated <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/PlaybackControlView.html\">PlaybackControlView<\/a>. Allows use of a custom extension of <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/PlaybackControlView.html\">PlaybackControlView<\/a>. Note that attributes such as rewind_increment will not be automatically propagated through to this instance. If a view exists with this id, any exo_controller_placeholder view will be ignored. Type: <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/PlaybackControlView.html\">PlaybackControlView<\/a><\/li>\r\n<li><strong>exo_overlay<\/strong> &#8211; A FrameLayout positioned on top of the player which the app can access via <a href=\"https:\/\/javadoc.io\/static\/com.google.android.exoplayer\/exoplayer-ui\/2.6.0\/com\/google\/android\/exoplayer2\/ui\/SimpleExoPlayerView.html#getOverlayFrameLayout--\">getOverlayFrameLayout()<\/a>, provided for convenience. Type: FrameLayout<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p>Any child views are optional, but where defined they must be of the expected type.<\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Specifying a custom layout file<\/h3>\r\n\r\n\r\n\r\n<p>Defining your own <em>exo_simple_player_view.xml<\/em> is useful to customize the layout of <strong>SimpleExoPlayerView<\/strong> throughout your application. It&#8217;s also possible to customize the layout for a single instance in a layout file. This can be achieved by setting the <em>player_layout_id<\/em> attribute on a SimpleExoPlayerView. This make specified layout inflated instead of <em>exo_simple_player_view.xml<\/em> for only the instance on which the attribute is set.<\/p>\r\n\r\n\r\n\r\n<p>For more customization option check <a href=\"https:\/\/exoplayer.dev\/customization.html\">official document on customizing ExoPlayer<\/a>.<\/p>\r\n<h3><b>Changing Video Quality in ExoPlayer on Android<\/b><\/h3>\r\n<p>To change the video quality in ExoPlayer, developers can utilize <strong>TrackSelector<\/strong> and <strong>DefaultTrackSelector<\/strong>. They can create a <strong>DefaultTrackSelector<\/strong>, configure it with desired parameters like bitrate, and then pass it to the ExoPlayer instance during initialization\u200b.<\/p>\r\n<h3><b>Changing ExoPlayer Aspect Ratio<\/b><\/h3>\r\n<p>Developers can set the aspect ratio of the ExoPlayer by creating a custom <strong>AspectRatioFrameLayout<\/strong> and wrapping it around the PlayerView. They can then use the <strong>setAspectRatio<\/strong> method on the <strong>AspectRatioFrameLayout<\/strong> to change the aspect ratio.<\/p>\r\n<h3><b>Implementing ExoPlayer Cache<\/b><\/h3>\r\n<p>Caching can be implemented in ExoPlayer by using the <strong>CacheDataSourceFactory<\/strong> which wraps around another <strong>DataSource.Factory<\/strong><strong> instance<\/strong>. A SimpleCache instance can be used to manage the cache, and the <strong>LeastRecentlyUsedCacheEvictor<\/strong> can be used to evict old data from the cache to ensure it doesn&#8217;t grow too large\u200b.<\/p>\r\n<h3><b>ExoPlayer Play Audio from URL<\/b><\/h3>\r\n<p>To play audio from a URL, developers can initialize a <strong>DefaultDataSourceFactory<\/strong> and a <strong>ProgressiveMediaSource<\/strong> (or other appropriate MediaSource depending on the audio format), and prepare the ExoPlayer instance with the MediaSource. The uri of the audio file needs to be passed to the MediaSource to start streaming and playing the audio.<\/p>\r\n<h3><b>ExoPlayer Play Local File<\/b><\/h3>\r\n<p>Playing a local file can be achieved by creating a MediaItem or a <strong>RawResourceDataSource<\/strong> with the URI of the local file, and then preparing the ExoPlayer instance with a MediaSource created with that URI. Developers can use the res\/raw folder to store and access local files, or use the assets directory if the file is stored there. They can use methods like <strong>RawResourceDataSource<\/strong>.<strong>buildRawResourceUri<\/strong> or <strong>MediaItem<\/strong>.<strong>fromUri<\/strong> to create a URI from the local file path<\/p>\r\n<hr \/>\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"drmcontent\">How To Play DRM Content On Exoplayer?<\/h2>\r\n\r\n\r\n\r\n<p>So far we have gone through the advantages of using ExoPlayer and how to customize it to suit our needs, in this section, we will see how to use ExoPlayer to play <a href=\"https:\/\/www.vdocipher.com\/blog\/2022\/02\/drm-content-protection\/\" target=\"_blank\" rel=\"noreferrer noopener\" data-type=\"URL\" data-id=\"https:\/\/www.vdocipher.com\/blog\/2022\/02\/drm-content-protection\/\">DRM-protected content<\/a> which is also mentioned as its advantage over the in-built MediaPlayer API.<\/p>\r\n\r\n\r\n\r\n<p>Before we start lets understand what is<a href=\"https:\/\/www.vdocipher.com\/blog\/2020\/12\/video-drm\/\" data-type=\"URL\" data-id=\"https:\/\/www.vdocipher.com\/blog\/2020\/12\/video-drm\/\"> Digital rights management<\/a> (DRM). Digital rights management (DRM) is way to protect copyrights for digital media. It has been developed to protect all kinds of digital materials prepared for computers and other technological devices, including movies, tv series, games, music and software. Putting these restrictions on DRM-protected content is creating security issues that prevent copying and distribution over the internet.<\/p>\r\n\r\n\r\n\r\n<p>ExoPlayer uses Android&#8217;s Media Drm API to support DRM protected playbacks.<\/p>\r\n\r\n\r\n\r\n<p>The minimum Android versions required for different supported DRM schemes, along with the streaming formats for which they&#8217;re supported are the following. In addition to the below table, playback is limited on older devices due to security updates. Android version 7 and above are more reliable to widevine playback.<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/NVVQdXfLDxMBFEZ3kvsOYCBweez5CrLAyL2Pj4gWNXc9TxSGvP1LXZkNnOCfMsqSEY0_ji1k1Zk0lKGlhohafun-WVJDu3RRQIobLZoe_lsUPh3L8pBDuEOcREbyJ7xVpk5jA_8BcGu_K8hQlbdR6g\" alt=\"\" \/><\/figure>\r\n\r\n\r\n\r\n<p>While building a media source for ExoPlayer, you should specify the UUID of the <a href=\"https:\/\/www.vdocipher.com\/blog\/in\/drm-solution\">DRM system<\/a> and the license server URI. Using these properties we will build an instance of DefaultDrmSessionManager needed for handling DRM related key and provisioning request to enable media playback.<\/p>\r\n\r\n\r\n\r\n<p><strong>Frist we need to create a instance of DrmSessionManager<\/strong><\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>private DefaultDrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String userAgent) {  \r\n    HttpDataSource.Factory licenseDataSourceFactory = new DefaultHttpDataSource.Factory().setUserAgent(userAgent);  \r\n    HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl, true,  \r\n            licenseDataSourceFactory);  \r\n    return new DefaultDrmSessionManager.Builder()  \r\n            .setUuidAndExoMediaDrmProvider(uuid, FrameworkMediaDrm.DEFAULT_PROVIDER)  \r\n            .build(drmCallback);  \r\n}<\/code><\/pre>\r\n\r\n\r\n\r\n<p><strong>Now we have to build a media source with license url<\/strong><\/p>\r\n\r\n\r\n\r\n<p><em>DRM License Url<\/em> : https:\/\/proxy.uat.widevine.com\/proxy?provider=widevine_test<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>private DashMediaSource buildDashMediaSource(Uri uri) {  \r\n    String drmLicenseUrl = \"https:\/\/proxy.uat.widevine.com\/proxy?provider=widevine_test\";  \r\n    String userAgent = Util.getUserAgent(context, context.getApplicationContext().getPackageName());  \r\n    UUID drmSchemeUuid = Util.getDrmUuid(C.WIDEVINE_UUID.toString());  \r\n\r\n    DrmSessionManager drmSessionManager = buildDrmSessionManager(drmSchemeUuid, drmLicenseUrl, userAgent);  \r\n\r\n    DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(context, new DefaultHttpDataSource.Factory().setUserAgent(userAgent));  \r\n    return new DashMediaSource.Factory(dataSourceFactory)  \r\n            .setDrmSessionManagerProvider(unusedMediaItem -&gt; drmSessionManager)  \r\n            .createMediaSource(  \r\n                    new MediaItem.Builder()  \r\n                            .setUri(uri)  \r\n                            .setMimeType(MimeTypes.APPLICATION_MPD)  \r\n                            .build()  \r\n            );  \r\n}<\/code><\/pre>\r\n\r\n\r\n\r\n<p><strong>Now add url and its ready to be played.<\/strong><\/p>\r\n\r\n\r\n\r\n<p><em>DRM Url<\/em>: https:\/\/storage.googleapis.com\/wvmedia\/cenc\/h264\/tears\/tears.mpd<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>private void initializePlayer() {  \r\n    String url = \"https:\/\/storage.googleapis.com\/wvmedia\/cenc\/h264\/tears\/tears.mpd\";  \r\n\r\n    MediaSource mediaSource = buildDashMediaSource(Uri.parse(url));  \r\n\r\n    ExoTrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory();  \r\n    TrackSelector trackSelector = new DefaultTrackSelector(context, videoTrackSelectionFactory);  \r\n    trackSelector.setParameters(trackSelector.getParameters().buildUpon()  \r\n            .setPreferredTextLanguage(\"en\")  \r\n            .build());  \r\n\r\n    DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(context)  \r\n            .forceEnableMediaCodecAsynchronousQueueing()  \r\n            .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);  \r\n\r\n    int maxBufferMs = DefaultLoadControl.DEFAULT_MAX_BUFFER_MS;  \r\n\r\n    DefaultLoadControl loadControl = new DefaultLoadControl.Builder()  \r\n            .setBufferDurationsMs(DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,  \r\n                    maxBufferMs,  \r\n                    DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,  \r\n                    DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)  \r\n            .build();  \r\n\r\n    ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory)  \r\n            .setTrackSelector(trackSelector)  \r\n            .setLoadControl(loadControl)  \r\n            .build();  \r\n\r\n    exoPlayer.setMediaSource(mediaSource);  \r\n    exoPlayer.prepare();  \r\n}<\/code><\/pre>\r\n\r\n\r\n\r\n<p>In next section we will see how we at VdoCipher use ExoPlayer to stream DRM protected videos.<\/p>\r\n\r\n\r\n<hr \/>\r\n<h2 class=\"wp-block-heading\" id=\"adaptive\">Adaptive Bitrate Streaming in Exoplayer<\/h2>\r\n\r\n\r\n\r\n<p>Exoplayer can also be used for adaptive bitrate streaming to set video quality automatically based on available network bandwidth. <a href=\"https:\/\/www.vdocipher.com\/blog\/adaptive-bitrate-streaming\" target=\"_blank\" rel=\"noreferrer noopener\" data-type=\"URL\" data-id=\"https:\/\/www.vdocipher.com\/blog\/adaptive-bitrate-streaming\">Adaptive bitrate streamin<\/a>g (also known as adaptive streaming) is a technology designed to deliver video in the most efficient way possible and in the highest usable quality for each specific user and device.<\/p>\r\n\r\n\r\n\r\n<p>For slow connections, the video will be played in low quality, and for fast connections, the video will be played in the best quality with less buffer time. These qualities(bit rates and resolutions) are known as tracks. The same media content is split into multiple tracks, each for a given quality based on bit rate and resolution. Each track is split into chunks of a given duration, typically between 2 and 10 seconds. This makes it easier to switch between tracks with changing network speeds and signals.<\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Implementing Adaptive Track Selection<\/h3>\r\n\r\n\r\n\r\n<p>To implement Adaptive streaming, add <code>TrackSelector<\/code> while initializing the player. The TrackSelector is used to switch between multiple tracks.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>ExoTrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory();\r\n\r\nTrackSelector trackSelector = new DefaultTrackSelector(context, videoTrackSelectionFactory);  \r\ntrackSelector.setParameters(trackSelector.getParameters().buildUpon()\r\n        .setMaxVideoSizeSd()  \r\n        .setPreferredTextLanguage(\"en\")  \r\n        .build());  \r\n\r\nExoPlayer exoPlayer = new ExoPlayer.Builder(context)  \r\n        .setTrackSelector(trackSelector)  \r\n        .build();  <\/code><\/pre>\r\n\r\n\r\n\r\n<p>Create an adaptive track selection factory with default parameters and pass it to <code>DefaultTrackSelector<\/code> which is responsible for choosing tracks in the media item.<br \/>Then pass the <code>trackSelector<\/code> to ExoPlayer builder.<\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Build an Adaptive Media Source<\/h3>\r\n\r\n\r\n\r\n<p>DASH, HLS, and SmoothStreaming are all media formats ExoPlayer supports that are capable of adaptive streaming, but we&#8217;ll focus on DASH for now and use the <code>DashMediaSource<\/code>. To stream DASH content, you need to create a MediaItem.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>Uri manifestUri = Uri.parse(dashUrl); \r\nDataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(context, new DefaultHttpDataSource.Factory().setUserAgent(userAgent));\r\nmediaSource = new DashMediaSource.Factory(dataSourceFactory)\r\n                    .createMediaSource(\r\n                            new MediaItem.Builder()\r\n                                .setUri(manifestUri)\r\n                                .setMimeType(MimeTypes.APPLICATION_MPD)\r\n                                .build()\r\n                    );<\/code><\/pre>\r\n\r\n\r\n<hr \/>\r\n<h2 class=\"wp-block-heading\" id=\"vdocipher\">How VdoCipher Streams Video on Android Using ExoPlayer<\/h2>\r\n\r\n\r\n\r\n<p>The components of our video streaming can be broken down into four main parts:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li>Client attempting to play content<\/li>\r\n<li>VdoCipher license server that generates decryption keys based on client requests<\/li>\r\n<li>Provisioning server if unique credentials are required for devices<\/li>\r\n<li>Content server that serves encrypted content<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<p>At client side we try to play protected content from the content server via a <a href=\"https:\/\/exoplayer.dev\/doc\/reference\/com\/google\/android\/exoplayer2\/source\/dash\/DashMediaSource.html\">DashMediaSource<\/a>\u00a0with a provided <a href=\"https:\/\/exoplayer.dev\/doc\/reference\/com\/google\/android\/exoplayer2\/drm\/DrmSessionManager.html\">DrmSessionManager<\/a>, this DRMSessionManager contains the implementation of <a href=\"https:\/\/exoplayer.dev\/doc\/reference\/com\/google\/android\/exoplayer2\/drm\/MediaDrmCallback.html\">MediaDRMCallback<\/a> wrapping a HttpMediaDrmCallback that extends its functionality by wrapping\/unwrapping license request\/response and throwing custom exceptions to help identify the cause. In the meantime, if the device needs provisioning, a request to the provisioning server is done via callback. After the MediaDRM client receives the license, and it is passed to ExoPlayer via the media source and media playback will begin. This procedure is repeated with every media playback request for non-persistent licenses. Our application saves persistent licenses and reuses them until they expire. In addition, persistent license requests are fetched before the <a href=\"https:\/\/www.vdocipher.com\/\">secure video<\/a> playback starts with <a href=\"https:\/\/exoplayer.dev\/doc\/reference\/com\/google\/android\/exoplayer2\/drm\/OfflineLicenseHelper.html\">OfflineLicenseHelper<\/a>, allowing for video initialization to happen regardless of whether or not the license fetch operation succeeded. Now lets see how these classes are utilized.<\/p>\r\n<p>With VdoCipher&#8217;s Android video SDK, you can let your users play their video in background, download the content to view it later in a secure manner, stream in PIP mode and plus with playintegrity you can block any emulator, rooted device playback.<\/p>\r\n<p>Here you can find the docs for these SDK features, explore them to know more.\u00a0<\/p>\r\n<ul>\r\n<li><a href=\"https:\/\/www.vdocipher.com\/docs\/mobile\/android\/background-playback\/\">Android Background Playback<\/a><\/li>\r\n<li><a href=\"https:\/\/www.vdocipher.com\/docs\/mobile\/android\/offline-downloads\/\">Android Offline Download<\/a><\/li>\r\n<li><a href=\"https:\/\/www.vdocipher.com\/docs\/mobile\/android\/pip-mode\/\">Android PIP<\/a> (Player in Player)<\/li>\r\n<li><a href=\"https:\/\/www.vdocipher.com\/docs\/mobile\/android\/safety-net\">Android PlayIntegrity<\/a><\/li>\r\n<li><a href=\"https:\/\/www.vdocipher.com\/docs\/mobile\/android\/getting-started\/\"><span data-sheets-root=\"1\">Android Video SDK<\/span><\/a><\/li>\r\n<\/ul>\r\n<h3>How can Exoplayer play video from URL in <a href=\"https:\/\/www.vdocipher.com\/blog\/top-video-player-for-android\/\">Android video player<\/a>?<\/h3>\r\n<p>After creating the instance of Exoplayer you can pass the video_url as, MediaItem mediaItem = MediaItem.fromUri(video_url);<\/p>\r\n<p>You can also stop playback on cloned apps, emulators and rooted devices in Android with our <a href=\"https:\/\/www.vdocipher.com\/playintegrity\/\">Play Integrity<\/a> integration in Android SDK. Check out our <a href=\"https:\/\/www.vdocipher.com\/docs\/mobile\/react-native\/safety-net\/\">play integrity api<\/a> documentation to know more. Learn more about <a href=\"https:\/\/www.vdocipher.com\/docs\/mobile\/android\/getting-started\/\">android video SDK<\/a> to stream your videos on Android with VdoCipher.<\/p>\r\n<hr \/>\r\n<h2 id=\"error\">Common ExoPlayer Errors and Solutions<\/h2>\r\n<p>While ExoPlayer (Media3) is highly reliable, developers may occasionally encounter playback or configuration issues. The table below outlines some of the most common problems, their likely causes, and recommended solutions.<\/p>\r\n<table>\r\n<thead>\r\n<tr>\r\n<th>Issue<\/th>\r\n<th>Possible Cause<\/th>\r\n<th>Recommended Solution<\/th>\r\n<\/tr>\r\n<\/thead>\r\n<tbody>\r\n<tr>\r\n<td>Black Screen During Playback<\/td>\r\n<td>Invalid video URL, unsupported format, or rendering issue.<\/td>\r\n<td>Verify the media URL, supported codecs, and ensure the <code>PlayerView<\/code> is properly attached to the player.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>PlaybackException<\/td>\r\n<td>Incorrect media source, network failure, or invalid configuration.<\/td>\r\n<td>Implement <code>Player.Listener<\/code> to capture errors and validate the media source before playback.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>DRM License Error<\/td>\r\n<td>Invalid or expired DRM license, incorrect license server URL.<\/td>\r\n<td>Verify the Widevine license server configuration, playback token, and DRM credentials.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Continuous Buffering<\/td>\r\n<td>Slow network connection or improperly configured streaming.<\/td>\r\n<td>Use adaptive streaming (HLS or MPEG-DASH), optimize buffering parameters, and verify CDN performance.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Audio Plays but Video Doesn&#8217;t<\/td>\r\n<td>Unsupported video codec or decoder compatibility issue.<\/td>\r\n<td>Confirm the video is encoded using supported codecs such as H.264 or H.265 and test on multiple devices.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Subtitles Not Displaying<\/td>\r\n<td>Incorrect subtitle format or MIME type.<\/td>\r\n<td>Ensure subtitle files are properly linked and use supported formats such as WebVTT or SubRip (SRT).<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Poor Playback Performance<\/td>\r\n<td>Large media files, excessive buffering, or limited device resources.<\/td>\r\n<td>Enable media caching, optimize buffering settings, and use adaptive bitrate streaming.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Live Stream Lag or Delay<\/td>\r\n<td>Network latency or high live streaming buffer.<\/td>\r\n<td>Configure low-latency HLS or DASH settings and reduce unnecessary buffering.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Player Not Releasing Resources<\/td>\r\n<td>ExoPlayer instance not released during Activity or Fragment lifecycle changes.<\/td>\r\n<td>Always release the player in <code>onStop()<\/code> or <code>onDestroy()<\/code> to prevent memory leaks.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Playback Issues on Specific Android Devices<\/td>\r\n<td>Device-specific codec limitations or manufacturer-specific issues.<\/td>\r\n<td>Test across multiple Android devices, keep Media3 updated, and use standard video encoding profiles.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td>Unsupported Media Format<\/td>\r\n<td>Unsupported codec or container format<\/td>\r\n<td>Encode videos using H.264\/H.265 with AAC audio in MP4, HLS, or MPEG-DASH formats supported by ExoPlayer<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n<p><strong>Tip<\/strong>: Many playback issues can be avoided by using adaptive streaming (HLS or MPEG-DASH), keeping Media3 updated, implementing proper error handling with Player.Listener, and using a secure video delivery solution such as VdoCipher for DRM-protected content.<\/p>\r\n<h2 id=\"conc\">Conclusion<\/h2>\r\n<p>ExoPlayer (AndroidX Media3) is the recommended media playback library for modern Android applications. With support for adaptive streaming (HLS and MPEG-DASH), Widevine DRM, offline playback, subtitles, playlists, and extensive customization, it provides everything developers need to build secure and high-performance video streaming apps.<\/p>\r\n<p>Whether you&#8217;re developing an OTT platform, e-learning application, or enterprise video solution, ExoPlayer offers the flexibility and scalability required for production-ready deployments. For applications that require enterprise-grade video security, ExoPlayer integrates seamlessly with VdoCipher to deliver secure video streaming with Widevine DRM, encrypted playback, and anti-piracy protection.<\/p>\r\n<hr \/>\r\n<h2 id=\"faqs\">Frequently Asked Questions (FAQs)<\/h2>\r\n<h4>1. What is ExoPlayer?<\/h4>\r\n<p>ExoPlayer is Google&#8217;s open-source media playback library for Android, now available as part of AndroidX Media3. It provides advanced playback capabilities such as adaptive streaming, DRM support, subtitles, playlists, offline playback, and extensive customization.<\/p>\r\n<h4>2. Is ExoPlayer deprecated?<\/h4>\r\n<p>No. ExoPlayer itself is not deprecated. Google has migrated the standalone ExoPlayer project into the AndroidX Media3 library. New Android applications should use the Media3 ExoPlayer APIs, while existing ExoPlayer 2.x projects can migrate using the official migration guide.<\/p>\r\n<h4>3. What is the difference between ExoPlayer and Android MediaPlayer?<\/h4>\r\n<p>Android&#8217;s built-in MediaPlayer API is suitable for basic media playback. ExoPlayer (Media3) offers additional features such as adaptive streaming (HLS and MPEG-DASH), Widevine DRM, playlist support, subtitles, offline playback, playback analytics, and extensive customization, making it the preferred choice for modern Android applications.<\/p>\r\n<h4>4. Does ExoPlayer support HLS and MPEG-DASH?<\/h4>\r\n<p>Yes. ExoPlayer provides native support for HTTP Live Streaming (HLS), MPEG-DASH, SmoothStreaming, and progressive media formats. It automatically adapts video quality based on the user&#8217;s network conditions to ensure smooth playback.<\/p>\r\n<h4>5. Does ExoPlayer support DRM-protected content?<\/h4>\r\n<p>Yes. ExoPlayer supports Widevine DRM and Common Encryption (CENC), enabling secure playback of protected video content. It is commonly used by OTT platforms, e-learning applications, and premium video streaming services to prevent unauthorized access.<\/p>\r\n<h4>6. Can ExoPlayer stream live videos?<\/h4>\r\n<p>Yes. ExoPlayer supports live video streaming using HLS, MPEG-DASH, and other streaming protocols. It also supports adaptive bitrate streaming, helping deliver a smooth viewing experience even when network conditions fluctuate.<\/p>\r\n<h4>7. Does ExoPlayer support offline playback?<\/h4>\r\n<p>Yes. ExoPlayer supports offline downloads and media caching. When combined with DRM technologies such as Widevine Offline License, applications can securely offer downloadable content for offline viewing.<\/p>\r\n<h4>8. Can ExoPlayer play local video files?<\/h4>\r\n<p>Yes. In addition to online streaming, ExoPlayer can play videos stored locally on the device, including MP4, MKV, WebM, MP3, AAC, FLAC, and several other supported media formats.<\/p>\r\n<h4>9. How do I migrate from ExoPlayer 2.x to AndroidX Media3?<\/h4>\r\n<p>Migration involves replacing the legacy ExoPlayer dependencies with AndroidX Media3 libraries, updating package imports, and modifying certain APIs to align with the new Media3 architecture. Google provides an official migration guide to simplify this process.<\/p>\r\n<h4>10. Why should I use ExoPlayer with VdoCipher?<\/h4>\r\n<p>VdoCipher integrates seamlessly with ExoPlayer to provide secure Android video streaming using Widevine DRM, encrypted video delivery, token-based authentication, and playback protection. This helps businesses securely stream premium content while minimizing the risk of piracy and unauthorized downloads.<\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;re building an Android application that streams video, choosing the right media player is critical for performance, security, and user experience.Google&#8217;s ExoPlayer, now part of AndroidX Media3, is the most widely used media playback library for Android. It supports adaptive streaming formats such as HLS and MPEG-DASH, Widevine DRM, subtitles, offline playback, and advanced [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":17186,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[290,25],"tags":[],"class_list":{"0":"post-12004","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-android","8":"category-technology","9":"entry"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.0 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Media3 ExoPlayer Tutorial: Secure Video Streaming on Android<\/title>\n<meta name=\"description\" content=\"Learn how to implement Media3 ExoPlayer in Android for secure video streaming with DRM, HLS, DASH, subtitles, and best practices in 2026.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android with DRM\" \/>\n<meta property=\"og:description\" content=\"Learn how to implement Media3 ExoPlayer in Android for secure video streaming with DRM, HLS, DASH, subtitles, and best practices in 2026.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/\" \/>\n<meta property=\"og:site_name\" content=\"VdoCipher Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/vdociphertech\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-06-28T16:05:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-29T10:48:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"450\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Mansi &amp; Nafis\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@vdocipher\" \/>\n<meta name=\"twitter:site\" content=\"@vdocipher\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mansi &amp; Nafis\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/\"},\"author\":{\"name\":\"Mansi &amp; Nafis\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#\/schema\/person\/fef6a093e1853734b67cae33f0a2717e\"},\"headline\":\"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android with DRM\",\"datePublished\":\"2026-06-28T16:05:12+00:00\",\"dateModified\":\"2026-06-29T10:48:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/\"},\"wordCount\":3724,\"publisher\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png\",\"articleSection\":[\"Android\",\"Technology\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/\",\"url\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/\",\"name\":\"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android\",\"isPartOf\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png\",\"datePublished\":\"2026-06-28T16:05:12+00:00\",\"dateModified\":\"2026-06-29T10:48:40+00:00\",\"description\":\"Learn how to implement Media3 ExoPlayer in Android for secure video streaming with DRM, HLS, DASH, subtitles, and best practices in 2026.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage\",\"url\":\"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png\",\"contentUrl\":\"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png\",\"width\":1000,\"height\":450,\"caption\":\"exoplayer\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.vdocipher.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android with DRM\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#website\",\"url\":\"https:\/\/www.vdocipher.com\/blog\/\",\"name\":\"VdoCipher Blog\",\"description\":\"Secure Video Streaming Player\",\"publisher\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.vdocipher.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#organization\",\"name\":\"VdoCipher\",\"url\":\"https:\/\/www.vdocipher.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2016\/11\/VdoCipher-logo2.png\",\"contentUrl\":\"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2016\/11\/VdoCipher-logo2.png\",\"width\":1625,\"height\":1925,\"caption\":\"VdoCipher\"},\"image\":{\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/vdociphertech\/\",\"https:\/\/x.com\/vdocipher\",\"https:\/\/www.linkedin.com\/company\/vdocipher\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#\/schema\/person\/fef6a093e1853734b67cae33f0a2717e\",\"name\":\"Mansi &amp; Nafis\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.vdocipher.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9490aa17112722a1fb42aca88660321377463b50cbb82d028f2f893de6510732?s=96&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9490aa17112722a1fb42aca88660321377463b50cbb82d028f2f893de6510732?s=96&r=g\",\"caption\":\"Mansi &amp; Nafis\"},\"description\":\"Mansi and Nafis both are Android Developers at VdoCipher. This article was jointly written by both of them\",\"url\":\"https:\/\/www-uat.vdocipher.com\/blog\/author\/mansi-nafis\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android","description":"Learn how to implement Media3 ExoPlayer in Android for secure video streaming with DRM, HLS, DASH, subtitles, and best practices in 2026.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/","og_locale":"en_US","og_type":"article","og_title":"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android with DRM","og_description":"Learn how to implement Media3 ExoPlayer in Android for secure video streaming with DRM, HLS, DASH, subtitles, and best practices in 2026.","og_url":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/","og_site_name":"VdoCipher Blog","article_publisher":"https:\/\/www.facebook.com\/vdociphertech\/","article_published_time":"2026-06-28T16:05:12+00:00","article_modified_time":"2026-06-29T10:48:40+00:00","og_image":[{"width":1000,"height":450,"url":"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png","type":"image\/png"}],"author":"Mansi &amp; Nafis","twitter_card":"summary_large_image","twitter_creator":"@vdocipher","twitter_site":"@vdocipher","twitter_misc":{"Written by":"Mansi &amp; Nafis","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#article","isPartOf":{"@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/"},"author":{"name":"Mansi &amp; Nafis","@id":"https:\/\/www.vdocipher.com\/blog\/#\/schema\/person\/fef6a093e1853734b67cae33f0a2717e"},"headline":"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android with DRM","datePublished":"2026-06-28T16:05:12+00:00","dateModified":"2026-06-29T10:48:40+00:00","mainEntityOfPage":{"@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/"},"wordCount":3724,"publisher":{"@id":"https:\/\/www.vdocipher.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage"},"thumbnailUrl":"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png","articleSection":["Android","Technology"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/","url":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/","name":"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android","isPartOf":{"@id":"https:\/\/www.vdocipher.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage"},"image":{"@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage"},"thumbnailUrl":"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png","datePublished":"2026-06-28T16:05:12+00:00","dateModified":"2026-06-29T10:48:40+00:00","description":"Learn how to implement Media3 ExoPlayer in Android for secure video streaming with DRM, HLS, DASH, subtitles, and best practices in 2026.","breadcrumb":{"@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.vdocipher.com\/blog\/exoplayer\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#primaryimage","url":"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png","contentUrl":"https:\/\/www-uat.vdocipher.com\/blog\/wp-content\/uploads\/2024\/01\/exoplayer.png","width":1000,"height":450,"caption":"exoplayer"},{"@type":"BreadcrumbList","@id":"https:\/\/www.vdocipher.com\/blog\/exoplayer\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.vdocipher.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android with DRM"}]},{"@type":"WebSite","@id":"https:\/\/www.vdocipher.com\/blog\/#website","url":"https:\/\/www.vdocipher.com\/blog\/","name":"VdoCipher Blog","description":"Secure Video Streaming Player","publisher":{"@id":"https:\/\/www.vdocipher.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.vdocipher.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.vdocipher.com\/blog\/#organization","name":"VdoCipher","url":"https:\/\/www.vdocipher.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.vdocipher.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2016\/11\/VdoCipher-logo2.png","contentUrl":"https:\/\/www.vdocipher.com\/blog\/wp-content\/uploads\/2016\/11\/VdoCipher-logo2.png","width":1625,"height":1925,"caption":"VdoCipher"},"image":{"@id":"https:\/\/www.vdocipher.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/vdociphertech\/","https:\/\/x.com\/vdocipher","https:\/\/www.linkedin.com\/company\/vdocipher"]},{"@type":"Person","@id":"https:\/\/www.vdocipher.com\/blog\/#\/schema\/person\/fef6a093e1853734b67cae33f0a2717e","name":"Mansi &amp; Nafis","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.vdocipher.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9490aa17112722a1fb42aca88660321377463b50cbb82d028f2f893de6510732?s=96&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9490aa17112722a1fb42aca88660321377463b50cbb82d028f2f893de6510732?s=96&r=g","caption":"Mansi &amp; Nafis"},"description":"Mansi and Nafis both are Android Developers at VdoCipher. This article was jointly written by both of them","url":"https:\/\/www-uat.vdocipher.com\/blog\/author\/mansi-nafis\/"}]}},"yoast":{"focuskw":"exoplayer","title":"Media3 ExoPlayer Tutorial: Secure Video Streaming on Android","metadesc":"Learn how to implement Media3 ExoPlayer in Android for secure video streaming with DRM, HLS, DASH, subtitles, and best practices in 2026.","linkdex":"91","metakeywords":"","meta-robots-noindex":"","meta-robots-nofollow":"","meta-robots-adv":"","canonical":"","redirect":"","opengraph-title":"","opengraph-description":"","opengraph-image":"","twitter-title":"","twitter-description":"","twitter-image":""},"_links":{"self":[{"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/posts\/12004","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/comments?post=12004"}],"version-history":[{"count":31,"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/posts\/12004\/revisions"}],"predecessor-version":[{"id":21959,"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/posts\/12004\/revisions\/21959"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/media\/17186"}],"wp:attachment":[{"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/media?parent=12004"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/categories?post=12004"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www-uat.vdocipher.com\/blog\/wp-json\/wp\/v2\/tags?post=12004"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}