插入广告

ExoPlayer 可用于客户端和服务器端广告插播。

客户端广告插播

在客户端广告插播中,播放器会在 在播放内容和广告之间转换时,应用会具有不同的网址。信息 与媒体分开加载,例如通过 XML VASTVMAP 广告代码。可包含广告插入点相对于 实际的广告媒体 URI 和元数据(如指定的广告是否 可跳过的广告

使用 ExoPlayer 的 AdsMediaSource 进行客户端广告插播时,播放器 包含要播放的广告的相关信息。这样做有几个好处:

  • 播放器可以使用其 API 提供与广告相关的元数据和功能。
  • ExoPlayer 界面组件可自动显示广告位置的标记, 并根据广告是否正在播放更改自身行为。
  • 在内部,播放器可以在两个视频之间的转场之间保持一致的缓冲区。 广告和内容。

在这种设置中,播放器负责在广告和内容之间进行切换, 这意味着应用无需负责控制 用于广告和内容的后台/前台播放器。

在准备要用于客户端广告插播的内容视频和广告代码时, 理想情况下,广告应放置在 内容视频,以便播放器可以无缝地继续播放内容。

声明式广告支持

构建 MediaItem 时,您可以指定广告代码 URI:

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.ProviderAdViewProvider

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 会将内容媒体来源封装在 AdsMediaSourceAdsMediaSource 将从 AdsLoader AdsLoader.Provider,并使用它来插入媒体项的广告所定义的广告 标记前面。

ExoPlayer 的 PlayerView 实现了 AdViewProvider。ExoPlayer IMA 库提供了一个易于使用的 AdsLoader,如下所述。

含广告的播放列表

播放包含多个媒体项的播放列表时,默认行为是 来请求广告代码并针对每个媒体 ID 存储一次广告播放状态, 内容 URI 和广告代码 URI 组合。也就是说,如果用户看到的是 包含具有独特媒体 ID 或内容 URI 的广告的每项媒体项,即使 广告代码 URI 是否匹配。如果媒体项重复出现,用户会看到 (广告播放状态存储广告是否已 因此系统会在第一次播放后跳过广告)。

您可以通过传递一个不透明的广告标识符来自定义此行为 与哪个广告播放状态相关联的指定媒体项(基于对象 是否相等。以下是广告播放状态与广告代码关联的 而不是媒体 ID 和广告代码 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 IMA 库

ExoPlayer IMA 库提供了 ImaAdsLoader,可让您轻松 将客户端广告插播功能集成到您的应用中。它封装了 客户端 IMA SDK 以支持插入 VAST/VMAP 广告。对于 有关如何使用该库的说明,包括如何处理后台运行 和恢复播放,请参见自述文件

演示应用使用 IMA 库,并包含几个示例应用 示例列表中的 VAST/VMAP 广告代码。

界面注意事项

PlayerView在广告播放期间隐藏其传输控件,具体方法是: 但应用可通过调用 setControllerHideDuringAds。IMA SDK 会在顶部显示 (例如,“更多信息”链接和“跳过”按钮、 (如果适用)。

IMA SDK 可能会报告广告是否被应用提供的视图遮挡 呈现在播放器之上应用需要叠加视图 必须在 IMA SDK 中注册它们,这样才能确保 则可以从可见度计算中省略以如下身份使用 PlayerView 时: AdViewProvider,则会自动注册其控件叠加层。应用 使用自定义播放器界面时,必须从 AdViewProvider.getAdOverlayInfos

有关叠加层视图的详细信息,请参阅 IMA SDK 中的 Open Measurement

随播广告

某些广告代码包含可在“广告位”中展示的其他随播广告以 应用界面。这些槽可通过 ImaAdsLoader.Builder.setCompanionAdSlots(slots)。如需了解详情,请参阅 添加随播广告

独立广告

IMA SDK 用于将广告插入媒体内容,而不是用于播放 独立的广告因此不支持播放独立广告 由 IMA 库决定。我们建议您改用 Google 移动广告 SDK 应用场景。

使用第三方广告 SDK

如果您需要通过第三方广告 SDK 加载广告,则有必要检查 它已经提供了 ExoPlayer 集成。如果不是,则实施自定义 建议您使用封装第三方广告 SDK 的 AdsLoader。 因为它具备上述 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(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)

Java

// 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 关于如何将广告加入播放列表的文档。

使用服务器端广告插播时,客户端可能需要解析媒体 动态网址以获取拼接的视频流,可能需要展示广告叠加层 或者可能需要向广告 SDK 或广告服务器报告事件。

ExoPlayer 的 DefaultMediaSourceFactory 可以将所有这些任务委托给 适用于使用 ssai:// 架构的 URI 的服务器端广告插播 MediaSource

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

ExoPlayer IMA 库

ExoPlayer IMA 库提供 ImaServerSideAdInsertionMediaSource, 可轻松集成 IMA 在服务器端插入的广告流, 应用。它包含适用于 Android 的 IMA DAI SDK 的功能, 将提供的广告元数据集成到播放器中。例如,这允许 您可以使用 Player.isPlayingAd() 等方法、监听内容-广告转换 并让播放器处理广告播放逻辑(例如跳过已播放的广告)。

要使用此类,您需要将 ImaServerSideAdInsertionMediaSource.AdsLoaderImaServerSideAdInsertionMediaSource.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 素材资源键,或内容来源 ID 和视频 ID 使用 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 集成。如果不是,建议您 提供接受具有 ssai:// 架构的 URI 的自定义 MediaSource 类似于 ImaServerSideAdInsertionMediaSource

创建广告结构的实际逻辑可委托给一般 用途 ServerSideAdInsertionMediaSource,用于封装数据流 MediaSource 并允许用户设置和更新表示广告的 AdPlaybackState 元数据。

通常,在服务器端插入的广告流会包含用于通知播放器的定时事件 广告元数据。请参阅支持的格式, ExoPlayer 支持定时元数据格式。自定义广告 SDK MediaSource 实现可以使用以下代码监听来自播放器的 Player.Listener.onMetadata