是否可以使用 AVPlayer 缓存 HLS 段?

Posted

技术标签:

【中文标题】是否可以使用 AVPlayer 缓存 HLS 段?【英文标题】:Is it possible to cache HLS segments with AVPlayer? 【发布时间】:2015-06-08 16:34:46 【问题描述】:

根本问题​

ios 中搜索时,我们的视频会缓冲很多。它比我们的网络播放器缓冲更多,后者将已经观看的片段的副本保存在临时存储中。

​所需的解决方案​

在设备磁盘上本地缓存视频片段。我们可以缓存单个质量并始终重放它。

​拦截器​

我们找不到在 AVFoundation/AVPlayer 中执行缓存的方法。

我们的尝试

使用 AVPlayer 拦截网络请求的两种方法。

    遵守 AVAssetResourceLoaderDelegate 并手动处理媒体的加载

不适用于 HLS。您可以通过实现 AVAssetResourceLoaderDelegate 来加载 m3u8 文件,这允许您通过身份验证或解密响应,但是无法加载 .ts 文件。 这是我们尝试的代码: https://gist.github.com/nathanhillyer/84e46152d7c4c88183b6

    实现一个 NSURLProtocol 来捕获对.ts 文件的请求。

AVURLAsset 实际上避免了被拦截。不知何故,网络请求只是没有被捕获。 (不知道为什么)

【问题讨论】:

我正要实现一个 NSURLProtocol 来尝试缓存 .ts 文件。 @narohi - 你有没有想过这个?我也很想在磁盘上缓存 HLS 段。很高兴在我浪费时间之前发现它不起作用。现在我倾向于放弃AVPlayer,并通过解析m3u8 播放列表并使用AVQueuePlayer 来编写我自己的HLS 播放器。 JWPlayer SDK for iOS 看起来很有希望,但他们的“联系我们了解我们的年度合同定价”听起来有点吓人。 啊,看起来我们遵循了完全相同的教程,并最终出现在同一个地方。在我根据请求调用finishLoading() 后,我也收到了AVPlayerItemStatus.Failed,错误只是:The operation could not be completed 您可以代理 HLS 流 - 手动下载 ts 并将 m3u8 托管在设备上 (localhost/xxx.m3u8) @nathan.f77 我们目前正在制作使用 CocoaHTTPServer 代理流的原型,结果很有希望 我写了一个反向代理服务器来缓存 HLS 段并且它工作。我工作的公司刚刚将此解决方案开源:github.com/StyleShare/HLSCachingReverseProxyServer 【参考方案1】:

让我们从真正的好消息开始 - iOS 10 及更高版本 - 开箱即用。 很快就不再需要黑客了。更多详细信息可以在以下 WWDC16 会议中找到,了解 HTTP Live Streaming 中的新功能: https://developer.apple.com/videos/play/wwdc2016/504/

现在回到当前状态 - iOS 9 及更低版本: 使用 AVPlayer,没有。但是您可以通过本地 HTTP 服务器缓存 HLS 片段并使用 AVPlayer 播放本地流。

AVPlayer 和 AVAsset 在处理 HLS 播放时不包含必要的信息(例如,它的行为与 MP4 静态文件不同)。

TL;DR - 您需要使用 HTTP 请求来获取分段并使用本地 HTTP 服务器为它们提供服务。

一些公司,包括我工作的公司,正在使用这种策略。

使用连接以您想要的质量下载片段,重建清单并将其全部展平为一个目录和一种质量,然后使用应用程序内的本地 http 服务器将其提供给 AVPlayer(AVPlayer 只能播放 HLS通过 HTTP 提供的流 - 不是来自文件资产)。

存在一些边缘情况,例如,如果您想在一次运行中播放和下载,则进行缓冲,正确重建 m3u8 清单,以及读取磁盘时不同的 AVPlayer 状态。

我从第一手知识中发现了这一点,无论是在生产中使用了 5 年的这样一个系统,还是在 App Store 中使用相同解决方案的其他视频产品 - 总共为许多用户提供服务。

这也是我们为 android 找到的最佳解决方案。

【讨论】:

