开始使用 IMA DAI SDK

借助 IMA SDK,您可以轻松地将多媒体广告集成到您的网站和应用中。IMA SDK 可以从任何 符合 VAST 标准的广告服务器请求广告,并在您的应用中管理广告播放。借助 IMA DAI SDK,应用可针对广告和内容视频(无论是 VOD 还是直播内容)发出流请求。然后,SDK 会返回一个组合的视频流,这样您就不必在应用内管理广告和内容视频之间的切换了。

选择您感兴趣的 DAI 解决方案

Pod 投放 DAI

本指南将演示如何使用适用于 HTML5 的 IMA DAI SDK 和依赖 hls.js 进行播放的视频播放器来播放用于直播或 VOD 内容的 DAI Pod Serving 流。如果您想要查看或了解已完成的示例集成,并支持 HLS.js 和 Safari Playback,请参阅 HLS Pod 投放示例。如需了解 DASH.js 支持,请参阅 DASH pod 投放示例。 您可以从 HTML5 DAI GitHub 版本页面下载这些示例应用。

DAI Pod Serving 概览

使用 IMA DAI SDK 实现 Pod 投放涉及两个主要组件,本指南对此进行了演示:

  • PodStreamRequest/PodVodStreamRequest:一个对象,用于定义对 Google 广告服务器的流请求。请求会指定网络代码,而 PodStreamRequest 还需要自定义资源密钥和可选的 API 密钥。两者都包含其他可选参数。

  • StreamManager:用于处理视频流与 IMA DAI SDK 之间的通信(例如触发跟踪 ping 和将视频流事件转发给发布商)的对象。

前提条件

在开始之前,您需要做好以下准备:

  • 三个空文件:

    • dai.html
    • dai.css
    • dai.js
  • 要用于测试的计算机、网络服务器或其他托管开发环境中安装的 Python

配置开发环境

由于 SDK 加载依赖项所用的协议与其加载页面所用的协议相同,因此您需要使用网络服务器来测试应用。启动本地开发服务器的最简单方法是使用 Python 的内置服务器。

  1. 从包含 index.html 文件的目录中,使用命令行运行以下命令:

    python -m http.server 8000
    
  2. 在网络浏览器中,前往 http://localhost:8000/

    您也可以使用任何其他托管的开发环境或 Web 服务器,例如 Apache HTTP Server

创建简单的视频播放器

首先,修改 dai.html 以创建简单的 HTML5 视频元素和一个用于广告界面元素的 div。另外,添加必要的标记来加载 dai.cssdai.js 文件,以及导入 hls.js 视频播放器。

然后,修改 dai.css 以指定页面元素的大小和位置。最后,在 dai.js 中,定义用于保存流请求信息的变量以及要在网页加载时运行的 initPlayer() 函数。

流请求常量如下所示:

  • BACKUP_STREAM:在广告进程遇到严重错误时要播放的备用视频流的网址。

  • STREAM_URL仅用于直播。您的清单操纵器或第三方合作伙伴使用 Pod 传送提供的视频流网址。在发出请求之前,您应插入由 IMA DAI SDK 提供的视频流 ID。在这种情况下,流网址包含一个占位符 [[STREAMID]],它会在发出请求之前替换为数据流 ID。

  • NETWORK_CODE:您的 Ad Manager 360 帐号的广告联盟代码。

  • CUSTOM_ASSET_KEY仅用于直播。自定义素材资源键,用于标识 Ad Manager 360 中的 Pod 投放事件。这可以由您的清单操纵器或第三方 Pod 投放合作伙伴创建。

  • API_KEY仅用于直播。(可选)从 IMA DAI SDK 检索视频流 ID 时需要使用的 API 密钥。

dai.html

<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script src="dai.js"></script>
  <link rel="stylesheet" href="dai.css" type="text/css">
</head>
<body onLoad="initPlayer()">
  <h2>IMA DAI SDK Demo (HLS.JS)</h2>
    <video id="video"></video>
    <div id="ad-ui"></div>
</body>
</html>

dai.css

#video,
#ad-ui {
  width: 640px;
  height: 360px;
  position: absolute;
  top: 35px;
  left: 0;
}

#ad-ui {
  cursor: pointer;
}

dai.js

var BACKUP_STREAM =
    'https://storage.googleapis.com/interactive-media-ads/media/bbb.m3u8'

// Stream Config.
const STREAM_URL = "https://encodersim.sandbox.google.com/masterPlaylist/...&stream_id=[[STREAMID]]";
const NETWORK_CODE = "51636543";
const CUSTOM_ASSET_KEY = "google-sample";
const API_KEY = "";

var hls = new Hls(); // hls.js video player
var videoElement;
var adUiElement;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
}

加载 IMA DAI SDK

接下来,使用 dai.html 中的脚本标记添加 DAI 框架(位于 dai.js 标记之前)。

dai.html

<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script type="text/javascript" src="//imasdk.googleapis.com/js/sdkloader/ima3_dai.js"></script>
  <script src="dai.js"></script>
  <link rel="stylesheet" href="dai.css" type="text/css">
</head>
...

初始化 StreamManager 并发出直播或 VOD 视频流请求

直播广告连播投放

为了请求一组广告,请创建一个 ima.dai.api.StreamManager,它负责请求和管理 DAI 流。构造函数采用视频元素,生成的实例采用广告界面元素来处理广告互动。

然后,定义一个函数来请求投放 Pod 直播。此函数首先创建一个 PodStreamRequest,使用第 2 步中提供的 streamRequest 参数对其进行配置,然后使用该请求对象调用 streamManager.requestStream()

dai.js

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement)

  requestLivePodStream(NETWORK_CODE, CUSTOM_ASSET_KEY, API_KEY);
}

function requestLivePodStream(networkCode, customAssetKey, apiKey) {
  // clear HLS.js instance, if in use
  if (hls) {
    hls.destroy();
  }

  // Generate a Pod Serving live Stream Request
  const streamRequest = new google.ima.dai.api.PodStreamRequest();
  streamRequest.networkCode = networkCode;
  streamRequest.customAssetKey = customAssetKey;
  streamRequest.apiKey = apiKey;
  streamRequest.format = 'hls';
  streamManager.requestStream(streamRequest);
}

VOD 广告连播投放

为了请求一组广告,请创建一个 ima.dai.api.StreamManager,它负责请求和管理 DAI 流。构造函数采用视频元素,生成的实例采用广告界面元素来处理广告互动。

然后,定义一个函数来请求投放广告连播 VOD 视频流。此函数首先创建一个 PodVodStreamRequest,使用第 2 步中提供的 streamRequest 参数对其进行配置,然后使用该请求对象调用 streamManager.requestStream()

dai.js

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement)

  requestVodPodStream(NETWORK_CODE);
}

function requestVodPodStream(networkCode) {
  // clear HLS.js instance, if in use
  if (hls) {
    hls.destroy();
  }

  // Generate a Pod Serving VOD Stream Request
  const streamRequest = new google.ima.dai.api.PodVodStreamRequest();
  streamRequest.networkCode = networkCode;
  streamRequest.format = 'hls';
  streamManager.requestStream(streamRequest);
}

处理数据流事件

直播广告连播投放

接下来,为主要视频事件实现事件监听器。此示例通过调用 onStreamEvent() 函数来处理 STREAM_INITIALIZEDERRORAD_BREAK_STARTEDAD_BREAK_ENDED 事件。此函数可以处理流加载和错误,以及在广告播放时停用播放器控件(此 SDK 要求)。加载流后,视频播放器会使用 loadStream() 函数加载并播放提供的网址。

dai.js

var isAdBreak;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
  
  streamManager.addEventListener(
    [google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
    google.ima.dai.api.StreamEvent.Type.ERROR,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED],
    onStreamEvent,
    false);
...
function onStreamEvent(e) {
  switch (e.type) {
    case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED:
      console.log('Stream initialized');
      loadStream(e.getStreamData().streamId);
      break;
    case google.ima.dai.api.StreamEvent.Type.ERROR:
      console.log('Error loading stream, playing backup stream.' + e);
      loadStream('');
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
      console.log('Ad Break Started');
      isAdBreak = true;
      videoElement.controls = false;
      adUiElement.style.display = 'block';
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
      console.log('Ad Break Ended');
      isAdBreak = false;
      videoElement.controls = true;
      adUiElement.style.display = 'none';
      break;
    default:
      break;
  }
}

