大多数浏览器和
Developer App 均支持流媒体播放。
-
探索 HLS 中的动态前置式贴片广告和插播广告
了解如何在广告和 HLS 流之间创建无缝过渡。我们将展示如何结合 HLS 标签和 AVFoundation API 来创建在您的主要内容和插播广告之间轻松移动的媒体体验,并提供在您的 app 中播放这些流的最佳实践。
资源
相关视频
WWDC22
WWDC21
-
下载
♪ ♪ 嗨 大家好 我是普拉尚 是AVFoundation的工程师 欢迎来到2021年的WWDC开发者大会 近几年蔚为风潮的 流媒体服务 应有尽有 几乎已经可以媲美传统线性电视 根据你所在的市场 你的使用者可能实际比较偏好 通过广告支持的免费内容 而非无广告的付费内容 所以如果你有兴趣加入广告 还有其他插入式广告 到你的HTTP实时流媒体上 你收看的正是合适的主题 在我们深入探讨之前 先回顾一下 一些已经存在的机制 让你能在HTTP实时流媒体上 插入广告 你可以执行服务器这边的广告插入 使用的是“不连续”的标签 这是个比较静态的方案 其中的广告片段 跟内容片段是结合在一起的 这个结合必须要提前做好 甚至在播放列表 贩卖给使用者之前就得完成 你可能会想象 这样的话便不允许 延迟绑定你的广告资产 你会希望广告取决于 用户接近广告标志的当下 甚至要重新绑定 比方说 有个使用者回去浏览 先前他们已经看过的片段 他们就会再次看到完全一样的广告 因为HTTP实时流媒体的运作 靠的是片段的粒度 从广告片段中切换回来 需要发生在片段边界 如果你的广告标志刚好在 内容片段的中间 你就得要分割这个片段 来将广告切进去 通常品质层的数量会不一样 你主要以及插入式广告的资产 会有所不同 为了要将广告接合 到所有主要的品质层上 广告需要被处理好 来配合内容的编码 你也会想确认这些广告使用 和主要内容一样的解码器 在实时流媒体的情境下 你的节目制作人可能 需要在后端进行很多簿记 你的广告与插入式广告 可能大部分会是 随选视频的流媒体 但节目制作人需要把它们安插好 以每一区块的基础 来让广告时段维持整体性 你也能从客户那端插入广告 目前为止 我们并没有官方推荐 以达成这种方式的作法 其中一个受欢迎的方式 是使用双播放器的方案 其中一个播放器呈现主要的内容 另一个则呈现插入式广告 而转换则通过切换回放达成 在两个播放器之间配合 并管理 使用者观看的阶层 虽然这样的作法效果很好 这里常出现的问题跟效能有关 若缓存没有适当地配合好 在两个播放器之间 先行提取你的广告会影响 自适应比特率的表现 在你主要内容的流媒体播放上 而有些功能 像是图片与隔空播放里的图片 会很难有好的表现 跟这些自定义播放器的 设计方式一起执行的话 今年我们处理了这些顾虑 大致上来说 企图让广告插入 更加简单许多 我们发布了HTTP实时流媒体的 插入式广告 广告可以用不同资产的方式处理 来安排到节目的时间轴上 广告再也不用使用 “不连续”的标签结合 而是保持自成一组的资产 可以从他们的主播放列表引用 我们很快就会看到 方案是动态的 允许延迟结合 甚至是重新结合到你的广告清单中 你不再被片段的边界限制住 你可以任意地把广告摆在任何地方 在节目的时间轴上 HTTP实时流媒体插入式广告 以及AVKit一起 为浏览限制提供了内建支持 在tvOS系统上 我们也内建支持隔空播放 以及图片中的图片 你所有排定的广告跟插入式广告会 在隔空播放的过程中存续 我们也配合了缓存 以及其他系统资源的使用 给主要或是插入式广告的播放器 以达到无缝衔接的目的 我们来瞧瞧典型的回放流 当我们播送随选视频的内容 还有使用HTTP实时流媒体 插入式广告技术的广告片段时
这张图里面的蓝色横条 就是你的主要内容 而绿色跟橘色的横条 则是你在回放里想安插的广告 现在主要内容会播放到广告标志为止 在这个点会暂停下来 然后第一个广告会开始播出 第一个广告播出后 第二个广告便会紧接着开始播放 在第二个广告之后 主要内容会重新开始 自刚刚停下的点开始 我们来看一下缓存的顺序 我们先由主要内容开始缓存 直到第一个广告开始的时间点 现在我们会预缓存第一个广告 让它有办法顺畅地转换 在它完全缓存完后 我们会预缓存第二个广告 在第二个广告完全缓存完后 我们会重新开始缓存主要内容 这样我们就能无缝切换回来 实时情境下的回放流也很相似 除了我们会重新加入主要内容 在广告时长后跳过去 如此我们跟现场播送的边缘才能同步 这也采用了一个相似的缓存策略 这样无缝衔接就有可能了 所以你要如何排定HTTP 实时流媒体的插入式广告呢? 你现在可以从服务器这边插入广告 使用DATERANGE的标签 为此我们加入了一个 全新的日期范围类别 拥有属性 这个播放列表带有时间的信息 使用的是 PROGRAM-DATE-TIME标签 这些标签现在是强制的 因为现在广告排程是用日期规定的 我们在这里看到一个 用DATERANGE标签排定的广告 类别设为com.apple.hls.interstitial ID属性和事件一对一重合 START-DATE是你希望广告 在主要时间轴开始的点 这边我们看到广告排程到 回放里的五秒 DURATION这个属性 规定了广告的时长 X-ASSET-URI这个属性 规定了统一资源标识符 属于广告的主播放列表 而X-RESUME-OFFSET这个属性 规定了偏移 是从START-DATE开始的 你会希望主要回放从这继续 重新开始偏移 设定为零代表的意思是 主要影片会从刚刚播到的地方继续 若重新开始偏移这个属性 没有加入的话 我们会重新加入主要影片 而它的偏移 会跟广告长度一样 这可能会是你想在现场 播出的情况下想做的
有时候你可能会希望 跳过串流中出现的广告 如同这里 想那么做 你只需要规定 重新开始偏移 让它跟串流中的广告一样长 你可以使用DATERANGE标签 来排程多个广告 我们看到这里排程的第一个广告 在主要影片五秒后开始 第二个则在十秒处 你可以排程连续的广告 只需要帮每一个规定 同一个开始时间即可 我们看到第一个广告开始在 回放的第五秒钟 第二个广告亦同 广告会照着顺序展示 跟播放列表里显示的一样 你使用X-ASSET-URI属性的这些方法 用以引用你的广告 会需要你 定义你的小群聚 当你加入 DATERANGE标签到播放列表时 但你可以延迟这个决定 只要你使用X-ASSET-LIST属性 X-ASSET-LIST指向一个JSON对象 里面含有事件的排程 对象拥有一个ASSETS数组 规定了 插入式广告的清单 每一个都规定了 主播放列表以及长度的 统一资源标识符 需要注意 提取这个JSON 只会发生在缓存的时候 让你的广告清单可以延后结合 通常广告会完整播完 然而 你可以规定一个结束时间 给你的广告 使用的是X-PLAYOUT-LIMIT属性 你可以使用这个属性去执行 提前返回 在现场广播的时候 提早返回的意思是你想中断 你的广告时间 来回到现场直播 可能的原因包含突发新闻的状况 或者是体育场上 突然有刺激精彩的时刻 你不希望你的观众错过了 那么你要如何执行提早返回呢? 这里我们可以看到一个 现场直播的播放列表 共有六个分段 现场演出的边界在分段六的最后面 播放头现在通常会是 在现场边缘后面的三个目标时长 以这个例子来说 它在第三段的最后面 在这个点有一个15秒的广告片段 被决定接着第六段 所以播放列表更新 其实包含了全部六个段落 还有DATERANGE标签 带有广告排程 在下次更新中 播放头会移到 第四段的最后面 广告仍然排程来接续第六段 这边暗色的第七段只是表示广告时段 再下一次更新播放头移到 第五段的最后面 下次更新 我们就来到了广告时段的开头 如果你什么都不做 广告会播放15秒 但若你想排程提早返回 例如12秒后就要切掉 你只需要规定 播放的时间限制就会是这么长 现在你的广告会播放12秒 在回到节目之前 通常由于合约的关系 你会想防止你的用户 完全跳过或提早略过广告 你可以规定浏览限制 只要使用X-RESTRICT这个标签就好了 X-RESTRICT的值为跳跃 能够防止使用者转到 广告的某个时间点之前与之后观看 X-RESTRICT的值为跳过 能够防止 使用者使用预设 偏好速率以外的设定播放广告 注意这些限制 都是由用户界面执行的 在tvOS上是由AVKit执行的 他们都可以任意使用 如果你用 AVPlayer观看控制器 来进行影片的播送 如果你用的是其他的平台 或是没有使用AVKit 这取决于你用的是哪种程序 来执行这些限制 我们既然看到你如何来排程 服务器端的广告 使用的是DATERANGE的标签 我们来看看你要如何 监测客户端这里的进展 因此我们要介绍两个 新的AVFoundation对象 AVPlayer插入式广告事件监测器 它会通知客户端 当一个插入式广告 已列入排程或是正在播放 而AVPlayer插入式广告事件的对象 包含了所有必要的信息 来安插广告到播放者项目的时间轴中 AVPlayer插入式广告事件监测器 有以下几项特点 一个主要播放器 正在播放你的主要资产 插入式广告的处置 你可以用来监测广告的回放 一个事件数组 这个数组里 都是AVPlayer插入式 广告事件的对象 代表了 播放器上不同的插入式广告集合 我们很快就会解释 什么是AVPlayer插入式广告事件 currentEvent的处置 当插入式广告播放时会有效 其他时候则无效 然后我们会有 eventsDidChangeNotification 只要事件排程改变就会发出 最后则是 CurrentEvent-DidChangeNotification 会在我们转换 到插入式广告及回来的时候发出 AVPlayer插入式广告事件对象描述 一个插入式广告事件会拥有性质 基本上就是 我们之前看到 DATERANGE属性的类比 primaryItem代表了你的主要资产 在它的时间轴上 你想要进行插入式广告的排程 标识符很类似于ID属性 就只有它会跟事件重合 时间及日期字段中规定了开始时间 分别写出来媒体中 插入式广告的时间与日期 也就像START-DATE的属性 我们会使用模板项目的拷贝来建立 插入式广告播放项目 能代表你的广告小群聚 这跟ASSET-LIST属性很相似 我们先前看到过了 限制性质会规定 你插入式广告的浏览限制 之后我们会有resumptionOffset 以及playoutLimit性质 类似于 他们在DATERANGE的对等部分 接下来我们终于有了 userDefinedAttributes的字典 你便可以规定自定义属性了 在DATERANGE标签中 这些会呈现在你的客户端应用程序里 通过userDefinedAttributes性质来表示 例如说你会包含一个信标路径 以及其他自定义属性 来回报广告回放的数据 这里有些范例代码 告诉你可以怎么使用 这些API来更新你的用户界面 当插入式广告正在播放的时候 你建立了一个AVPlayer 来播放你的主要内容 因此这个内容已经 把插入式广告排程好了 用的是DATERANGE的标签 接着再建立一个 AVPlayer插入式广告事件监测器 把它设置在播放器上 你接着再订阅 currentEvent-DidChangeNotification 来通知你的应用程序 当播放器转换到 插入式广告 或是退出的时候 而当通知发出时 你便会更新用户界面 有时候你会想排程广告 在客户端 我们为此介绍 AVPlayer插入式广告事件控制器 会让你依节目次序 在AVPlayer上设定事件 这个对象的来源是 AVPlayer插入式广告事件监测器 有许多的共同性质 有件事需要注意 当事件性质在监测器上为只读时 在控制器上它是可读可写的 让你能够依节目次序排程事件 它也有cancelCurrentEvent的API 让你能取消 现在正在播放的插入式广告 在这个范例里 我们看到操作者可以排程 一个广告小群聚到AVPlayer上 里面有两个广告 你创立AVPlayer来播放你的主要资产 之后再建立一个 AVPlayer插入式广告事件控制器 设置在AVPlayer上 你建立了AVPlayer项目的一个数组 能代表你的广告小群聚 接着建立AVPlayerInterstitialEvent 对象 你用来规定 primaryItem为播放器目前的项目 这个代表了你的电影资产 这个例子中的开始时间 是回放开始后大约十秒钟 而templateItems则是广告片段 是我们刚刚建立的 在对象建立之后 你只要把它设置 到控制器的事件性质上 你可能注意到了 在我们设定 播放器到AVPlayer观看控制器之前 我们设定currentItem.translates- PlayerInterstitialEvents这个性质为真 设立完成后AVKit 会订出浏览标志 到时间轴上 也会在tvOS上 执行浏览限制 我们现在来看看示范 我们会从AVKit整合 tvOS的HTTP实时流媒体 插入式广告开始
这边我们有个广告排程要开始 在回放大概进行40秒后开始 这个广告没有浏览限制的设定 你可以看到时间线上 广告标志是可见的
当广告在播放时 倒数计时的计时器出现 就在播放头上 因为这个广告没有限制设定 当我的手滑到边缘的时候 用Apple TV遥控器操作 我就会有跳过的选项 这么做就会让我们跳出广告 回到主要内容上 而这一个我们的设定也一样 但这个广告有跳过限制的设定
所以当广告播放时 你不会看到跳过广告的选项 你必须要等到它完全播完 才能回到主要内容 汤姆汉克斯在《灰猎犬号》 分级为PG-13 Apple TV+独家放映 感谢你 乔许 这里有两个广告 我们可以在时间轴上看到 第一个没有浏览限制 第二个则有跳过限制 所以当我们企图要跳过 这两个广告的时候
我们看到播放头跳了一下 到限制的广告标志上 广告则正在播出
我们从天上带来地狱
汤姆汉克斯在《灰猎犬号》 分级为PG-13 Apple TV+独家放映 当广告播放完后 我们会从寻觅位置继续播放
总结一下 你现在可以排程 服务器端的广告 使用的是DATERANGE标签 你会想把重新开始偏移规定为0 给随选视频串流 这样你就能重新 从节目里刚刚停下的地方继续 在直播串流的时候 你会跳过这个属性 这样我们就能从现场边缘重新进入 你可以使用X-ASSET-LIST属性 来延迟结合 你的广告资产 在直播放映时排程提早返回 使用的是X-PLAYOUT-LIMIT的属性 规定你的浏览限制 则是用X-RESTRICT属性 监测客户端的广告回放 你会使用 AVPlayer插入式广告事件监测器 你可以依节目次序安排广告 使用的是 AVPlayer插入式广告事件控制器 感谢你的收看 祝你收看WWDC其他内容愉快
-
-
9:50 - AVPlayerInterstitialEvent
class AVPlayerInterstitialEvent { var primaryItem: AVPlayerItem? { get } var identifier: String { get } var time: CMTime { get } var date: Date? { get } var templateItems: [AVPlayerItem] { get } var restrictions: AVPlayerInterstitialEvent.Restrictions { get } var resumptionOffset: CMTime { get } var playoutLimit: CMTime { get } var userDefinedAttributes: [AnyHashable : Any] { get } }
-
10:58 - Observing server inserted events
// Client observes server-side interstitial playback let player = AVPlayer(url: movieURL) // movieURL has EXT-X-DATERANGE ad tags let observer = AVPlayerInterstitialEventMonitor(primaryPlayer: player) NotificationCenter.default.addObserver( forName: AVPlayerInterstitialEventMonitor.currentEventDidChangeNotification, object: observer, queue: OperationQueue.main) { notification_ in self.updateUI(observer.currentEvent, observer.interstitialPlayer) }
-
11:40 - AVPlayerInterstitialEventController
class AVPlayerInterstitialEventController : AVPlayerInterstitialEventMonitor { var events: [AVPlayerInterstitialEvent]! func cancelCurrentEvent(withResumptionOffset resumptionOffset: CMTime) }
-
12:01 - Client schedules ad pod
// Client inserted events // Client schedules an ad pod at 10s into primary asset let player = AVPlayer(url: movieURL) // no ads in primary asset let controller = AVPlayerInterstitialEventController(primaryPlayer: player) let adPodTemplates = [AVPlayerItem(url: ad1URL), AVPlayerItem(url: ad2URL)] let event = AVPlayerInterstitialEvent( primaryItem: player.currentItem, time: CMTime(seconds: 10, preferredTimescale: 1), templateItems: adPodTemplates, restrictions: [], resumptionOffset: .zero, playoutLimit: .invalid) controller.events = [event] player.currentItem.translatesPlayerInterstitialEvents = true let vc = AVPlayerViewController() vc.player = player player.play()
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。