ExoPlayer можно использовать для вставки рекламы как на стороне клиента, так и на стороне сервера.
Вставка объявлений на стороне клиента
При вставке объявлений на стороне клиента проигрыватель переключается между загрузкой медиаконтента с разных URL при переходе от контента к рекламе. Информация об объявлениях загружается отдельно от медиаконтента, например из XML-тега объявления VAST или VMAP. Это могут быть позиции рекламных пауз относительно начала контента, фактические URI медиафайлов объявлений и метаданные, например можно ли пропустить то или иное объявление.
При использовании AdsMediaSource ExoPlayer для вставки объявлений на стороне клиента у проигрывателя есть информация об объявлениях, которые нужно воспроизвести. Это дает следующие преимущества:
- С помощью API проигрыватель может предоставлять метаданные и функции, связанные с рекламой.
- Компоненты интерфейса ExoPlayer могут автоматически показывать маркеры позиций объявлений и менять свое поведение в зависимости от того, воспроизводится ли реклама.
- Внутренний буфер проигрывателя остается неизменным при переходе от рекламы к контенту.
В этом случае переключение между объявлениями и контентом выполняет проигрыватель, поэтому приложениям не нужно управлять несколькими отдельными проигрывателями для объявлений и контента.
При подготовке видеоконтента и тегов объявлений для использования с клиентской вставкой рекламы объявления должны быть размещены в синхронизированных выборках (ключевых кадрах) видеоконтента, чтобы проигрыватель мог без проблем возобновить воспроизведение контента.
Поддержка декларативных объявлений
URI тега объявления можно указать при создании MediaItem:
Kotlin
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:
Kotlin
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 тега объявления передается как идентификатор объявления. В результате объявления будут загружаться только один раз, и пользователь не увидит рекламу во втором видео, если будет смотреть плейлист от начала до конца.
Kotlin
// 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.
Библиотека IMA для ExoPlayer
Библиотека ExoPlayer IMA предоставляет ImaAdsLoader, что упрощает интеграцию в приложение вставки объявлений на стороне клиента. Она включает функции IMA SDK на стороне клиента для поддержки вставки объявлений VAST/VMAP. Инструкции по использованию библиотеки, в том числе по обработке фонового режима и возобновлению воспроизведения, приведены в файле README.
В демонстрационном приложении используется библиотека IMA и есть несколько примеров тегов объявлений VAST/VMAP.
Особенности интерфейса
PlayerView по умолчанию скрывает элементы управления воспроизведением во время показа рекламы, но приложения могут изменить это поведение, вызвав setControllerHideDuringAds. Во время показа объявления поверх проигрывателя с помощью IMA SDK будут показываться дополнительные элементы, например ссылка "Подробнее" и кнопка пропуска (если она доступна).
IMA SDK может сообщать, закрыты ли объявления элементами интерфейса, которые приложение размещает поверх проигрывателя. Приложения, которым необходимо накладывать представления, важные для управления воспроизведением, должны регистрировать их в IMA SDK, чтобы они не учитывались при расчете видимости. Если в качестве AdViewProvider используется PlayerView, то его наложения для управления будут зарегистрированы автоматически. Приложения, в которых используется собственный интерфейс проигрывателя, должны регистрировать наложения, возвращая их из AdViewProvider.getAdOverlayInfos.
Подробнее об отслеживании видимости в IMA SDK…
Сопутствующие баннеры
Некоторые теги объявлений содержат дополнительные сопутствующие объявления, которые можно показывать в слотах в интерфейсе приложения. Эти слоты можно передавать с помощью ImaAdsLoader.Builder.setCompanionAdSlots(slots). Подробнее о том, как добавлять сопутствующие объявления…
Отдельные объявления
IMA SDK предназначена для вставки объявлений в медиаконтент, а не для воспроизведения отдельных объявлений. Поэтому библиотека IMA не поддерживает воспроизведение отдельных объявлений. В этом случае мы рекомендуем использовать Google Mobile Ads SDK.
Использование стороннего SDK для рекламы
Если вам нужно загружать объявления через сторонний рекламный SDK, проверьте, есть ли в нем интеграция с ExoPlayer. Если нет, рекомендуем реализовать собственный AdsLoader, который будет обертывать сторонний SDK для объявлений, поскольку это позволит вам воспользоваться преимуществами AdsMediaSource, описанными выше.
ImaAdsLoader – это пример реализации.
Вы также можете использовать поддержку плейлистов в ExoPlayer, чтобы создать последовательность объявлений и фрагментов контента:
Kotlin
// 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: Incorporating ads into a playlist (Добавление рекламы в плейлист).
При использовании вставки объявлений на стороне сервера клиенту может потребоваться динамически разрешить URL медиаконтента, чтобы получить объединенный поток, показать наложения объявлений в интерфейсе или отправить отчеты о событиях в SDK для рекламы или на сервер объявлений.
DefaultMediaSourceFactory ExoPlayer может делегировать все эти задачи MediaSource для URI, использующих схему ssai://:
Kotlin
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();
Библиотека IMA для ExoPlayer
Библиотека ExoPlayer IMA предоставляет ImaServerSideAdInsertionMediaSource, что позволяет легко интегрировать в приложение потоки объявлений, вставляемых на стороне сервера с помощью IMA. Она включает функции IMA DAI SDK для Android и полностью интегрирует предоставленные метаданные объявлений в проигрыватель. Например, это позволяет использовать такие методы, как Player.isPlayingAd(), отслеживать переходы между контентом и объявлениями и позволять проигрывателю обрабатывать логику воспроизведения объявлений, например пропускать уже показанные объявления.
Чтобы использовать этот класс, вам нужно настроить ImaServerSideAdInsertionMediaSource.AdsLoader и ImaServerSideAdInsertionMediaSource.Factory и подключить их к проигрывателю:
Kotlin
// 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:
Kotlin
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));
Наконец, освободите загрузчик объявлений, когда он больше не нужен:
Kotlin
adsLoader.release()
Java
adsLoader.release();
Особенности интерфейса
При показе рекламы на стороне сервера действуют те же требования к интерфейсу, что и при показе рекламы на стороне клиента.
Сопутствующие баннеры
Некоторые теги объявлений содержат дополнительные сопутствующие объявления, которые можно показывать в слотах в интерфейсе приложения. Эти слоты можно передавать с помощью ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots).
Подробнее о добавлении сопутствующих объявлений…
Использование стороннего SDK для рекламы
Если вам нужно загружать объявления с помощью стороннего SDK, проверьте, есть ли в нем интеграция с ExoPlayer. В противном случае рекомендуется указать специальный MediaSource, который принимает URI со схемой ssai://, аналогичной ImaServerSideAdInsertionMediaSource.
Фактическая логика создания структуры объявления может быть делегирована универсальному объекту ServerSideAdInsertionMediaSource, который содержит поток MediaSource и позволяет пользователю задавать и обновлять объект AdPlaybackState, представляющий метаданные объявления.
Часто в рекламных потоках, вставленных на стороне сервера, содержатся события с временными метками, которые уведомляют проигрыватель о метаданных объявлений. Информацию о том, какие форматы метаданных с временными метками поддерживаются ExoPlayer, можно найти в разделе Поддерживаемые форматы. Реализации SDK специальных объявлений MediaSourceмогут прослушивать события метаданных с временными метками от проигрывателя с помощью Player.Listener.onMetadata.