ExoPlayer è una libreria lettore multimediale open source per Android sviluppata da Google come alternativa al MediaPlayer integrato. ExoPlayer offre la riproduzione audio e video in vari formati, tra cui DASH, HLS, SmoothStreaming e file multimediali normali, attraverso una singola API con supporto per lo streaming adattivo. Secondo Google I/O (2024), ExoPlayer è utilizzato in oltre 60.000 applicazioni Android, tra cui YouTube, Google TV e Netflix.
Punti chiave
ExoPlayer è una libreria di riproduzione multimediale open source (Apache 2.0) per Android, la cui prima versione è stata rilasciata da Google nel 2014. A differenza del MediaPlayer integrato, che è un sottile strato sopra il codec multimediale di sistema (MediaCodec), ExoPlayer è implementato interamente a livello Java/Kotlin, dando agli sviluppatori il controllo completo su ogni fase della riproduzione.
Architetturalmente, ExoPlayer è costruito su un principio modulare: ogni aspetto della riproduzione è implementato da un componente separato. Il modulo principale (exoplayer-core) contiene il lettore, i renderer, i selettori di traccia e la gestione del buffer. I moduli aggiuntivi (exoplayer-dash, exoplayer-hls, exoplayer-rtsp, exoplayer-smoothstreaming) aggiungono supporto per i corrispondenti protocolli di streaming. Questa architettura consente alle applicazioni di includere solo i componenti necessari, minimizzando la dimensione dell’APK.
ExoPlayer 2 (la versione principale attuale) è stato rilasciato nel 2018 e ha portato una revisione radicale dell’API: introduzione dell’interfaccia Player, supporto Compose tramite AndroidX Media3, gestione degli errori migliorata e algoritmi adattivi di selezione delle tracce. A partire dalla versione 2.19 (2024), ExoPlayer è diventato parte della libreria AndroidX Media, semplificando l’integrazione e gli aggiornamenti attraverso il gestore di dipendenze standard di Android.
Al centro di ExoPlayer si trova il componente ExoPlayerImpl, che gestisce il ciclo di vita della riproduzione. Esso contiene MediaSource (fonte multimediale), TrackSelector (selezione tracce), LoadControl (gestione buffer) e un elenco di Renderer (render per video, audio, sottotitoli e metadati). Ogni componente può essere sostituito con un’implementazione personalizzata tramite Builder o metodi factory.
Per il rendering video, ExoPlayer utilizza SurfaceView, TextureView o SphericalSurfaceView (per video a 360 gradi). L’opzione consigliata è SurfaceView, poiché fornisce accelerazione hardware e consumo energetico minimo. Per Jetpack Compose, la libreria AndroidX Media3 fornisce il componente `AndroidView`, che incapsula SurfaceView, e l’esperimentale `Media3Compose` con integrazione nativa Compose.
ExoPlayer offre un’ampia gamma di funzionalità oltre a un normale lettore multimediale. Le principali capacità includono il supporto per tutti i protocolli di streaming più diffusi, un sistema DRM flessibile, la commutazione adattiva del bitrate (ABR) e strumenti di analisi della riproduzione.
| Funzione | Descrizione | Modulo |
|---|---|---|
| DASH | Streaming adattivo secondo lo standard MPEG | exoplayer-dash |
| HLS | HTTP Live Streaming di Apple | exoplayer-hls |
| SmoothStreaming | Streaming adattivo di Microsoft | exoplayer-smoothstreaming |
| RTSP | Protocollo di streaming in tempo reale per live | exoplayer-rtsp |
| Widevine | Protezione contenuti DRM | exoplayer-drm |
| Concatenation | Unione di più file multimediali | exoplayer-core |
| Ads | Integrazione IMA SDK per pubblicità | exoplayer-ima |
ABR (Adaptive Bitrate) in ExoPlayer è implementato tramite l’interfaccia AdaptiveTrackSelection. Per impostazione predefinita, viene utilizzato AdaptiveTrackSelectionFactory, che crea DefaultAdaptiveTrackSelection — un algoritmo bilanciato che tiene conto della larghezza di banda della rete e della dimensione del buffer. Per scenari specifici, è possibile collegare implementazioni alternative: BOLA (minimizzazione delle commutazioni), RandomAdaptiveTrackSelection (test) o un’implementazione personalizzata tramite l’interfaccia TrackSelection.
BandwidthMeter — un altro componente chiave responsabile della misurazione della larghezza di banda della rete. Per impostazione predefinita, viene utilizzato DefaultBandwidthMeter, che raccoglie statistiche su tutte le richieste HTTP del lettore. Lo sviluppatore può estenderlo per considerare fattori aggiuntivi: tipo di rete (Wi-Fi, 4G, 5G), segnale della torre cellulare o costo dei dati per l’utente.
ExoPlayer supporta Widevine (L1, L3), PlayReady e ClearKey DRM. L’acquisizione della licenza viene configurata tramite DrmSessionManager, che interagisce con il server di licenze. Per i video premium (4K HDR), è richiesto il supporto hardware Widevine L1, che fornisce protezione a livello di chip e impedisce la cattura dello schermo. La scelta del sistema DRM dipende dalla piattaforma di destinazione: Widevine viene utilizzato su Android e Chromecast, PlayReady su Xbox e Windows, FairPlay su iOS e Apple TV. ExoPlayer determina automaticamente il sistema DRM disponibile in base al file MPD e non richiede configurazione manuale per scenari di base.
La connessione di ExoPlayer a un progetto Android avviene tramite dipendenze Gradle. A partire dalla versione 2.19, ExoPlayer fa parte di AndroidX Media (androidx.media3), garantendo la compatibilità con Jetpack Compose e altri componenti AndroidX. Vediamo un’integrazione passo passo in Kotlin.
Aggiungi i moduli ExoPlayer al file build.gradle (Module). Il set minimo include core, ui e il modulo per il protocollo di streaming necessario. Per la riproduzione di contenuti DASH, è necessario exoplayer-dash, per 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"
}
Creazione e configurazione del lettore in un’Activity o Fragment. ExoPlayer utilizza PlayerView (o StyledPlayerView per la personalizzazione) per visualizzare video e controlli integrati. La configurazione minima include la creazione del lettore tramite ExoPlayer.Builder e il passaggio di un MediaItem con l’URI di origine.
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()
}
}
Per le applicazioni di produzione, è necessaria la gestione dei possibili errori di riproduzione: guasti di rete, formati non supportati, errori di licenza DRM. ExoPlayer fornisce l’interfaccia Player.Listener con i metodi onPlayerError, onPlaybackStateChanged e onPlayWhenReadyChanged. Si consiglia di mostrare all’utente messaggi di errore informativi con opzione di riprova.
Scegliere tra ExoPlayer e il MediaPlayer integrato è una domanda comune nello sviluppo di applicazioni Android. MediaPlayer fa parte dell’Android SDK dalla versione 1.0, mentre ExoPlayer è una libreria che richiede una dipendenza Gradle. Vediamo le loro differenze secondo criteri chiave.
| Criterio | ExoPlayer | MediaPlayer |
|---|---|---|
| Architettura | Modulare, interamente in Java/Kotlin | Strato sopra componenti C++ di sistema |
| Streaming | DASH, HLS, SmoothStreaming, RTSP | Solo file locali e HLS (Android 9+) |
| Personalizzazione | Completa (ogni componente sostituibile) | Minima (solo parametri) |
| Aggiornamenti | Via Google Play o APK (indipendente dall’OS) | Solo tramite aggiornamento Android (OTA) |
| Dimensione APK | +1–3 MB (a seconda dei moduli) | 0 (parte dell’OS) |
| SDK minimo | API 16+ (Android 4.1) | API 1+ |
| DRM | Widevine, PlayReady, ClearKey | Widevine (limitato) |
ExoPlayer vince negli scenari che richiedono streaming (DASH, HLS), personalizzazione dell’interfaccia, supporto DRM e indipendenza dalla versione di Android. MediaPlayer è adatto per applicazioni semplici che riproducono file multimediali locali dove la dimensione dell’APK è critica e non ci sono requisiti di streaming adattivo. Per le applicazioni moderne con contenuti dalla rete, ExoPlayer è la scelta ovvia.
Eccezione — applicazioni con SDK minimo inferiore a API 16 (Android 4.1), che praticamente non esistono sul mercato. Per tutte le applicazioni con targetSdk 33+ e SDK minimo 21+, ExoPlayer non è solo preferibile ma necessario per supportare formati moderni come AV1 e Dolby Vision attraverso le estensioni appropriate.
Per le applicazioni di produzione, l’integrazione di base di ExoPlayer richiede spesso una configurazione aggiuntiva: gestione della cache, ottimizzazione del buffer per reti mobili, integrazione con analisi e personalizzazione della selezione delle tracce audio. Vediamo scenari di utilizzo avanzati.
CacheDataSourceFactory consente di memorizzare nella cache locale i segmenti scaricati, risparmiando traffico nelle visualizzazioni ripetute e permettendo la riproduzione offline. ExoPlayer utilizza SimpleCache dalla libreria exoplayer-cas — caching basato su file con supporto di evacuazione LRU e limiti di dimensione.
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()
Nelle applicazioni mobili, la gestione della commutazione tra Wi-Fi e rete cellulare è fondamentale. ExoPlayer fornisce ConnectivityManager per monitorare lo stato della rete. In caso di perdita di connessione, si consiglia di non fermare il lettore ma di portarlo nello stato PAUSED preservando la posizione. Dopo il ripristino della connessione, riprendere la riproduzione ricaricando i segmenti.
Con il rilascio di AndroidX Media3, la libreria ha ottenuto supporto sperimentale per Jetpack Compose. Il componente `AndroidView` incapsula SurfaceView o PlayerView, garantendo la compatibilità con la gerarchia Compose. Per un’integrazione più profonda, viene utilizzata la libreria `androidx.media3:media3-ui-compose`, che fornisce controlli del lettore compatibili con Compose.
@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 } }
)
}
Domande frequenti
ExoPlayer supporta Android API 16+ (Android 4.1 Jelly Bean). Tuttavia, per DASH e HLS con segmenti fMP4, si consiglia API 21+ (Android 5.0 Lollipop). I moduli DRM (Widevine) richiedono API 19+, e la decodifica HEVC hardware è disponibile da API 21.
Sì, ExoPlayer è eccellente per l’audio. Per la riproduzione solo audio, non è necessario SurfaceView o PlayerView. ExoPlayer selezionerà automaticamente il renderer audio e funzionerà in background. Per la riproduzione in background, si consiglia di utilizzare MediaSessionService per l’integrazione con i controlli di sistema.
Il TrackSelector in ExoPlayer gestisce la selezione delle tracce audio. Per cambiare, utilizzare player.getCurrentTracks().groups e player.setTrackSelectionParameters() specificando la lingua audio preferita. Per i flussi DASH e HLS con più tracce audio, il passaggio avviene senza interrompere la riproduzione.
Sì, ExoPlayer supporta sottotitoli incorporati (in contenitori MP4, WebM) ed esterni nei formati TTML, SRT, VTT e CEA-608. Per i sottotitoli esterni, viene utilizzato SingleSampleMediaSource o MergingMediaSource per unire con il flusso video. La visualizzazione dei sottotitoli stilizzati viene configurata tramite CaptionStyleCompat.
Per lo streaming a bassa latenza, configurare LoadControl con valori di buffer target più piccoli: utilizzare DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) per HLS LL e DASH LL. Impostare anche minPlaybackSpeed = 1.02 per un riempimento accelerato del buffer quando si è in ritardo rispetto alla trasmissione live.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche