ExoPlayer est une bibliothèque de lecteur multimédia open source pour Android développée par Google comme alternative au MediaPlayer intégré. ExoPlayer assure la lecture audio et vidéo dans divers formats, notamment DASH, HLS, SmoothStreaming et les fichiers multimédia classiques, via une API unique avec prise en charge du streaming adaptatif. Selon Google I/O (2024), ExoPlayer est utilisé dans plus de 60 000 applications Android, dont YouTube, Google TV et Netflix.
Points clés
ExoPlayer est une bibliothèque de lecture multimédia open source (Apache 2.0) pour Android, dont la première version a été publiée par Google en 2014. Contrairement au MediaPlayer intégré, qui est une fine couche au-dessus du codec multimédia système (MediaCodec), ExoPlayer est implémenté entièrement au niveau Java/Kotlin, offrant aux développeurs un contrôle total sur chaque étape de la lecture.
Architecturalement, ExoPlayer est construit sur un principe modulaire : chaque aspect de la lecture est implémenté par un composant séparé. Le module principal (exoplayer-core) contient le lecteur, les rendus, les sélecteurs de pistes et la gestion du tampon. Les modules supplémentaires (exoplayer-dash, exoplayer-hls, exoplayer-rtsp, exoplayer-smoothstreaming) ajoutent la prise en charge des protocoles de streaming correspondants. Cette architecture permet aux applications d’inclure uniquement les composants nécessaires, minimisant ainsi la taille de l’APK.
ExoPlayer 2 (la version majeure actuelle) a été publié en 2018 et a apporté une refonte radicale de l’API : introduction de l’interface Player, prise en charge de Compose via AndroidX Media3, gestion améliorée des erreurs et algorithmes adaptatifs de sélection de pistes. À partir de la version 2.19 (2024), ExoPlayer fait partie de la bibliothèque AndroidX Media, simplifiant l’intégration et les mises à jour via le gestionnaire de dépendances standard d’Android.
Au cœur d’ExoPlayer se trouve le composant ExoPlayerImpl, qui gère le cycle de vie de la lecture. Il contient MediaSource (source multimédia), TrackSelector (sélection de pistes), LoadControl (gestion de la mise en tampon) et une liste de Renderer (rendus pour la vidéo, l’audio, les sous-titres et les métadonnées). Chaque composant peut être remplacé par une implémentation personnalisée via Builder ou des méthodes d’usine.
Pour le rendu vidéo, ExoPlayer utilise SurfaceView, TextureView ou SphericalSurfaceView (pour la vidéo à 360 degrés). L’option recommandée est SurfaceView, car elle offre une accélération matérielle et une consommation d’énergie minimale. Pour Jetpack Compose, la bibliothèque AndroidX Media3 fournit le composant `AndroidView`, encapsulant SurfaceView, et l’expérimental `Media3Compose` avec une intégration native Compose.
ExoPlayer offre un large éventail de fonctionnalités au-delà d’un lecteur multimédia ordinaire. Les principales capacités incluent la prise en charge de tous les protocoles de streaming populaires, un système DRM flexible, la commutation adaptative du débit binaire (ABR) et des outils d’analyse de lecture.
| Fonction | Description | Module |
|---|---|---|
| DASH | Streaming adaptatif selon la norme MPEG | exoplayer-dash |
| HLS | HTTP Live Streaming d’Apple | exoplayer-hls |
| SmoothStreaming | Streaming adaptatif de Microsoft | exoplayer-smoothstreaming |
| RTSP | Protocole de streaming en temps réel pour le live | exoplayer-rtsp |
| Widevine | Protection du contenu DRM | exoplayer-drm |
| Concatenation | Assemblage de plusieurs fichiers multimédia | exoplayer-core |
| Ads | Intégration IMA SDK pour la publicité | exoplayer-ima |
ABR (Adaptive Bitrate) dans ExoPlayer est implémenté via l’interface AdaptiveTrackSelection. Par défaut, AdaptiveTrackSelectionFactory est utilisé, qui crée DefaultAdaptiveTrackSelection — un algorithme équilibré prenant en compte la bande passante réseau et la taille du tampon. Pour des scénarios spécifiques, des implémentations alternatives peuvent être branchées : BOLA (minimisation des commutations), RandomAdaptiveTrackSelection (tests) ou une implémentation personnalisée via l’interface TrackSelection.
BandwidthMeter — un autre composant clé responsable de la mesure de la bande passante réseau. Par défaut, DefaultBandwidthMeter est utilisé, qui collecte des statistiques sur toutes les requêtes HTTP du lecteur. Le développeur peut l’étendre pour prendre en compte des facteurs supplémentaires : type de réseau (Wi-Fi, 4G, 5G), signal de la tour cellulaire ou coût des données pour l’utilisateur.
ExoPlayer prend en charge Widevine (L1, L3), PlayReady et ClearKey DRM. L’obtention de licence est configurée via DrmSessionManager, qui interagit avec le serveur de licences. Pour la vidéo premium (4K HDR), un support matériel Widevine L1 est requis, offrant une protection au niveau de la puce et empêchant la capture d’écran. Le choix du système DRM dépend de la plateforme cible : Widevine est utilisé sur Android et Chromecast, PlayReady sur Xbox et Windows, FairPlay sur iOS et Apple TV. ExoPlayer détermine automatiquement le système DRM disponible en se basant sur le fichier MPD et ne nécessite pas de configuration manuelle pour les scénarios de base.
La connexion d’ExoPlayer à un projet Android se fait via des dépendances Gradle. À partir de la version 2.19, ExoPlayer fait partie d’AndroidX Media (androidx.media3), garantissant la compatibilité avec Jetpack Compose et d’autres composants AndroidX. Voyons une intégration étape par étape en Kotlin.
Ajoutez les modules ExoPlayer au fichier build.gradle (Module). L’ensemble minimal comprend core, ui et le module pour le protocole de streaming nécessaire. Pour la lecture de contenu DASH, exoplayer-dash est requis, pour 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"
}
Création et configuration du lecteur dans une Activity ou un Fragment. ExoPlayer utilise PlayerView (ou StyledPlayerView pour la personnalisation) pour afficher la vidéo et les contrôles intégrés. La configuration minimale comprend la création du lecteur via ExoPlayer.Builder et le passage d’un MediaItem avec l’URI source.
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()
}
}
Pour les applications de production, la gestion des erreurs de lecture possibles est nécessaire : pannes réseau, formats non pris en charge, erreurs de licence DRM. ExoPlayer fournit l’interface Player.Listener avec les méthodes onPlayerError, onPlaybackStateChanged et onPlayWhenReadyChanged. Il est recommandé d’afficher à l’utilisateur des messages d’erreur informatifs avec une option de réessai.
Choisir entre ExoPlayer et le MediaPlayer intégré est une question courante lors du développement d’applications Android. MediaPlayer fait partie de l’Android SDK depuis la version 1.0, tandis qu’ExoPlayer est une bibliothèque nécessitant une dépendance Gradle. Examinons leurs différences selon des critères clés.
| Critère | ExoPlayer | MediaPlayer |
|---|---|---|
| Architecture | Modulaire, entièrement en Java/Kotlin | Couche au-dessus des composants C++ système |
| Streaming | DASH, HLS, SmoothStreaming, RTSP | Fichiers locaux uniquement et HLS (Android 9+) |
| Personnalisation | Totale (tout composant remplaçable) | Minimale (paramètres uniquement) |
| Mises à jour | Via Google Play ou APK (indépendant de l’OS) | Uniquement via mise à jour Android (OTA) |
| Taille APK | +1–3 Mo (selon les modules) | 0 (partie de l’OS) |
| SDK min | API 16+ (Android 4.1) | API 1+ |
| DRM | Widevine, PlayReady, ClearKey | Widevine (limité) |
ExoPlayer l’emporte dans les scénarios nécessitant du streaming (DASH, HLS), une personnalisation de l’interface, une prise en charge DRM et une indépendance vis-à-vis de la version Android. MediaPlayer convient aux applications simples lisant des fichiers multimédia locaux où la taille de l’APK est critique et sans exigence de streaming adaptatif. Pour les applications modernes avec du contenu réseau, ExoPlayer est le choix évident.
Exception — les applications avec un SDK minimum inférieur à l’API 16 (Android 4.1), qui n’existent pratiquement plus sur le marché. Pour toutes les applications avec targetSdk 33+ et SDK minimum 21+, ExoPlayer est non seulement préférable mais nécessaire pour prendre en charge les formats modernes comme AV1 et Dolby Vision via les extensions appropriées.
Pour les applications de production, l’intégration de base d’ExoPlayer nécessite souvent une configuration supplémentaire : gestion du cache, optimisation du tampon pour les réseaux mobiles, intégration avec l’analyse et personnalisation de la sélection des pistes audio. Examinons les scénarios d’utilisation avancés.
CacheDataSourceFactory permet de mettre en cache les segments téléchargés sur le stockage local, économisant du trafic lors des visionnages répétés et permettant la lecture hors ligne. ExoPlayer utilise SimpleCache de la bibliothèque exoplayer-cas — une mise en cache basée sur des fichiers avec prise en charge de l’éviction LRU et des limites de taille.
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()
Dans les applications mobiles, la gestion de la commutation entre Wi-Fi et réseau cellulaire est cruciale. ExoPlayer fournit ConnectivityManager pour suivre l’état du réseau. En cas de perte de connexion, il est recommandé de ne pas arrêter le lecteur mais de le mettre en état PAUSED en conservant la position. Après restauration de la connexion, reprendre la lecture en rechargeant les segments.
Avec la sortie d’AndroidX Media3, la bibliothèque a obtenu une prise en charge expérimentale de Jetpack Compose. Le composant `AndroidView` encapsule SurfaceView ou PlayerView, assurant la compatibilité avec la hiérarchie Compose. Pour une intégration plus profonde, la bibliothèque `androidx.media3:media3-ui-compose` est utilisée, fournissant des contrôles de lecteur compatibles 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 } }
)
}
Questions fréquemment posées
ExoPlayer prend en charge Android API 16+ (Android 4.1 Jelly Bean). Cependant, pour DASH et HLS avec des segments fMP4, API 21+ (Android 5.0 Lollipop) est recommandée. Les modules DRM (Widevine) nécessitent API 19+, et le décodage matériel HEVC est disponible à partir de l’API 21.
Oui, ExoPlayer est excellent pour l’audio. Pour une lecture audio uniquement, SurfaceView ou PlayerView n’est pas nécessaire. ExoPlayer sélectionnera automatiquement le rendu audio et fonctionnera en arrière-plan. Pour la lecture en arrière-plan, il est recommandé d’utiliser MediaSessionService pour l’intégration avec les commandes système.
Le TrackSelector dans ExoPlayer gère la sélection des pistes audio. Pour basculer, utilisez player.getCurrentTracks().groups et player.setTrackSelectionParameters() en spécifiant la langue audio préférée. Pour les flux DASH et HLS avec plusieurs pistes audio, le basculement se produit sans interrompre la lecture.
Oui, ExoPlayer prend en charge les sous-titres intégrés (dans les conteneurs MP4, WebM) et externes aux formats TTML, SRT, VTT et CEA-608. Pour les sous-titres externes, SingleSampleMediaSource ou MergingMediaSource est utilisé pour fusionner avec le flux vidéo. L’affichage des sous-titres stylisés est configuré via CaptionStyleCompat.
Pour le streaming à faible latence, configurez LoadControl avec des valeurs de tampon cible plus petites : utilisez DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) pour HLS LL et DASH LL. Définissez également minPlaybackSpeed = 1.02 pour un remplissage accéléré du tampon en cas de retard sur la diffusion en direct.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi