借助 IMA SDK,您可以轻松将多媒体广告集成到您的网站和应用中。IMA SDK 可以从任何 与 VAST 兼容的广告服务器请求广告,并管理应用中的广告播放。借助 IMA DAI SDK,应用可以针对广告和内容视频(VOD 或直播内容)发出流式传输请求。然后,SDK 会返回一个合并的视频串流,这样您就不必在应用中管理广告视频和内容视频之间的切换。
选择您感兴趣的 DAI 解决方案
Pod Serving DAI
本指南演示了如何将 IMA DAI SDK for HTML5 与依赖于 hls.js 进行播放的视频播放器搭配使用,以播放直播或视频点播内容的 DAI Pod Serving 直播。如需查看或遵循已完成的示例集成(同时支持 HLS.js 和 Safari 播放),请参阅 HLS Pod 服务示例。如需了解 DASH.js 支持,请参阅 DASH Pod 服务示例。 您可以从 HTML5 DAI GitHub 版本页面下载这些示例应用。
DAI Pod Serving 概览
使用 IMA DAI SDK 实现 pod 投放涉及两个主要组件,本指南将对此进行演示:
PodStreamRequest
/PodVodStreamRequest
:用于定义对 Google 广告服务器的串流请求的对象。请求指定 Network Code,PodStreamRequest
还需要 Custom Asset Key 和可选的 API key。这两种方法都包含其他可选参数。StreamManager
:用于处理视频串流与 IMA DAI SDK 之间的通信的对象,例如触发跟踪 ping 和将串流事件转发给发布商。
前提条件
在开始之前,您需要做好以下准备:
三个空文件:
- dai.html
- dai.css
- dai.js
在用于测试的计算机或网络服务器或其他托管开发环境上安装 Python
配置开发环境
由于 SDK 加载依赖项时会使用与其加载时所在网页所用的协议相同的协议,因此您需要使用网络服务器来测试应用。要启动本地开发服务器,最快捷的方法是使用 Python 的内置服务器。
在您的
index.html
文件所在的目录下使用命令行运行以下命令:python -m http.server 8000
在网络浏览器中,前往
http://localhost:8000/
您也可以使用任何其他托管式开发环境或 Web 服务器,例如 Apache HTTP Server。
创建视频播放器
首先,修改 dai.html,以创建一个 HTML5 视频元素和一个用于广告界面元素的 div。此外,还要添加必要的标记来加载 dai.css 和 dai.js 文件,以及导入 hls.js
视频播放器。
然后,修改 dai.css 以指定页面元素的大小和位置。最后,在 dai.js 中,定义用于存储数据流请求信息的变量,以及在页面加载时运行的 initPlayer()
函数。
串流请求常量如下:
BACKUP_STREAM
:备用直播的网址,用于在广告进程遇到严重错误时播放。STREAM_URL
:仅适用于直播。您的清单操纵工具或使用广告连播投放的第三方合作伙伴提供的视频串流网址。您需要先插入 IMA DAI SDK 提供的直播 ID,然后才能发出请求。在本例中,数据流网址包含占位符[[STREAMID]]
,系统会在发出请求之前将其替换为数据流 ID。NETWORK_CODE
:您的 Ad Manager 360 账号的广告资源网代码。CUSTOM_ASSET_KEY
:仅适用于直播。用于在 Ad Manager 360 中标识广告连播投放事件的自定义素材资源键。此文件可以由您的清单操纵器或第三方广告连播服务合作伙伴创建。API_KEY
:仅适用于直播。可选 API 密钥,可能需要此密钥才能从 IMA DAI SDK 检索串流 ID。
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 并发出直播或视频点播流式传输请求
直播连播投放
如需请求一组广告,请创建一个 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 Pod Serving
如需请求一组广告,请创建 ima.dai.api.StreamManager
,该类负责请求和管理 DAI 数据流。该构造函数接受一个视频元素,生成的实例接受一个广告界面元素来处理广告互动。
然后,定义一个函数来请求 Pod 传送 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_INITIALIZED
、ERROR
、AD_BREAK_STARTED
和 AD_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 Pod Serving
接下来,为主要视频事件实现事件监听器。此示例通过调用 onStreamEvent()
函数来处理 STREAM_INITIALIZED
、LOADED
、ERROR
、AD_BREAK_STARTED
和 AD_BREAK_ENDED
事件。此函数会处理流加载和错误,以及在广告播放时停用播放器控件(这是 SDK 的要求)。
此外,VOD 文件包提取串流需要调用 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 在线播放格式(直播和视频点播在线播放、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 Player(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 Player(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);
}
}
处理播放器事件
将事件监听器添加到视频元素的 pause
和 start
事件,以便在 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';
}
}
清理 IMA DAI 素材资源
使用 IMA DAI SDK 在广告连播中成功请求和展示广告后,我们建议您在广告连播会话结束后清理所有资源。调用 StreamManager.destroy()
可停止流式传输播放、停止所有广告跟踪,并释放所有已加载的流式传输资产。
如需了解更高级的 SDK 功能,请参阅其他指南或 GitHub 上的示例。