用于 VOD 视频流的清单操纵器

Pod Serving API 提供对自适应比特率视频广告连播的访问权限,这些广告连播以特定方式准备,可直接拼接到面向用户的 HLS 或 MPEG-DASH 媒体播放列表中。

本指南将重点介绍如何为 VOD 串流实现基本 Pod 服务清单操作服务器。

接收直播清单请求

您的清单操作程序必须提供一个 API 端点来监听来自视频播放器客户端应用的清单请求。此端点至少必须从客户端播放器应用收集一个串流 ID。此串流 ID 用于在广告连播请求中向 Ad Manager 标识串流会话。

您还需要收集一些其他信息,以便识别适当的内容串流,例如内容 ID。

清单请求端点示例

GET /api/stream_id/{stream_id}/video/{content_id}.{format}
Host: {your_domain}
路径参数
stream_id 客户端视频播放器应用中的 Ad Manager 串流 ID。
content_id 与您系统中的内容视频对应的假设 ID。
format 与数据流格式对应的假设参数。以下任一项:
mpd 对于 MPEG-DASH 串流
m3u8 对于 HLS 直播

检索内容流

使用从清单请求收集的内容 ID 选择要与广告拼接的内容串流。

请求广告连播清单

如需向 Ad Manager 请求广告,您的服务器必须向广告连播端点发出 POST 请求,并传递请求的编码配置文件和广告代码。此请求还包含您在第 1 步中收集的串流 ID。

作为回报,您会收到一个广告连播对象列表,其中包含发布商广告代码请求的广告连播的清单文件,以及应在何时何地将这些广告连播插入到您的内容中的信息。

POST /ondemand/pods/api/v1/network/{network_code}/streams/{stream_id}/adpods
Host: dai.google.com
Content-Type: application/json
路径参数
network_code 发布商的 Ad Manager 360 广告资源网代码。
stream_id 客户端视频播放器应用中的数据流 ID。

JSON 正文

身体参数
encoding_profiles Required 您希望为每个广告插播收到的编码配置文件的 JSON 表示形式的列表。请参阅以下详情

为了尽可能流畅地播放,此值应与内容串流中使用的一组编码配置文件相匹配。

ad_tag Required 用于请求 VMAP 广告的广告代码。
cuepoints Optional 内容流中将插入中贴片广告插播时间点的广告插入点列表。广告插入点以浮点秒为单位。

仅适用于包含使用位置时间偏移的插播广告的 VMAP 响应。这种情况并不常见。

content_duration_seconds Optional 内容时长(以秒为单位)。

仅适用于包含使用百分比时间偏移的插播广告的 VMAP 响应。这种情况并不常见。

manifest_type Optional 请求的广告串的格式,hlsdash。默认值为 hls
dai_options Optional 用于控制清单呈现方式的其他选项。 请参阅以下详情
编码配置文件
profile_name Required 此编码配置文件的标识符。此值可以是您选择的任何字符串,但您不能在同一直播中使用多个同名编码配置文件。
type Required 此编码配置文件所描述的串流的编码类型。内容类型包括:mediaiframesubtitles
container_type Required 此编码配置文件使用的容器格式。容器格式:mpeg2tsfmp4cmafhls_packed_audio
video_settings Optional 如果编码配置文件类型为 iframe,则为必填项。否则,仅当媒体类型包含视频时才允许。请参阅以下详情
audio_settings Optional 如果编码配置文件包含音频,则必须填写此字段。仅当类型为媒体时才允许。请参阅以下详情
subtitle_settings Optional 如果编码配置文件包含字幕,则必须填写。 请参阅以下详情
视频设置
codec Required RFC6381 编解码器字符串。

示例avc1.4d000c

bitrate Required 一个整数,表示此配置文件的视频码率上限(以字节/秒为单位)。
frames_per_second Required 视频的浮点 FPS。
resolution Required 一个 JSON 编码值,包含视频的“宽度”和“高度”(以像素为单位)。

示例{"width": 640, "height": 320}

音频设置
codec Required RFC6381 编解码器字符串。

示例mp4a.40.5

bitrate Required 一个整数,表示此配置文件的最大音频比特率(以每秒字节为单位)。

示例300000

channels Required 一个整数,表示音频声道数量(包括低频声道)。
sample_rate Required 一个整数,表示音频采样率(以赫兹为单位)。

示例4800

