ExoPlayer поддерживает HLS с несколькими форматами контейнеров. Содержащиеся форматы образцов аудио и видео также должны поддерживаться (подробности см. в разделе « Форматы примеров» ). Мы настоятельно рекомендуем производителям контента HLS создавать высококачественные потоки HLS, как описано в этом сообщении блога .
Особенность | Поддерживается | Комментарии |
---|---|---|
Контейнеры | ||
MPEG-TS | ДА | |
ФМП4/КМАФ | ДА | |
АДТС (ААС) | ДА | |
МП3 | ДА | |
Скрытые субтитры/ субтитры | ||
СЕА-608 | ДА | |
СЕА-708 | ДА | |
ВебВТТ | ДА | |
Метаданные | ||
ID3 | ДА | |
СКТЭ-35 | НЕТ | |
Защита контента | ||
АЭС-128 | ДА | |
Образец АЭС-128 | НЕТ | |
Широкая лоза | ДА | API 19+ (схема «cenc») и 25+ (схема «cbcs») |
PlayReady SL2000 | ДА | Только Android-ТВ |
Управление сервером | ||
Дельта-обновления | ДА | |
Блокировка перезагрузки плейлиста | ДА | |
Блокировка загрузки подсказок по предварительной загрузке | ДА | За исключением диапазонов байтов с неопределенной длиной. |
Вставка объявления | ||
Вставка рекламы, управляемая сервером (межстраничные объявления) | Частично | Только VOD с X-ASSET-URI . Прямые трансляции и X-ASSET-LIST будут добавлены позже. |
Объявления IMA на стороне сервера и на стороне клиента | ДА | Руководство по вставке объявлений |
Живое воспроизведение | ||
Регулярное живое воспроизведение | ДА | |
HLS с малой задержкой (Apple) | ДА | |
HLS с низкой задержкой (сообщество) | НЕТ | |
Общие данные медиаклиента CMCD | ДА | Руководство по интеграции CMCD |
Использование Медиаитем
Чтобы воспроизводить поток HLS, вам необходимо зависеть от модуля HLS.
Котлин
implementation("androidx.media3:media3-exoplayer-hls:1.6.0")
классный
implementation "androidx.media3:media3-exoplayer-hls:1.6.0"
Затем вы можете создать MediaItem
для URI плейлиста HLS и передать его проигрывателю.
Котлин
// 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()
Ява
// 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();
Если ваш URI не заканчивается на .m3u8
, вы можете передать MimeTypes.APPLICATION_M3U8
в setMimeType
MediaItem.Builder
, чтобы явно указать тип контента.
URI элемента мультимедиа может указывать либо на список воспроизведения мультимедиа, либо на многовариантный список воспроизведения. Если URI указывает на многовариантный список воспроизведения, в котором объявлено несколько тегов #EXT-X-STREAM-INF
, то ExoPlayer автоматически адаптируется между вариантами, принимая во внимание как доступную пропускную способность, так и возможности устройства.
Использование HlsMediaSource
Чтобы получить дополнительные возможности настройки, вы можете создать HlsMediaSource
и передать его непосредственно проигрывателю вместо MediaItem
.
Котлин
// 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()
Ява
// 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();
Доступ к манифесту
Вы можете получить текущий манифест, вызвав Player.getCurrentManifest
. Для HLS вам следует привести возвращаемый объект к HlsManifest
. Обратный вызов onTimelineChanged
Player.Listener
также вызывается при каждой загрузке манифеста. Это произойдет один раз для контента по запросу и, возможно, много раз для контента в реальном времени. В следующем фрагменте кода показано, как приложение может что-то делать при загрузке манифеста.
Котлин
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.
}
}
}
)
Ява
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.
}
}
});
Воспроизведение потоков HLS с межстраничными объявлениями
Спецификация HLS определяет межстраничные объявления HLS, которые можно использовать для включения межстраничной информации в список воспроизведения мультимедиа. ExoPlayer по умолчанию игнорирует эти межстраничные объявления. Поддержка может быть добавлена с помощью HlsInterstitialsAdsLoader
. Мы не поддерживаем все функции спецификации с самого начала. Если вам не хватает поддержки вашего потока, сообщите нам об этом, оставив заявку на GitHub и отправьте нам URI вашего потока, чтобы мы могли добавить поддержку вашего потока.
Используйте MediaItem
с API списка воспроизведения.
Самый удобный способ воспроизводить потоки HLS с межстраничными объявлениями — создать экземпляр ExoPlayer с помощью HlsInterstitialsAdsLoader.AdsMediaSourceFactory
. Это позволяет использовать API плейлиста на основе MediaItem
интерфейса Player
для воспроизведения межстраничных объявлений HLS.
MediaSource.Factory
ExoPlayer
можно внедрить в сборщик при создании экземпляра проигрывателя:
Котлин
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)
Ява
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);
При такой настройке проигрывателя воспроизведение межстраничных объявлений HLS сводится к настройке медиа-элемента с AdsConfiguration
в проигрывателе:
Котлин
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();
Ява
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();
Используйте API на основе медиа-источника
Альтернативно, экземпляр ExoPlayer может быть создан без переопределения фабрики медиа-источников по умолчанию. Для поддержки межстраничных объявлений приложение может затем использовать HlsInterstitialsAdsLoader.AdsMediaSourceFactory
напрямую, чтобы создать MediaSource
и предоставить его ExoPlayer с помощью API списка воспроизведения на основе медиа-источника:
Котлин
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()
Ява
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();
Слушайте рекламные события
В HlsInterstitialsAdsLoader
можно добавить Listener
для отслеживания событий, связанных с изменениями статуса, касающимися воспроизведения межстраничных объявлений HLS. Это позволяет приложению или SDK отслеживать воспроизводимую рекламу, загрузку списков ресурсов, подготовку рекламных медиа-источников или обнаруживать ошибки загрузки списка ресурсов и подготовки рекламы. Кроме того, метаданные, исходящие от источников рекламного мультимедиа, могут быть получены для детальной проверки воспроизведения рекламы или для отслеживания хода воспроизведения рекламы.
Котлин
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.
}
}
Ява
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
@Override
public void onStop(MediaItem mediaItem, Object adsId, AdPlaybackState adPlaybackState) {
// Do something with the resulting ad playback state when stopped.
}
}
Подробную документацию по всем доступным обратным вызовам см. в JavaDoc HlsInterstitialsAdsLoader.Listener
.
Затем прослушиватель можно добавить в загрузчик рекламы:
Котлин
var listener = AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
Ява
AdsLoaderListener listener = new AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
Жизненный цикл HlsInterstitialsAdsLoader
Экземпляр HlsInterstitialsAdsLoader
или HlsInterstitialsAdsLoader.AdsMediaSourceFactory
можно повторно использовать для нескольких экземпляров проигрывателя, которые создают несколько источников мультимедиа, для которых необходимо загружать рекламу.
Экземпляр можно создать, например, в методе onCreate
Activity
, а затем повторно использовать для нескольких экземпляров игрока. Это работает до тех пор, пока оно одновременно используется одним экземпляром игрока. Это полезно в обычном случае использования, когда приложение переводится в фоновый режим, экземпляр проигрывателя уничтожается, а затем создается новый экземпляр, когда приложение снова переходит на передний план.
Котлин
// 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();
Ява
// 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();
Как правило, обязательно освободите старый экземпляр проигрывателя, прежде чем устанавливать следующий экземпляр проигрывателя в загрузчике рекламы. Как только загрузчик рекламы будет выпущен, его больше нельзя будет использовать.
Настройка воспроизведения
ExoPlayer предоставляет вам несколько способов адаптировать воспроизведение к потребностям вашего приложения. Примеры см. на странице «Настройки» .
Отключение бескусковой подготовки
По умолчанию ExoPlayer будет использовать подготовку без кусков. Это означает, что ExoPlayer будет использовать информацию из многовариантного списка воспроизведения только для подготовки потока, что работает, если теги #EXT-X-STREAM-INF
содержат атрибут CODECS
.
Возможно, вам придется отключить эту функцию, если ваши медиасегменты содержат мультиплексированные дорожки со скрытыми субтитрами, которые не объявлены в многовариантном списке воспроизведения с помощью тега #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS
. В противном случае эти треки со скрытыми субтитрами не будут обнаружены и воспроизведены. Вы можете отключить подготовку без фрагментов в HlsMediaSource.Factory
, как показано в следующем фрагменте кода. Обратите внимание, что это увеличит время запуска, поскольку ExoPlayer необходимо загрузить медиа-сегмент, чтобы обнаружить эти дополнительные треки, и вместо этого предпочтительно объявить треки со скрытыми субтитрами в многовариантном списке воспроизведения.
Котлин
val hlsMediaSource =
HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri))
Ява
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri));
Создание высококачественного HLS-контента
Чтобы получить максимальную отдачу от ExoPlayer, существует ряд рекомендаций, которым вы можете следовать, чтобы улучшить свой HLS-контент. Прочтите нашу публикацию на Medium о воспроизведении HLS в ExoPlayer для получения полного объяснения. Основные моменты:
- Используйте точную длительность сегментов.
- Используйте непрерывный медиапоток; избегать изменений в медиаструктуре между сегментами.
- Используйте тег
#EXT-X-INDEPENDENT-SEGMENTS
. - Отдавайте предпочтение демультиплексированным потокам, а не файлам, содержащим как видео, так и аудио.
- Включите всю возможную информацию в многовариантный плейлист.
Следующие правила применяются специально для прямых трансляций:
- Используйте тег
#EXT-X-PROGRAM-DATE-TIME
. - Используйте тег
#EXT-X-DISCONTINUITY-SEQUENCE
. - Обеспечьте окно долгой жизни. Одна минута или больше – это здорово.