Вставка рекламы

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()

Ява

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()

Ява

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 . Библиотека ExoPlayer IMA предоставляет простой в использовании 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)

Ява

// 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 IMA

Библиотека ExoPlayer IMA предоставляет ImaAdsLoader , что позволяет легко интегрировать вставку рекламы на стороне клиента в ваше приложение. Он объединяет функциональность клиентского IMA SDK для поддержки вставки объявлений VAST/VMAP. Инструкции по использованию библиотеки, в том числе по работе с фоновым режимом и возобновлению воспроизведения, см. в README .

Демонстрационное приложение использует библиотеку IMA и включает в список примеров несколько рекламных тегов VAST/VMAP.

Рекомендации по пользовательскому интерфейсу

PlayerView по умолчанию скрывает элементы управления транспортировкой во время воспроизведения рекламы, но приложения могут отключить это поведение, вызвав setControllerHideDuringAds . IMA SDK будет отображать дополнительные представления поверх проигрывателя во время воспроизведения рекламы (например, ссылку «Подробнее» и кнопку «Пропустить», если применимо).

IMA SDK может сообщать, скрыты ли рекламные объявления в представлениях, предоставляемых приложением и отображаемых поверх проигрывателя. Приложения, которым необходимо накладывать представления, необходимые для управления воспроизведением, должны зарегистрировать их в IMA SDK, чтобы их можно было исключить из расчетов видимости. При использовании PlayerView в качестве AdViewProvider он автоматически регистрирует свои наложения элементов управления. Приложения, использующие собственный пользовательский интерфейс проигрывателя, должны регистрировать представления наложения, возвращая их из AdViewProvider.getAdOverlayInfos .

Дополнительную информацию о представлениях наложения см. в разделе Open Measurement в IMA SDK .

Сопутствующие объявления

Некоторые теги объявлений содержат дополнительные сопутствующие объявления, которые можно показывать в «слотах» пользовательского интерфейса приложения. Эти слоты можно передать через 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(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(ClippingConfiguration.Builder().setStartPositionMs(120000).build())
    .build()

// Build the playlist.
player.addMediaItem(preRollAd)
player.addMediaItem(contentStart)
player.addMediaItem(midRollAd)
player.addMediaItem(contentEnd)

Ява

// A pre-roll ad.
MediaItem preRollAd = MediaItem.fromUri(preRollAdUri);
// The start of the content.
MediaItem contentStart =
    new MediaItem.Builder()
        .setUri(contentUri)
        .setClippingConfiguration(
            new 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 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()

Ява

Player player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context)
                .setServerSideAdInsertionMediaSourceFactory(ssaiFactory))
        .build();

Библиотека ExoPlayer IMA

Библиотека ExoPlayer IMA предоставляет ImaServerSideAdInsertionMediaSource , что упрощает интеграцию с вставленными на стороне сервера рекламными потоками IMA в вашем приложении. Он объединяет функциональность IMA DAI SDK для 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)

Ява

// 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))

Ява

Uri ssaiUri =
    new ImaServerSideAdInsertionUriBuilder()
        .setAssetKey(assetKey)
        .setFormat(C.CONTENT_TYPE_HLS)
        .build();
player.setMediaItem(MediaItem.fromUri(ssaiUri));

Наконец, отпустите загрузчик рекламы, когда он больше не будет использоваться:

Котлин

adsLoader.release()

Ява

adsLoader.release();

Рекомендации по пользовательскому интерфейсу

Те же рекомендации по пользовательскому интерфейсу, что и при вставке рекламы на стороне клиента, применимы и к вставке рекламы на стороне сервера.

Сопутствующие объявления

Некоторые теги объявлений содержат дополнительные сопутствующие объявления, которые можно показывать в «слотах» пользовательского интерфейса приложения. Эти слоты можно передать через ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots) . Дополнительную информацию см. в разделе «Добавление сопутствующих объявлений» .

Использование стороннего рекламного SDK

Если вам нужно загружать рекламу с помощью стороннего рекламного SDK, стоит проверить, обеспечивает ли он уже интеграцию с ExoPlayer. В противном случае рекомендуется предоставить собственный MediaSource , который принимает URI со схемой ssai:// аналогичной ImaServerSideAdInsertionMediaSource .

Фактическую логику создания структуры объявления можно делегировать серверу общего назначения ServerSideAdInsertionMediaSource , который оборачивает поток MediaSource и позволяет пользователю устанавливать и обновлять AdPlaybackState представляющий метаданные объявления.

Зачастую рекламные потоки, вставленные на стороне сервера, содержат синхронизированные события для уведомления игрока о метаданных рекламы. Ознакомьтесь с поддерживаемыми форматами для получения информации о том, какие форматы синхронизированных метаданных поддерживаются ExoPlayer. Реализации SDK для пользовательских объявлений MediaSource могут прослушивать синхронизированные события метаданных от проигрывателя с помощью Player.Listener.onMetadata .