用于 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 内容时长(以秒为单位)。

仅对包含使用 percentage 时间偏移的中贴片广告的 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 包含视频的“width”和“height”(以像素为单位)的 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 格式拼接视频流,则内容流将是一个多变体播放列表,其中包含指向单独的视频流清单的链接,每个编码配置文件对应一个。您的广告 Pod 需要插入到每个变体清单中。为了实现此目的,一种方法是准备所有变体清单,并将其传递给内容分发网络 (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>

其他资源