ExoPlayer is an open-source media player library for Android developed by Google as an alternative to the built-in MediaPlayer. ExoPlayer provides audio and video playback in various formats, including DASH, HLS, SmoothStreaming and regular media files, through a single API with support for adaptive streaming. According to Google I/O (2024), ExoPlayer is used in over 60,000 Android applications, including YouTube, Google TV and Netflix.
Key Takeaways
ExoPlayer is an open-source (Apache 2.0) multimedia playback library for Android, whose first version was released by Google in 2014. Unlike the built-in MediaPlayer, which is a thin wrapper over the system media codec (MediaCodec), ExoPlayer is implemented entirely at the Java/Kotlin level, giving developers full control over every stage of playback.
Architecturally, ExoPlayer is built on a modular principle: each aspect of playback is implemented by a separate component. The core module (exoplayer-core) contains the player, renderers, track selectors and buffer management. Additional modules (exoplayer-dash, exoplayer-hls, exoplayer-rtsp, exoplayer-smoothstreaming) add support for the corresponding streaming protocols. This architecture allows applications to include only the necessary components, minimizing APK size.
ExoPlayer 2 (the current major version) was released in 2018 and brought a radical API overhaul: introduction of the Player Interface, Compose support through AndroidX Media3, improved error handling and adaptive track selection algorithms. Starting from version 2.19 (2024), ExoPlayer became part of the AndroidX Media library, simplifying integration and updates through the standard Android dependency manager.
At the core of ExoPlayer lies the ExoPlayerImpl component, which manages the playback lifecycle. It contains MediaSource (media source), TrackSelector (track selection), LoadControl (buffering management) and a list of Renderer (renderers for video, audio, subtitles and metadata). Each component can be replaced with a custom implementation through Builder or factory methods.
For video rendering, ExoPlayer uses SurfaceView, TextureView or SphericalSurfaceView (for 360-degree video). The recommended option is SurfaceView, as it provides hardware acceleration and minimal power consumption. For Jetpack Compose, the AndroidX Media3 library provides the `AndroidView` component, wrapping SurfaceView, and the experimental `Media3Compose` with native Compose integration.
ExoPlayer provides a wide range of features beyond a regular media player. Key capabilities include support for all popular streaming protocols, a flexible DRM system, adaptive bitrate switching (ABR) and playback analytics tools.
| Feature | Description | Module |
|---|---|---|
| DASH | Adaptive streaming per MPEG standard | exoplayer-dash |
| HLS | HTTP Live Streaming from Apple | exoplayer-hls |
| SmoothStreaming | Adaptive streaming from Microsoft | exoplayer-smoothstreaming |
| RTSP | Real-Time Streaming Protocol for live | exoplayer-rtsp |
| Widevine | DRM content protection | exoplayer-drm |
| Concatenation | Merging multiple media files | exoplayer-core |
| Ads | IMA SDK integration for advertising | exoplayer-ima |
ABR (Adaptive Bitrate) in ExoPlayer is implemented through the AdaptiveTrackSelection interface. By default, AdaptiveTrackSelectionFactory is used, which creates DefaultAdaptiveTrackSelection — a balanced algorithm that takes into account network bandwidth and buffer size. For specific scenarios, alternative implementations can be plugged in: BOLA (minimizing switches), RandomAdaptiveTrackSelection (testing) or a custom implementation through the TrackSelection interface.
BandwidthMeter — another key component responsible for measuring network bandwidth. By default, DefaultBandwidthMeter is used, which collects statistics on all HTTP requests from the player. The developer can extend it to account for additional factors: network type (Wi-Fi, 4G, 5G), cell tower signal or data cost for the user.
ExoPlayer supports Widevine (L1, L3), PlayReady and ClearKey DRM. License acquisition is configured through DrmSessionManager, which interacts with the license server. For premium video (4K HDR), hardware support for Widevine L1 is required, which provides chip-level protection and prevents screen capture. The choice of DRM system depends on the target platform: Widevine is used on Android and Chromecast, PlayReady on Xbox and Windows, FairPlay on iOS and Apple TV. ExoPlayer automatically determines the available DRM system based on the MPD file and does not require manual configuration for basic scenarios.
Connecting ExoPlayer to an Android project is done through Gradle dependencies. Starting from version 2.19, ExoPlayer is part of AndroidX Media (androidx.media3), ensuring compatibility with Jetpack Compose and other AndroidX components. Let's look at a step-by-step integration in Kotlin.
Add ExoPlayer modules to the build.gradle file (Module). The minimum set includes core, ui and the module for the required streaming protocol. For DASH content playback, exoplayer-dash is required, for HLS — exoplayer-hls.
dependencies {
implementation "androidx.media3:media3-exoplayer:1.5.0"
implementation "androidx.media3:media3-ui:1.5.0"
implementation "androidx.media3:media3-exoplayer-dash:1.5.0"
implementation "androidx.media3:media3-exoplayer-hls:1.5.0"
}
Creating and configuring the player in an Activity or Fragment. ExoPlayer uses PlayerView (or StyledPlayerView for customization) to display video and built-in controls. The minimum configuration includes creating the player via ExoPlayer.Builder and passing a MediaItem with the source URI.
class PlayerActivity : AppCompatActivity() {
private var player: ExoPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_player)
player = ExoPlayer.Builder(this).build()
val playerView = findViewById<StyledPlayerView>(R.id.playerView)
playerView.player = player
val mediaItem = MediaItem
.Builder()
.setUri("https://example.com/video.mp4")
.build()
player?.setMediaItem(mediaItem)
player?.prepare()
}
override fun onDestroy() {
player?.release()
super.onDestroy()
}
}
For production applications, handling of possible playback errors is necessary: network failures, unsupported formats, DRM licensing errors. ExoPlayer provides the Player.Listener interface with methods onPlayerError, onPlaybackStateChanged and onPlayWhenReadyChanged. It is recommended to show users informative error messages with a retry option.
Choosing between ExoPlayer and the built-in MediaPlayer is a common question when developing Android applications. MediaPlayer has been part of the Android SDK since version 1.0, while ExoPlayer is a library that requires Gradle dependency. Let's look at their differences across key criteria.
| Criterion | ExoPlayer | MediaPlayer |
|---|---|---|
| Architecture | Modular, entirely in Java/Kotlin | Wrapper over system C++ components |
| Streaming | DASH, HLS, SmoothStreaming, RTSP | Local files only and HLS (Android 9+) |
| Customization | Full (any component replaceable) | Minimal (parameters only) |
| Updates | Via Google Play or APK (OS independent) | Only via Android update (OTA) |
| APK Size | +1–3 MB (depending on modules) | 0 (part of OS) |
| Min SDK | API 16+ (Android 4.1) | API 1+ |
| DRM | Widevine, PlayReady, ClearKey | Widevine (limited) |
ExoPlayer wins in scenarios requiring streaming (DASH, HLS), UI customization, DRM support and independence from Android version. MediaPlayer is suitable for simple applications playing local media files where APK size is critical and there are no adaptive streaming requirements. For modern applications with content from the network, ExoPlayer is the clear choice.
Exception — applications with a minimum SDK below API 16 (Android 4.1), which are practically non-existent on the market. For all applications with targetSdk 33+ and minimum SDK 21+, ExoPlayer is not only preferable but necessary for supporting modern formats such as AV1 and Dolby Vision through appropriate extensions.
For production applications, basic ExoPlayer integration often requires additional configuration: cache management, buffer optimization for mobile networks, analytics integration and audio track selection customization. Let's look at advanced usage scenarios.
CacheDataSourceFactory allows caching downloaded segments to local storage, saving traffic on repeat viewing and enabling offline playback. ExoPlayer uses SimpleCache from the exoplayer-cas library — file-based caching with LRU eviction support and size limits.
val cache = SimpleCache(
cacheDir,
LeastRecentlyUsedCacheEvictor(50 * 1024 * 1024),
AppDatabaseProvider(this)
)
val cacheDataSourceFactory = CacheDataSource
.Factory()
.setCache(cache)
val player = ExoPlayer.Builder(this)
.setMediaSourceFactory(
DefaultMediaSourceFactory(cacheDataSourceFactory)
)
.build()
In mobile applications, handling network switching between Wi-Fi and cellular is critical. ExoPlayer provides ConnectivityManager for tracking network state. Upon connection loss, it is recommended not to stop the player but to switch it to PAUSED state while preserving the position. After connection is restored, resume playback with segment reloading.
With the release of AndroidX Media3, the library gained experimental support for Jetpack Compose. The `AndroidView` component wraps SurfaceView or PlayerView, ensuring compatibility with the Compose hierarchy. For deeper integration, the `androidx.media3:media3-ui-compose` library is used, providing Compose-compatible player controls.
@Composable
fun VideoPlayer(uri: String) {
val context = LocalContext.current
val player = remember {
ExoPlayer.Builder(context).build()
.also { it.setMediaItem(MediaItem.fromUri(uri)) }
}
DisposableEffect(key = null) {
player.prepare()
onDispose { player.release() }
}
AndroidView(
factory = { StyledPlayerView(context).also { it.player = player } }
)
}
Frequently Asked Questions
ExoPlayer supports Android API 16+ (Android 4.1 Jelly Bean). However, for DASH and HLS with fMP4 segments, API 21+ (Android 5.0 Lollipop) is recommended. DRM modules (Widevine) require API 19+, and hardware HEVC decoding is available from API 21.
Yes, ExoPlayer is excellent for audio. For audio-only playback, SurfaceView or PlayerView is not required. ExoPlayer will automatically select the audio renderer and work in the background. For background playback, it is recommended to use MediaSessionService for integration with system controls.
The TrackSelector in ExoPlayer manages audio track selection. To switch tracks, use player.getCurrentTracks().groups and player.setTrackSelectionParameters() specifying the preferred audio language. For DASH and HLS streams with multiple audio tracks, switching occurs without playback interruption.
Yes, ExoPlayer supports embedded (in MP4, WebM containers) and external subtitles in TTML, SRT, VTT and CEA-608 formats. For external subtitles, SingleSampleMediaSource or MergingMediaSource is used to merge with the video stream. Styled subtitle display is configured through CaptionStyleCompat.
For Low-Latency streaming, configure LoadControl with smaller target buffer values: use DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) for HLS LL and DASH LL. Also set minPlaybackSpeed = 1.02 for accelerated buffer filling when behind the live broadcast.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also