字幕设置
format Required 带内字幕使用的文件格式。支持的值为 webvttttml
language Optional 字幕语言,采用 RFC5646 语言字符串。如果提供,此值仅用于 DASH 渲染。

示例en-us

DAI 选项
dash_profile Optional 要应用于广告连播清单的 MPEG-DASH 配置文件。此设置仅适用于 DASH 清单。允许的值为 liveon-demand。默认值为 on-demand

live 对应于 MPEG-DASH 配置文件 "urn:mpeg:dash:profile:isoff-live:2011"

on-demand 对应于 MPEG-DASH 配置文件 urn:mpeg:dash:profile:isoff-on-demand:2011

ad_pod_timeout Optional 选择广告和制作广告连播的最长时间(以浮点秒为单位)。在该时间过后,Ad Manager 会在 ad_pods 响应中返回已选择的所有广告,并停止处理。
sam_id Optional 指定一个备用调试密钥,用于在视频流活动监控工具中查找会话。

响应

响应参数
valid_for 这些广告连播播放列表的有效时长(以 dhms 格式 [天、小时、分钟、秒]表示)。
valid_until 这些广告连播播放列表的有效截止日期和时间,采用 ISO8601 日期时间字符串,格式为 yyyy-MM-dd'T'hh:mm:ss.sssssssss[+|-]hh:mm
ad_pods 为此直播选择的广告连播列表。
广告连播
manifest_uris 仅适用于 HLS 串流。编码配置 ID 与 HLS 清单 URI 的映射。
mpd_uri 仅适用于 DASH 串流。DASH MPD 的 URI。
type 广告连播的类型。广告连播类型包括:premidpost
start 仅适用于中贴片广告连播。应将此广告连播插入直播中的位置(以浮点秒为单位)。
duration 此广告连播的时长(以浮点秒为单位)。
midroll_index 仅适用于中贴片广告连播。当前中贴片广告连播的索引。编入索引以 1 开头。

请求示例 (c网址)

curl -X POST \
     -d '@request-body.json' \
     -H 'Content-Type: application/json' \
  https://dai.google.com/ondemand/pods/api/v1/network/21775744923/streams/6e69425c-0ac5-43ef-b070-c5143ba68541:CHS/adpods

请求正文示例

这是上述 c网址 调用中引用的 request-body.json 的内容。

{
  "encoding_profiles": [
   {
     "profile_name": "1080p",
     "type": "media",
     "container_type": "mpeg2ts",
     "video_settings": {
       "codec": "avc1.4d000c",
       "bitrate": 5000000,
       "frames_per_second": 30.0,
       "resolution": {
         "width": 1920,
         "height": 1080
       }
     },
     "audio_settings": {
       "codec": "mp4a.40.5",
       "bitrate": 300000,
       "channels": 2,
       "sample_rate": 48000
     }
   },
   {
     "profile_name": "360p",
     "type": "media",
     "container_type": "mpeg2ts",
     "video_settings": {
       "codec": "avc1.4d000d",
       "bitrate": 1000000,
       "frames_per_second": 30.0,
       "resolution": {
         "width": 640,
         "height": 360
       }
     },
     "audio_settings": {
       "codec": "mp4a.40.5",
       "bitrate": 64000,
       "channels": 2,
       "sample_rate": 48000
     }
   },
   {
     "profile_name": "subtitles-webvtt",
     "type": "subtitles",
     "subtitle_settings": {
       "format": "webvtt"
     }
   }
 ],
 "ad_tag": "https://pubads.g.doubleclick.net/gampad/ads?...",
 "manifest_type": "hls"
}

示例响应

{
  "valid_for": "8h0m0s",
  "valid_until": "2023-03-24T08:30:26.839717986-07:00",
  "ad_pods": [
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/0/profile/1080p.m3u8",
        "360p": "https://{...}/pod/0/profile.m3u8",
        "subtitles-webvtt": "https://{...}/pod/0/profile/subtitles-en.vtt"
      },
      "type": "pre",
      "duration": 10.0
    },
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/1/profile/1080p.m3u8",
        "360p": "https://{...}/pod/1/profile.m3u8",
        "subtitles-webvtt": "https://{...}/pod/1/profile/subtitles-en.vtt"
      },
      "type": "mid",
      "start": 15.0,
      "duration": 15.0,
      "midroll_index": 1
    },
    {
      "manifest_urls":{
        ]"1080p": "https://{...}/pod/2/profile/1080p.m3u8",
        "360p": "https://{...}/pod/2/profile.m3u8",
        "subtitles-webvtt": "https://{...}/pod/0/profile/subtitles-en.vtt""
      },
      "type": "post",
      "duration": 10.0
    }
  ]
}

