ExoPlayer можно использовать как для вставки рекламы на стороне клиента, так и на стороне сервера.
Вставка рекламы на стороне клиента
При вставке рекламы на стороне клиента плеер переключается между загрузкой медиафайлов с разных URL-адресов по мере перехода от воспроизводимого контента к рекламе. Информация о рекламе загружается отдельно от медиафайлов, например, из тега XML VAST или VMAP . Это может включать в себя позиции рекламных фрагментов относительно начала контента, фактические URI рекламных медиафайлов и метаданные, такие как возможность пропуска данной рекламы.
При использовании AdsMediaSource из ExoPlayer для вставки рекламы на стороне клиента, плеер получает информацию о воспроизводимой рекламе. Это дает ряд преимуществ:
- Игрок может предоставлять доступ к метаданным и функционалу, связанным с рекламой, используя свой API.
- Компоненты пользовательского интерфейса ExoPlayer могут автоматически отображать маркеры позиций рекламы и изменять свое поведение в зависимости от того, воспроизводится ли реклама.
- Внутри системы плеер может поддерживать постоянный буфер при переходах между рекламой и контентом.
В этой конфигурации плеер сам переключается между рекламой и контентом, а это значит, что приложениям не нужно управлять несколькими отдельными плеерами для показа рекламы и контента в фоновом/активном режиме.
При подготовке видеороликов и рекламных тегов для использования с вставкой рекламы на стороне клиента, рекламу в идеале следует размещать в момент синхронизации (ключевые кадры) видеоролика, чтобы проигрыватель мог беспрепятственно возобновить воспроизведение контента.
Декларативная поддержка рекламы
URI рекламного тега можно указать при создании MediaItem :
Котлин
val mediaItem = MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(new MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build();
Для включения поддержки воспроизведения медиафайлов, содержащих рекламные теги, необходимо создать и внедрить DefaultMediaSourceFactory , настроенный с использованием AdsLoader.Provider и AdViewProvider при создании плеера:
Котлин
val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(context).setLocalAdInsertionComponents(adsLoaderProvider, playerView) val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build()
Java
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(context) .setLocalAdInsertionComponents(adsLoaderProvider, /* adViewProvider= */ playerView); ExoPlayer player = new ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
Внутри DefaultMediaSourceFactory оборачивает источник медиаконтента в AdsMediaSource . AdsMediaSource получает AdsLoader от AdsLoader.Provider и использует его для вставки рекламы в соответствии с рекламным тегом медиафайла.
PlayerView ExoPlayer реализует AdViewProvider . Библиотека IMA ExoPlayer предоставляет простой в использовании AdsLoader , как описано ниже.
Плейлисты с рекламой
При воспроизведении плейлиста, содержащего несколько медиафайлов, по умолчанию запрашивается рекламный тег и сохраняется состояние воспроизведения рекламы один раз для каждой комбинации идентификатора медиафайла, URI контента и URI рекламного тега. Это означает, что пользователи будут видеть рекламу для каждого медиафайла, содержащего рекламу с уникальным идентификатором медиафайла или URI контента, даже если URI рекламных тегов совпадают. Если медиафайл повторяется, пользователь увидит соответствующую рекламу только один раз (состояние воспроизведения рекламы хранит информацию о том, была ли реклама воспроизведена, поэтому она пропускается после первого показа).
Это поведение можно настроить, передав непрозрачный идентификатор рекламы, с которым связано состояние воспроизведения рекламы для данного медиафайла на основе равенства объектов. Вот пример, где состояние воспроизведения рекламы связано только с URI тега рекламы, а не с комбинацией идентификатора медиафайла и URI тега рекламы, путем передачи URI тега рекламы в качестве идентификатора рекламы. В результате реклама будет загружаться только один раз, и пользователь не увидит рекламу во втором элементе при воспроизведении плейлиста от начала до конца.
Котлин
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. val firstItem = MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() val secondItem = MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() player.addMediaItem(firstItem) player.addMediaItem(secondItem)
Java
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. MediaItem firstItem = new MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); MediaItem secondItem = new MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); player.addMediaItem(firstItem); player.addMediaItem(secondItem);
Вставка рекламы на стороне клиента с управлением со стороны сервера
ExoPlayer поставляется с HlsInterstitialsAdsLoader , который поддерживает автоматическую вставку рекламы, определенной в плейлисте HLS, на стороне клиента. См. раздел о HlsInterstitialsAdsLoader на странице HLS .
Библиотека ExoPlayer IMA
Библиотека ExoPlayer IMA предоставляет ImaAdsLoader , что упрощает интеграцию вставки рекламы на стороне клиента в ваше приложение. Она использует функциональность клиентского SDK IMA для поддержки вставки рекламы VAST/VMAP. Инструкции по использованию библиотеки, включая обработку фонового режима и возобновление воспроизведения, см. в файле README .
Демонстрационное приложение использует библиотеку IMA и включает в себя несколько примеров рекламных тегов VAST/VMAP в списке примеров.
соображения пользовательского интерфейса
По умолчанию PlayerView скрывает элементы управления воспроизведением во время показа рекламы, но приложения могут изменить это поведение, вызвав метод setControllerHideDuringAds . В этом случае SDK IMA будет отображать дополнительные элементы поверх плеера во время воспроизведения рекламы (например, ссылку «подробнее» и кнопку «пропустить», если применимо).
IMA SDK может сообщать, перекрываются ли рекламные объявления представлениями, предоставляемыми приложением и отображаемыми поверх плеера. Приложениям, которым необходимо перекрывать представления, необходимые для управления воспроизведением, следует зарегистрировать их в IMA SDK, чтобы они не учитывались при расчете видимости. При использовании PlayerView в качестве AdViewProvider , он автоматически зарегистрирует свои элементы управления. Приложениям, использующим пользовательский интерфейс плеера, необходимо регистрировать элементы управления, возвращая их из AdViewProvider.getAdOverlayInfos .
Для получения дополнительной информации о наложенных представлениях см. раздел «Открытие измерений» в SDK IMA .
Сопутствующие объявления
Некоторые рекламные теги содержат дополнительные сопутствующие объявления, которые могут отображаться в «слотах» в пользовательском интерфейсе приложения. Эти слоты можно передать с помощью метода ImaAdsLoader.Builder.setCompanionAdSlots(slots) . Для получения дополнительной информации см. раздел «Добавление сопутствующих объявлений» .
Отдельные рекламные объявления
IMA SDK предназначен для вставки рекламы в медиаконтент, а не для воспроизведения отдельных рекламных объявлений. Поэтому воспроизведение отдельных рекламных объявлений не поддерживается библиотекой IMA. Для этой цели мы рекомендуем использовать Google Mobile Ads SDK .
Использование стороннего SDK для рекламы
Если вам необходимо загружать рекламу через сторонний SDK для рекламы, стоит проверить, предоставляет ли он уже интеграцию с ExoPlayer. Если нет, рекомендуется реализовать собственный AdsLoader , который будет обертывать сторонний SDK для рекламы, поскольку он обеспечивает преимущества AdsMediaSource , описанные выше. ImaAdsLoader служит примером реализации.
В качестве альтернативы вы можете использовать функцию создания плейлистов в ExoPlayer для формирования последовательности рекламных роликов и видеофрагментов:
Котлин
// A pre-roll ad. val preRollAd = MediaItem.fromUri(preRollAdUri) // The start of the content. val contentStart = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(MediaItem.ClippingConfiguration.Builder().setEndPositionMs(120000).build()) .build() // A mid-roll ad. val midRollAd = MediaItem.fromUri(midRollAdUri) // The rest of the content val contentEnd = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(MediaItem.ClippingConfiguration.Builder().setStartPositionMs(120000).build()) .build() // Build the playlist. player.addMediaItem(preRollAd) player.addMediaItem(contentStart) player.addMediaItem(midRollAd) player.addMediaItem(contentEnd)
Java
// A pre-roll ad. MediaItem preRollAd = MediaItem.fromUri(preRollAdUri); // The start of the content. MediaItem contentStart = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new MediaItem.ClippingConfiguration.Builder().setEndPositionMs(120_000).build()) .build(); // A mid-roll ad. MediaItem midRollAd = MediaItem.fromUri(midRollAdUri); // The rest of the content MediaItem contentEnd = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new MediaItem.ClippingConfiguration.Builder().setStartPositionMs(120_000).build()) .build(); // Build the playlist. player.addMediaItem(preRollAd); player.addMediaItem(contentStart); player.addMediaItem(midRollAd); player.addMediaItem(contentEnd);
Вставка рекламы на стороне сервера
При вставке рекламы на стороне сервера (также называемой динамической вставкой рекламы, или DAI) медиапоток содержит как рекламу, так и контент. Манифест DASH может указывать как на сегменты контента, так и на сегменты рекламы, возможно, в разных периодах. Для HLS см. документацию Apple по включению рекламы в плейлист .
При использовании серверной вставки рекламы клиенту может потребоваться динамически определять URL-адрес медиафайла для получения объединенного потока, отображать рекламные наложения в пользовательском интерфейсе или отправлять сообщения о событиях в SDK для рекламы или на рекламный сервер.
Компонент DefaultMediaSourceFactory в ExoPlayer может делегировать все эти задачи серверному MediaSource для вставки рекламы по URI, использующим схему ssai:// :
Котлин
val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setServerSideAdInsertionMediaSourceFactory(ssaiFactory) ) .build()
Java
Player player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setServerSideAdInsertionMediaSourceFactory(ssaiFactory)) .build();
Библиотека ExoPlayer IMA
Библиотека ExoPlayer IMA предоставляет ImaServerSideAdInsertionMediaSource , что упрощает интеграцию с потоками вставляемой рекламы на стороне сервера IMA в ваше приложение. Она инкапсулирует функциональность SDK IMA DAI для Android и полностью интегрирует предоставленные метаданные рекламы в плеер. Например, это позволяет использовать такие методы, как Player.isPlayingAd() , отслеживать переходы между контентом и рекламой и позволять плееру обрабатывать логику воспроизведения рекламы, например, пропускать уже показанные объявления.
Для использования этого класса необходимо настроить объекты ImaServerSideAdInsertionMediaSource.AdsLoader и ImaServerSideAdInsertionMediaSource.Factory и подключить их к плееру:
Котлин
// MediaSource.Factory to load the actual media stream. val defaultMediaSourceFactory = DefaultMediaSourceFactory(context) // AdsLoader that can be reused for multiple playbacks. val adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build() // MediaSource.Factory to create the ad sources for the current player. val adsMediaSourceFactory = ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory) // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory) // Set the MediaSource.Factory on the Player. val player = ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build() // Set the player on the AdsLoader adsLoader.setPlayer(player)
Java
// MediaSource.Factory to load the actual media stream. DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context); // AdsLoader that can be reused for multiple playbacks. ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader = new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build(); // MediaSource.Factory to create the ad sources for the current player. ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory = new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory); // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory); // Set the MediaSource.Factory on the Player. Player player = new ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build(); // Set the player on the AdsLoader adsLoader.setPlayer(player);
Загрузите ключ ресурса IMA, или идентификатор источника контента и идентификатор видео, создав URL-адрес с помощью ImaServerSideAdInsertionUriBuilder :
Котлин
val ssaiUri = ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build() player.setMediaItem(MediaItem.fromUri(ssaiUri))
Java
Uri ssaiUri = new ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build(); player.setMediaItem(MediaItem.fromUri(ssaiUri));
Наконец, освободите загрузчик рекламы, когда он больше не будет использоваться:
Котлин
adsLoader.release()
Java
adsLoader.release();
соображения пользовательского интерфейса
Те же соображения, касающиеся пользовательского интерфейса, что и при вставке рекламы на стороне клиента, применимы и к вставке рекламы на стороне сервера.
Сопутствующие объявления
Некоторые рекламные теги содержат дополнительные сопутствующие объявления, которые могут отображаться в «слотах» в пользовательском интерфейсе приложения. Эти слоты можно передать с помощью метода ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots) . Для получения дополнительной информации см. раздел «Добавление сопутствующих объявлений» .
Использование стороннего SDK для рекламы
Если вам необходимо загружать рекламу с помощью стороннего SDK для рекламы, стоит проверить, предоставляет ли он уже интеграцию с ExoPlayer. Если нет, рекомендуется использовать собственный MediaSource , принимающий URI со схемой ssai:// аналогично ImaServerSideAdInsertionMediaSource .
Фактическую логику создания структуры объявления можно делегировать универсальному компоненту ServerSideAdInsertionMediaSource , который инкапсулирует поток MediaSource и позволяет пользователю устанавливать и обновлять AdPlaybackState , представляющий метаданные объявления.
Часто в рекламные потоки, вставляемые на стороне сервера, содержатся события, привязанные ко времени, которые уведомляют проигрыватель о метаданных рекламы. Информацию о поддерживаемых форматах метаданных можно найти в разделе «Поддерживаемые форматы ». Реализации MediaSource в пользовательском SDK для рекламы могут отслеживать события, привязанные ко времени, от проигрывателя с помощью Player.Listener.onMetadata .