function loadStream(streamID) {
  var url;
  if(streamID) {
    url = STREAM_URL.replace('[[STREAMID]]', streamID);
  } else {
    console.log('Stream Initialization Failed');
    url = BACKUP_STREAM;
  }
  console.log('Loading:' + url);
  hls.loadSource(url);
  hls.attachMedia(videoElement);
}

VOD 广告连播投放

接下来,为主要视频事件实现事件监听器。此示例通过调用 onStreamEvent() 函数来处理 STREAM_INITIALIZEDLOADEDERRORAD_BREAK_STARTEDAD_BREAK_ENDED 事件。此函数可以处理流加载和错误,以及在广告播放时停用播放器控件(SDK 要求)。

此外,VOD Pod 投放流需要调用 StreamManager.loadStreamMetadata() 来响应 STREAM_INITIALIZED 事件。您还需要向视频技术合作伙伴 (VTP) 请求流网址。loadStreamMetadata() 调用成功后会触发 LOADED 事件,您应在其中使用流网址调用 loadStream() 函数来加载和播放流。

var isAdBreak;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
  
  streamManager.addEventListener(
    [google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
    google.ima.dai.api.StreamEvent.Type.ERROR,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED],
    onStreamEvent,
    false);
...
function onStreamEvent(e) {
  switch (e.type) {
    case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED:
      const streamId = e.getStreamData().streamId;
      // 'vtpInterface' is a place holder for your own video technology
      //  partner (VTP) API calls.
      vtpInterface.requestStreamURL({
        'streamId': streamId,
      })
      .then( (vtpStreamUrl) => {
        streamUrl = vtpStreamUrl;
        streamManager.loadStreamMetadata();
      }, (error) => {
        // Handle the error.
      });
      break;
    case google.ima.dai.api.StreamEvent.Type.LOADED:
      loadStream(streamUrl);
      break;
    case google.ima.dai.api.StreamEvent.Type.ERROR:
      console.log('Error loading stream, playing backup stream.' + e);
      loadStream();
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
      console.log('Ad Break Started');
      isAdBreak = true;
      videoElement.controls = false;
      adUiElement.style.display = 'block';
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
      console.log('Ad Break Ended');
      isAdBreak = false;
      videoElement.controls = true;
      adUiElement.style.display = 'none';
      break;
    default:
      break;
  }
}

function loadStream(url) {
  if(url) {
    console.log('Loading:' + url);
    hls.loadSource(url);
  } else {
    console.log('Stream Initialization Failed');
    hls.loadSource(BACKUP_STREAM);
  }
  hls.attachMedia(videoElement);
}

处理数据流元数据

在此步骤中,您将为元数据实现事件监听器,以便在发生广告事件时通知 SDK。监听插播视频元数据事件可能会因视频流格式(HLS 或 DASH)、视频流类型(直播或 VOD 视频流)、您的播放器类型和所使用的 DAI 后端类型而异。如需了解详情,请参阅我们的定时元数据指南。

HLS 视频流格式(直播和 VOD 视频流,HLS.js 播放器)

如果您使用的是 HLS.js 播放器,请监听 HLS.js FRAG_PARSING_METADATA 事件以获取 ID3 元数据,并使用 StreamManager.processMetadata() 将其传递给 SDK。

如需在所有内容加载完毕并就绪后自动播放视频,请监听 HLS.js MANIFEST_PARSED 事件以触发播放。

function loadStream(streamID) {
  hls.loadSource(url);
  hls.attachMedia(videoElement);
  
  // Timed metadata is passed HLS stream events to the streamManager.
  hls.on(Hls.Events.FRAG_PARSING_METADATA, parseID3Events);
  hls.on(Hls.Events.MANIFEST_PARSED, startPlayback);
}

function parseID3Events(event, data) {
  if (streamManager && data) {
    // For each ID3 tag in the metadata, pass in the type - ID3, the
    // tag data (a byte array), and the presentation timestamp (PTS).
    data.samples.forEach((sample) => {
      streamManager.processMetadata('ID3', sample.data, sample.pts);
    });
  }
}