将广告连播插入内容中

将广告连播缝合到内容串流中的流程因您的实现方式、串流格式以及您选择从格式规范中实现的功能而异。以下工作流程是对如何处理此流程的建议。具体实现细节可能会因您的业务需求和内容串而异。

HLS 在线播放

如果您要拼接 HLS 格式的直播,则内容直播将是一个多变量播放列表,其中包含指向单独直播清单的链接,每个编码配置对应一个链接。您需要将广告连播插入到每个变体清单中。实现此目的的一种方法是准备所有变体清单,并将其传递给内容分发网络 (CDN) 进行托管。最终的多变体播放列表是指指向这些 CDN 托管的清单的一组链接。

迭代编码配置文件

对于每个编码配置文件,从 Ad Manager 的响应中收集所有关联的广告连播清单以及其关联的开始时间。对于前贴片广告连播,请将开始时间设置为 0。对于片尾广告,请将内容时长用作广告连播的开始时间。在多变体播放列表中,找出与每个编码配置的音频和视频设置匹配的变体串流。

广告连播数组示例
"ad_pods": [
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/0/profile/1080p.m3u8",
        "360p": "https://{...}/pod/0/profile/360p.m3u8",
        "subtitles-en": "https://{...}/pod/0/profile/subitles-en.vtt"
      },
      "type": "pre",
      "duration": 10.0
    },
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/1/profile/1080p.m3u8",
        "360p": "https://{...}/pod/1/profile/360p.m3u8",
        "subtitles-en": "https://{...}/pod/1/profile/subitles-en.vtt"
      },
      "type": "mid",
      "start": 15.0,
      "duration": 15.0,
      "midroll_index": 1
    },
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/2/profile/1080p.m3u8",
        "360p": "https://{...}/pod/2/profile/360p.m3u8",
        "subtitles-en": "https://{...}/pod/2/profile/subitles-en.vtt"
      },
      "type": "post",
      "duration": 10.0
    }
  ]
多变体内容播放列表示例
#EXTM3U
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs0",LANGUAGE="en",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="https://{...}/subitles-en.vtt"
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.4d000c,mp4a.40.5"
https://{...}/1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.4d000d,mp4a.40.5"
https://{...}/360p.m3u8
收集的变体数据示例
Encoding profile: "1080p"
Profile settings: {...}
Content manifest: https://{...}/1080p.m3u8
Ad pods (start time -> manifest):
    0 -> https://{...}/pod/0/profile/1080p.m3u8
   15 -> https://{...}/pod/1/profile/1080p.m3u8
  600 -> https://{...}/pod/2/profile/1080p.m3u8

将广告插入每个变体清单

对于每个变体串流,请浏览内容清单的片段,并记录已用内容时间的累计总和。当您到达广告连播的起始位置时,从广告连播的清单中提取细分列表,将细分列表封装在两个 #EXT-X-DISCONTINUITY 标记中,然后将列表插入内容清单的当前位置。继续执行此流程,直到处理完所有广告连播和变体串流。

生成的清单必须符合 HLS 标准。因此,根据您的内容清单包含的规范功能,您可能需要对合并后的清单进行最终传递,以修正媒体序列号、内容时长、中断序列号以及需要更新的任何其他标记,以考虑新的广告片段。修复与标准存在的任何差异后,将每个特定于用户的变体清单推送到您的 CDN 进行托管。

如果您的内容清单已加密,您需要将在当前广告连播开始前找到的最后一个加密密钥存储在 #EXT-X-KEY 标记中。然后,您需要在每个广告连播的第一个片段前添加标记 #EXT-X-KEY:METHOD=NONE 以移除加密。最后,您必须在每个广告连播后面的第一个内容片段之前添加存储的 #EXT-X-KEY 标记的副本,以恢复内容加密。

收集的变体数据示例
Encoding profile: "1080p"
Content manifest: https://{...}/1080p.m3u8
Ad pods (start time -> manifest):
    0 -> https://dai.google.com/{...}pod/0/profile/1080p.m3u8
   15 -> https://dai.google.com/{...}pod/1/profile/1080p.m3u8
  600 -> https://dai.google.com/{...}pod/2/profile/1080p.m3u8
内容清单示例

