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

Pod Serving API 可让您访问自适应比特率的视频广告连播,这种广告连播采用的方式可以直接拼接到面向用户的 HLS 或 MPEG-DASH 媒体播放列表中。

本指南重点介绍如何为 VOD 数据流实现基本的 Pod Serving 清单操纵服务器。

接收数据流清单请求

您的清单操纵器必须提供一个 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

liveMPEG-DASH 配置文件 "urn:mpeg:dash:profile:isoff-live:2011" 相对应。

on-demandMPEG-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 这些广告连播播放列表处于有效状态的日期和时间(采用 ISO 8601 日期时间字符串,格式为 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 格式的流,则只需生成单个文件。这样可以让 DASH 视频流比 HLS 更易于拼接。

准备好的 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>

其他资源