ExoPlayer est compatible avec HLS avec plusieurs formats de conteneur. Les formats d'échantillons audio et vidéo contenus doivent également être compatibles (pour en savoir plus, consultez la section Formats d'échantillons). Nous encourageons vivement les producteurs de contenus HLS à générer des flux HLS de haute qualité, comme décrit dans cet article de blog.
Fonctionnalité | Compatible | Commentaires |
---|---|---|
Conteneurs | ||
MPEG-TS | OUI | |
FMP4/CMAF | OUI | |
ADTS (AAC) | OUI | |
MP3 | OUI | |
Sous-titres /sous-titres en version étrangère | ||
CEA-608 | OUI | |
CEA-708 | OUI | |
WebVTT | OUI | |
Métadonnées | ||
ID3 | OUI | |
SCTE-35 | NON | |
Protection du contenu | ||
AES-128 | OUI | |
Exemple AES-128 | NON | |
Widevine | OUI | API 19 et versions ultérieures ("cenc") et 25 et versions ultérieures ("cbcs") |
PlayReady SL2000 | OUI | Android TV uniquement |
Contrôle du serveur | ||
Mises à jour delta | OUI | |
Bloquer le rechargement de la playlist | OUI | |
Blocage du chargement des indices de préchargement | OUI | À l'exception des plages d'octets dont la longueur n'est pas définie |
Insertion d'annonces | ||
Insertion d'annonces guidée par le serveur (annonces interstitielles) | En partie | Uniquement la VOD avec X-ASSET-URI .
Les diffusions en direct et X-ASSET-LIST seront ajoutés ultérieurement. |
Annonces IMA côté serveur et côté client | OUI | Guide d'insertion d'annonces |
Lecture en direct | ||
Lecture en direct régulière | OUI | |
HLS à faible latence (Apple) | OUI | |
HLS à faible latence (communauté) | NON | |
Données client multimédias communes CMCD | OUI | Guide d'intégration CMMC |
Utiliser MediaItem
Pour lire un flux HLS, vous devez dépendre du module HLS.
Kotlin
implementation("androidx.media3:media3-exoplayer-hls:1.6.0")
Groovy
implementation "androidx.media3:media3-exoplayer-hls:1.6.0"
Vous pouvez ensuite créer un MediaItem
pour un URI de playlist HLS et le transmettre au lecteur.
Kotlin
// Create a player instance.
val player = ExoPlayer.Builder(context).build()
// Set the media item to be played.
player.setMediaItem(MediaItem.fromUri(hlsUri))
// Prepare the player.
player.prepare()
Java
// Create a player instance.
ExoPlayer player = new ExoPlayer.Builder(context).build();
// Set the media item to be played.
player.setMediaItem(MediaItem.fromUri(hlsUri));
// Prepare the player.
player.prepare();
Si votre URI ne se termine pas par .m3u8
, vous pouvez transmettre MimeTypes.APPLICATION_M3U8
à setMimeType
de MediaItem.Builder
pour indiquer explicitement le type de contenu.
L'URI de l'élément multimédia peut pointer vers une playlist multimédia ou une playlist multivariée. Si l'URI pointe vers une playlist multivariante qui déclare plusieurs balises #EXT-X-STREAM-INF
, ExoPlayer s'adapte automatiquement entre les variantes, en tenant compte à la fois de la bande passante disponible et des fonctionnalités de l'appareil.
Utiliser HlsMediaSource
Pour plus d'options de personnalisation, vous pouvez créer un HlsMediaSource
et le transmettre directement au lecteur au lieu d'un MediaItem
.
Kotlin
// Create a data source factory.
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
// Create a HLS media source pointing to a playlist uri.
val hlsMediaSource =
HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri))
// Create a player instance.
val player = ExoPlayer.Builder(context).build()
// Set the HLS media source as the playlist with a single media item.
player.setMediaSource(hlsMediaSource)
// Prepare the player.
player.prepare()
Java
// Create a data source factory.
DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory();
// Create a HLS media source pointing to a playlist uri.
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri));
// Create a player instance.
ExoPlayer player = new ExoPlayer.Builder(context).build();
// Set the HLS media source as the playlist with a single media item.
player.setMediaSource(hlsMediaSource);
// Prepare the player.
player.prepare();
Accéder au fichier manifeste
Vous pouvez récupérer le fichier manifeste actuel en appelant Player.getCurrentManifest
.
Pour HLS, vous devez caster l'objet renvoyé en HlsManifest
. Le rappel onTimelineChanged
de Player.Listener
est également appelé chaque fois que le fichier manifeste est chargé. Cela se produit une fois pour les contenus à la demande et peut se produire plusieurs fois pour les contenus en direct. L'extrait de code suivant montre comment une application peut effectuer une action chaque fois que le fichier manifeste est chargé.
Kotlin
player.addListener(
object : Player.Listener {
override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) {
val manifest = player.currentManifest
if (manifest is HlsManifest) {
// Do something with the manifest.
}
}
}
)
Java
player.addListener(
new Player.Listener() {
@Override
public void onTimelineChanged(
Timeline timeline, @Player.TimelineChangeReason int reason) {
Object manifest = player.getCurrentManifest();
if (manifest != null) {
HlsManifest hlsManifest = (HlsManifest) manifest;
// Do something with the manifest.
}
}
});
Lire des flux HLS avec des interstitiels
La spécification HLS définit les interstitiels HLS qui peuvent être utilisés pour inclure des informations interstitielles dans une playlist multimédia. Par défaut, ExoPlayer ignore ces interstitiels. Vous pouvez ajouter une prise en charge à l'aide de HlsInterstitialsAdsLoader
. Nous ne prenons pas en charge toutes les fonctionnalités de la spécification dès le départ. Si votre flux n'est pas compatible, veuillez nous en informer en signalant un problème sur GitHub et en nous envoyant votre URI de flux afin que nous puissions le prendre en charge.
Utiliser un MediaItem
avec l'API Playlist
Le moyen le plus pratique de lire des flux HLS avec des interstitiels consiste à créer une instance ExoPlayer avec un HlsInterstitialsAdsLoader.AdsMediaSourceFactory
.
Cela permet d'utiliser l'API de playlist basée sur MediaItem
de l'interface Player
pour lire des interstitiels HLS.
Le MediaSource.Factory
de ExoPlayer
peut être injecté dans le compilateur lors de la création de l'instance de lecteur:
Kotlin
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
var hlsMediaSourceFactory =
HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader,
playerView,
DefaultMediaSourceFactory(context),
)
// Build player with interstitials media source factory
player =
ExoPlayer.Builder(context)
.setMediaSourceFactory(hlsMediaSourceFactory)
.build()
// Set the player on the ads loader.
hlsInterstitialsAdsLoader.setPlayer(player)
playerView.setPlayer(player)
Java
hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Create a MediaSource.Factory for HLS streams with interstitials.
MediaSource.Factory hlsMediaSourceFactory =
new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader, playerView, new DefaultMediaSourceFactory(context));
// Build player with interstitials media source factory
player =
new ExoPlayer.Builder(context)
.setMediaSourceFactory(hlsMediaSourceFactory)
.build();
// Set the player on the ads loader.
hlsInterstitialsAdsLoader.setPlayer(player);
playerView.setPlayer(player);
Avec une telle configuration du lecteur, la lecture d'annonces interstitielles HLS consiste simplement à définir un élément multimédia avec un AdsConfiguration
sur le lecteur:
Kotlin
player.setMediaItem(
MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0") // must be unique within playlist
.build())
.build())
player.prepare();
player.play();
Java
player.setMediaItem(
new MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
new AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0") // must be unique within playlist
.build())
.build());
player.prepare();
player.play();
Utiliser l'API basée sur la source multimédia
Vous pouvez également créer l'instance ExoPlayer sans remplacer la fabrique de sources multimédias par défaut. Pour prendre en charge les interstitiels, une application peut ensuite utiliser HlsInterstitialsAdsLoader.AdsMediaSourceFactory
directement pour créer un MediaSource
et le fournir à ExoPlayer à l'aide de l'API de playlist basée sur la source multimédia:
Kotlin
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
var hlsMediaSourceFactory =
HlsInterstitialsAdsLoader.AdsMediaSourceFactory(hlsInterstitialsAdsLoader, playerView, context)
// Build player with default media source factory.
player = new ExoPlayer.Builder(context).build();
// Create an media source from an HLS media item with ads configuration.
val mediaSource =
hlsMediaSourceFactory.createMediaSource(
MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
MediaItem.AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0")
.build()
)
.build()
)
// Set the media source on the player.
player.setMediaSource(mediaSource)
player.prepare()
player.play()
Java
HlsInterstitialsAdsLoader hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Create a MediaSource.Factory for HLS streams with interstitials.
MediaSource.Factory hlsMediaSourceFactory =
new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader, playerView, context);
// Build player with default media source factory.
player = new ExoPlayer.Builder(context).build();
// Create an media source from an HLS media item with ads configuration.
MediaSource mediaSource =
hlsMediaSourceFactory.createMediaSource(
new MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
new MediaItem.AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0")
.build())
.build());
// Set the media source on the player.
exoPlayer.setMediaSource(mediaSource);
exoPlayer.prepare();
exoPlayer.play();
Écouter les événements publicitaires
Un Listener
peut être ajouté à HlsInterstitialsAdsLoader
pour surveiller les événements liés aux changements d'état concernant la lecture des interstitiels HLS. Cela permet à une application ou à un SDK de suivre les annonces diffusées, les listes d'assets en cours de chargement, les sources multimédias d'annonces en cours de préparation ou de détecter les erreurs de chargement de la liste d'assets et de préparation des annonces. De plus, les métadonnées émises par les sources multimédias d'annonces peuvent être reçues pour vérifier la lecture des annonces de manière précise ou pour suivre la progression de la lecture des annonces.
Kotlin
class AdsLoaderListener : HlsInterstitialsAdsLoader.Listener {
override fun onStart(mediaItem: MediaItem, adsId: Any, adViewProvider: AdViewProvider) {
// Do something when HLS media item with interstitials is started.
}
override fun onMetadata(
mediaItem: MediaItem,
adsId: Any,
adGroupIndex: Int,
adIndexInAdGroup: Int,
metadata: Metadata,
) {
// Do something with metadata that is emitted by the ad media source of the given ad.
}
override fun onAdCompleted(
mediaItem: MediaItem,
adsId: Any,
adGroupIndex: Int,
adIndexInAdGroup: Int,
) {
// Do something when ad completed playback.
}
// ... See JavaDoc for further callbacks of HlsInterstitialsAdsLoader.Listener.
override fun onStop(mediaItem: MediaItem, adsId: Any, adPlaybackState: AdPlaybackState) {
// Do something with the resulting ad playback state when stopped.
}
}
Java
private class AdsLoaderListener
implements HlsInterstitialsAdsLoader.Listener {
// implement HlsInterstitialsAdsLoader.Listener
@Override
public void onStart(MediaItem mediaItem, Object adsId, AdViewProvider adViewProvider) {
// Do something when HLS media item with interstitials is started.
}
@Override
public void onMetadata(
MediaItem mediaItem,
Object adsId,
int adGroupIndex,
int adIndexInAdGroup,
Metadata metadata) {
// Do something with metadata that is emitted by the ad media source of the given ad.
}
@Override
public void onAdCompleted(
MediaItem mediaItem, Object adsId, int adGroupIndex, int adIndexInAdGroup) {
// Do something when ad completed playback.
}
// ... See JavaDoc for further callbacks of HlsInterstitialsAdsLoader.Listener.
@Override
public void onStop(MediaItem mediaItem, Object adsId, AdPlaybackState adPlaybackState) {
// Do something with the resulting ad playback state when stopped.
}
}
L'écouteur peut ensuite être ajouté au chargeur d'annonces:
Kotlin
var listener = AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
Java
AdsLoaderListener listener = new AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
Cycle de vie HlsInterstitialsAdsLoader
Une instance de HlsInterstitialsAdsLoader
ou HlsInterstitialsAdsLoader.AdsMediaSourceFactory
peut être réutilisée pour plusieurs instances de lecteur qui créent plusieurs sources multimédias pour lesquelles des annonces doivent être chargées.
Une instance peut être créée, par exemple, dans la méthode onCreate
d'un Activity
, puis réutilisée pour plusieurs instances de joueurs. Cela fonctionne tant qu'il est utilisé par une seule instance de joueur en même temps. Cela est utile pour le cas d'utilisation courant lorsque l'application est mise en arrière-plan, que l'instance du lecteur est détruite, puis qu'une nouvelle instance est créée lorsque l'application est de nouveau au premier plan.
Kotlin
// Create the ads loader instance (for example onCreate).
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context);
// Build a player and set it on the ads loader (for example onStart).
player = ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Build another player and set it on the ads loader (for example onStart).
player = ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Release the ads loader when not used anymore (for example onDestroy).
hlsInterstitialsAdsLoader.release();
Java
// Create the ads loader instance (for example onCreate).
hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Build a player and set it on the ads loader (for example onStart).
player = new ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Build another player and set it on the ads loader (for example onStart).
player = new ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Release the ads loader when not used anymore (for example onDestroy).
hlsInterstitialsAdsLoader.release();
En règle générale, veillez à libérer l'ancienne instance de lecteur avant de définir l'instance de lecteur suivante sur le chargeur d'annonces. Une fois le chargeur d'annonces lui-même publié, il ne peut plus être utilisé.
Personnaliser la lecture
ExoPlayer vous permet de personnaliser l'expérience de lecture en fonction des besoins de votre application de plusieurs façons. Pour en savoir plus, consultez la page Personnalisation.
Désactiver la préparation sans bloc
Par défaut, ExoPlayer utilise la préparation sans blocs. Cela signifie qu'ExoPlayer n'utilisera que les informations de la playlist multivariée pour préparer le flux, ce qui fonctionne si les balises #EXT-X-STREAM-INF
contiennent l'attribut CODECS
.
Vous devrez peut-être désactiver cette fonctionnalité si vos segments multimédias contiennent des pistes de sous-titres multiplexées qui ne sont pas déclarées dans la playlist multivariante avec une balise #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS
. Sinon, ces pistes de sous-titres ne seront pas détectées ni diffusées. Vous pouvez désactiver la préparation sans bloc dans HlsMediaSource.Factory
, comme indiqué dans l'extrait suivant. Notez que cela augmentera le temps de démarrage, car ExoPlayer doit télécharger un segment multimédia pour découvrir ces pistes supplémentaires. Il est préférable de déclarer les pistes de sous-titres dans la playlist multivariante.
Kotlin
val hlsMediaSource =
HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri))
Java
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri));
Créer du contenu HLS de haute qualité
Pour tirer le meilleur parti d'ExoPlayer, vous pouvez suivre certaines consignes pour améliorer votre contenu HLS. Pour en savoir plus, consultez notre post sur Medium concernant la lecture HLS dans ExoPlayer. Voici les points principaux:
- Utilisez des durées de segment précises.
- Utilisez un flux multimédia continu. Évitez les modifications de la structure multimédia entre les segments.
- Utilisez la balise
#EXT-X-INDEPENDENT-SEGMENTS
. - Privilégiez les flux démultiplexés plutôt que les fichiers contenant à la fois de la vidéo et de l'audio.
- Incluez toutes les informations possibles dans la playlist multivariée.
Les consignes suivantes s'appliquent spécifiquement aux diffusions en direct:
- Utilisez la balise
#EXT-X-PROGRAM-DATE-TIME
. - Utilisez la balise
#EXT-X-DISCONTINUITY-SEQUENCE
. - Fournissez une longue période de diffusion en direct. Une minute ou plus est idéal.