这是收集的款式/规格数据中列出的 https://{...}/1080p.m3u8 清单的内容。

#EXTM3U
{...}
#EXTINF:5.000,
https://{...}/1080p/content-segment-0.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-1.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-2.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-3.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-4.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-5.ts
{...}
广告连播清单示例

这是收集的款式/规格数据中列出的 https://dai.google.com/{...}/pod/1/profile/1080p.m3u8 清单的内容。

#EXTM3U
{...}
#EXTINF:5.000,
https://dai.google.com/{...}/0.ts
#EXTINF:5.000,
https://dai.google.com/{...}/1.ts
#EXTINF:5.000,
https://dai.google.com/{...}/2.ts
拼接变体清单示例

这将是最终的拼接变体清单,会传递给 CDN 并托管在 https://cdn.{...}/{userid}/1080p.m3u8 中。

#EXTM3U
{...}
#EXTINF:5.000,
https://{...}/1080p/content-segment-0.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-1.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
https://dai.google.com/{...}/0.ts
#EXTINF:5.000,
https://dai.google.com/{...}/1.ts
#EXTINF:5.000,
https://dai.google.com/{...}/2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
https://{...}/1080p/content-segment-3.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-4.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-5.ts
{...}

构建多变体播放列表

收集每个已完成的变体清单的 CDN 地址以及匹配的编码配置文件详细信息,并将结果组合成新的多变体清单。系统会将此特定于用户的清单作为对您在第 1 步中收到的清单请求的响应返回。

最终多变体播放列表示例
#EXTM3U
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs0",LANGUAGE="en",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="https://cdn.{...}-subitles-en.vtt"
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.4d000c,mp4a.40.5"
https://cdn.{...}/{userid}/1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.4d000d,mp4a.40.5"
https://cdn.{...}/{userid}/360p.m3u8

MPEG DASH 串流

如果您要拼接 MPEG DASH 格式的串流,则只需生成一个文件。与 HLS 相比,这可以让 DASH 串流更易于拼接。

正确准备的 MPEG DASH 媒体演示说明 (MPD) 文件应包含多个时段,每个时段包含多个表示法。每个表示法都应与您的某个编码配置文件相匹配。从 Ad Manager 返回的每个广告连播也是一个 MPD 文件,其中包含一系列具有匹配表示形式的时段。

如需将这些 MPD 文件拼接在一起,请先记下每个广告连播的开始时间。对于前贴片广告,请在任何内容时段之前插入前贴片广告连播时段。对于后贴片广告,请在所有内容时段后面插入后贴片广告连播时段。迭代内容 MPD 中的时段,跟踪所有已处理内容时段的经过播放时长。当您到达与广告连播的开始时间对应的时段边界时,请在此边界处插入匹配插播广告连播的 MPD 文件中的时段。

最终的拼接 MPD 文件必须完全符合 MPEG_DASH 规范,因此您可能需要对最终文件进行一次迭代,以更正所有时段的开始时间、修正媒体呈现时长以考虑新插入的广告时段,并解决可能因拼接过程而产生的任何其他冲突。

内容 MPD 示例

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" mediaPresentationDuration="PT0H10M00.000S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
  <ProgramInformation moreInformationURL="http://.../info">
    <Title>Example Stream</Title>
  </ProgramInformation>
  <Period duration="PT0H0M15.000S" id="content-period-1">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-2">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-3">
    ...
  </Period>
  ...
</MPD>

广告连播 JSON 示例

[{
  "mpd_uri": "https://{...}pod/1.mpd",
  "type": "mid",
  "start": 15.0,
  "duration": 15.0,
  "midroll_index": 1
}]

广告连播 MPD 示例

这是上方广告连播 JSON 中的 mpd_uri 内容。

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" mediaPresentationDuration="PT0H0M15.000S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
  <ProgramInformation moreInformationURL="http://.../info">
    <Title>Ad Pod 1</Title>
  </ProgramInformation>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-1">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-2">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-3">
    ...
  </Period>
  ...
</MPD>

拼接 MPD 示例

将其作为对初始数据流清单请求的响应提供。

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" mediaPresentationDuration="PT0H10M15.000S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
  <ProgramInformation moreInformationURL="http://.../info">
    <Title>Example Stream</Title>
  </ProgramInformation>
  <Period duration="PT0H0M15.000S" id="content-period-1">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-1">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-2">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-3">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-2">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-3">
    ...
  </Period>
  ...
</MPD>

其他资源