我很欣赏您的观点,我们确实代理了本地 HLS 流。原始问题“是否可以使用 AVPlayer 缓存 HLS 段?”但是,没有正确回答。答案是,但可以使用 本地HTTP 服务器缓存HLS 段。如果你更新你的答案,我会接受。 修改了答案:) 顺便说一句 - 确保为 HTTP 代理使用非标准端口,以避免与您使用相同机制分发的其他应用程序/其他应用程序发生冲突 :) 特别是如果您有一些后台权限。 很好的解决方案!这样,当应用在后台时,音乐/视频会继续运行(无休止)吗? @dubbelugh - 需要添加背景模式音频,它应该。我不得不说我还没有尝试过。我们不允许这样的后台播放(就像大多数视频应用一样),因此除了该注释之外没有任何见解。【参考方案2】:

实际上,我们可以让 AVPlayer 播放来自网络的视频,但是如果您想缓存下载的数据以在本地播放,现在使用 AVPlayer 似乎是不可能的。

幸运的是,有一个很棒的 AP​​I 是 AVURLAsset 中的 resourceLoader 对象,您可以通过它为 AVPlayer 提供对远程音频文件的受控访问。这就像本地 HTTP 代理一样工作,但没有所有麻烦。

你可以在https://gist.github.com/anonymous/83a93746d1ea52e9d23f找到更多细节

【讨论】:

谢谢洪。如原始问题所述,AVURLAsset 的资源加载器不会为 HLS 视频调用其委托,因此该解决方案将不起作用。 谢谢。在使用 AVURLAsset 的资源加载器方面,我没有仔细阅读您的问题,因为我认为它的代表不要求 HLS。目前,您是否有任何替代方法来解决这个问题? 是的,我们在本地运行 CocoaHTTPServer 并代理 HLS 流。我希望仅使用 AVPlayer 就可以做到这一点,但我们还没有找到解决方案。【参考方案3】:

从 iOS 10 开始,您可以使用AVFoundation 在用户设备上下载和存储 HLS 电影,同时用户可以访问快速、可靠的网络,以后无需网络连接即可观看。

AVAssetDownloadURLSession

这个wwdc2016/504/ session 谈论Offline HLS。它是关于使用AVAssetDownloadURLSession 下载和持久化资产的,它是URLSession 的子类,这里用于管理AVAssetDownloadTasks。本次会议中提到的 API 在 iOS10 之后可用。

AVAggregateAssetDownloadTask

wwdc2017/504 session 在 iOS11 中引入了AVAggregateAssetDownloadTask

一个 AVAssetDownloadTask 用于下载单个 AVAsset 的多个 AVMediaSelections,位于单个下载任务的保护伞下。

Apple 提供了使用AVFoundation 播放和Persist HTTP Live Streams 的示例项目。 Demo doc。演示项目使用AVAggregateAssetDownloadTask

AVAssetDownloadStorageManager

/wwdc2017/504 还引入了一个新的 API,AVAssetDownloadStorageManager,用于管理自动清除下载的AVAssets 的策略。

有效期 优先级(重要,默认)
// Get the singleton
let storageManager = AVAssetDownloadStorageManager.shared()
// Set the policy
let newPolicy = AVMutableAssetDownloadStorageManagementPolicy() 
newPolicy.expirationDate = myExpiryDate
newPolicy.priority = .important 
storageManager.setStorageManagementPolicy(newPolicy, forURL: myDownloadStorageURL)
Working with HTTP Live Streaming

【讨论】:

【参考方案4】:

关于NSURLProtocol: 据我了解,它会提出自己的请求,因此您的自定义标签/字段/标记将被删除。

我采用了其他方式:将分段请求重定向到某个自定义 url 方案,然后在协议的 canInitWithRequest 方法中检查方案。

这样就可以了。 (花了一个星期来弄清楚整个 hls 处理的事情......)

【讨论】:

以上是关于是否可以使用 AVPlayer 缓存 HLS 段?的主要内容,如果未能解决你的问题,请参考以下文章

AVPlayer 不播放 HLS 直播

在 iOS SDK - AVPlayer 中手动选择视频质量的 HLS 流?

带有 HLS 冗余流和不良网络的奇怪 AVPlayer 行为

iOS AVPlayer 未加载大多数 HLS 流

AVPlayer HLS 直播 IOS

在 iOS 13 上,AVPlayer 会为此 HLS 视频选择仅音频流。我可以控制这种行为,而是让它加载视频+音频吗?