function startPlayback() {
  console.log('Video Play');
  videoElement.play();
}

DASH.js(DASH 视频流格式,直播和 VOD 视频流类型)

如果您使用的是 DASH.js 播放器,则必须使用不同的字符串来监听直播或 VOD 视频流的 ID3 元数据:

  • 直播数:'https://developer.apple.com/streaming/emsg-id3'
  • VOD 视频流:'urn:google:dai:2018'

使用 StreamManager.processMetadata() 将 ID3 元数据传递给 SDK。

如需在所有内容加载完毕并准备就绪后自动显示视频控件,请监听 DASH.js MANIFEST_LOADED 事件。

const googleLiveSchema = 'https://developer.apple.com/streaming/emsg-id3';
const googleVodSchema = 'urn:google:dai:2018';
dashPlayer.on(googleLiveSchema, processMetadata);
dashPlayer.on(googleVodSchema, processMetadata);
dashPlayer.on(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);

function processMetadata(metadataEvent) {
  const messageData = metadataEvent.event.messageData;
  const timestamp = metadataEvent.event.calculatedPresentationTime;

  // Use StreamManager.processMetadata() if your video player provides raw
  // ID3 tags, as with dash.js.
  streamManager.processMetadata('ID3', messageData, timestamp);
}

function loadlistener() {
  showControls();

  // This listener must be removed, otherwise it triggers as addional
  // manifests are loaded. The manifest is loaded once for the content,
  // but additional manifests are loaded for upcoming ad breaks.
  dashPlayer.off(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);
}

具有直播活动的 Shaka 播放器(DASH 流格式)

如果您使用 Shaka 播放器进行直播播放,请使用字符串 'emsg' 监听元数据事件。然后,在对 StreamManager.onTimedMetadata() 的调用中使用事件消息数据。

shakaPlayer.addEventListener('emsg', (event) => onEmsgEvent(event));

function onEmsgEvent(metadataEvent) {
  // Use StreamManager.onTimedMetadata() if your video player provides
  // processed metadata, as with Shaka player livestreams.
  streamManager.onTimedMetadata({'TXXX': metadataEvent.detail.messageData});
}

具有 VOD 视频流的 Shaka 播放器(DASH 视频流格式)

如果您使用 Shaka 播放器进行 VOD 流播放,请使用字符串 'timelineregionenter' 监听元数据事件。然后,在对 StreamManager.processMetadata() 的调用中使用带有字符串 'urn:google:dai:2018' 的事件消息数据。

shakaPlayer.addEventListener('timelineregionenter', (event) => onTimelineEvent(event));

function onTimelineEvent(metadataEvent) {
  const detail = metadataEvent.detail;
  if ( detail.eventElement.attributes &&
       detail.eventElement.attributes['messageData'] &&
       detail.eventElement.attributes['messageData'].value ) {
        const mediaId = detail.eventElement.attributes['messageData'].value;
        const pts = detail.startTime;
        // Use StreamManager.processMetadata() if your video player provides raw
        // ID3 tags, as with Shaka player VOD streams.
        streamManager.processMetadata('urn:google:dai:2018', mediaId, pts);
       }
}

处理播放器事件

向视频元素的 pausestart 事件添加事件监听器,以便用户在 SDK 在广告插播期间暂停时继续播放。

function loadStream(streamUrl) {
  ...
  
  videoElement.addEventListener('pause', onStreamPause);
  videoElement.addEventListener('play', onStreamPlay);
}

function onStreamPause() {
  console.log('paused');
  if (isAdBreak) {
    videoElement.controls = true;
    adUiElement.style.display = 'none';
  }
}

function onStreamPlay() {
  console.log('played');
  if (isAdBreak) {
    videoElement.controls = false;
    adUiElement.style.display = 'block';
  }
}

大功告成!现在,您正使用 HTML5 版 IMA DAI SDK 请求在广告连播投放流中展示广告并展示广告。如需详细了解高级 SDK 功能,请参阅其他指南或 GitHub 上的示例