本指南介绍了在使用动态广告插播 (DAI) 播放视频点播 (VOD) 视频流时,如何使用 IMA DAI SDK 实现书签功能。 本指南假定您已实现 IMA DAI,例如 入门指南中介绍的实现。
什么是书签?
书签功能可用于保存内容流中的某个具体点,方便之后返回同一位置。假设用户观看了 5 分钟的内容,然后离开视频流,之后又返回该视频流。由于书签可保存用户在视频流中的位置,因此用户返回时便可从上次停下的位置继续观看,畅享流畅一致的体验。
DAI 书签功能揭秘
为 DAI 视频流添加书签时,您必须记录用户离开视频时的视频流 ID 和时间。当用户返回时,重新请求视频流并跳转到保存的时间。由于所请求视频流的每个实例的广告插播时长可能不同,因此仅保存视频流时间是行不通的。您真正想要做的是从相同的内容时间 继续观看。
转换方法来救场
IMA DAI SDK 提供了一对方法,用于请求给定视频流时间 的内容时间 ,以及给定内容时间 的视频流时间 。使用这些转换方法,您可以存储添加书签的内容时间 ,然后在视频流的新实例中跳转到相应的视频流时间 。下面介绍了具体方法,并提供了一个示例应用的链接,该应用展示了可正常运行的书签实现。
保存书签
当 Activity 暂停时,保存书签。
Objective-C
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.contentPlayer pause];
// Ignore this if we're presenting a modal view (e.g. in-app clickthrough).
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
// Don't save bookmark if we're playing a live stream.
if (self.video.streamType != StreamTypeLive) {
NSTimeInterval contentTime = [self.streamManager
contentTimeForStreamTime:CMTimeGetSeconds(self.contentPlayer.currentTime)];
[self.delegate videoViewController:self didReportSavedTime:contentTime forVideo:self.video];
}
Swift
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
contentPlayer.pause()
if isMovingFromParent {
// Only save bookmark if we're playing a VOD stream.
if let vodStream = stream as? VODStream, let streamManager = streamManager {
let contentTime = streamManager.contentTime(
forStreamTime: contentPlayer.currentTime().seconds)
if contentTime.isFinite, contentTime > 0 {
delegate?.videoViewController(self, didReportBookmarkedTime: contentTime, for: vodStream)
}
}
if trackingContent {
removeContentPlayerObservers()
}
streamManager?.destroy()
adsLoader?.contentComplete()
streamManager = nil
adsLoader = nil
}
}
加载书签
重新请求视频流时,加载书签。这是实现 VideoStreamPlayer 接口的一部分。
Objective-C
case kIMAAdEvent_STREAM_LOADED: {
if (self.video.streamType == StreamTypeVOD) {
[self addContentPlayerObservers];
if (self.video.savedTime > 0) {
NSTimeInterval streamTime =
[self.streamManager streamTimeForContentTime:self.video.savedTime];
[self.IMAVideoDisplay seekStreamToTime:streamTime];
self.video.savedTime = 0;
}
}
Swift
case .STREAM_LOADED:
guard let stream else { return }
addContentPlayerObservers()
if let vodStream = stream as? VODStream, vodStream.bookmarkTime > 0 {
bookmarkStreamTime = streamManager.streamTime(forContentTime: vodStream.bookmarkTime)
if let time = bookmarkStreamTime {
pendingBookmarkSeek = true
logMessage(
"STREAM_LOADED: Bookmark pending for contentTime: \(String(format: "%.2f", vodStream.bookmarkTime)) (streamTime: \(String(format: "%.2f", time)))"
)
vodStream.bookmarkTime = 0
}
}