AVPlayer能否缓存HLS片段?

36

根本问题

iOS中寻求视频时,我们的视频缓冲很多。 它比我们的Web播放器缓冲了更多,后者在临时存储中保存已观看过的片段的副本。

期望解决方案

在设备磁盘上缓存视频片段。 我们可以只缓存单一质量并不断重播。

阻碍因素

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

我们尝试过什么

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

  1. 符合AVAssetResourceLoaderDelegate并手动处理媒体加载。

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

  1. 实施NSURLProtocol以捕获对 .ts 文件的请求。

AVURLAsset实际上避免被拦截。 不知何故,网络请求不会被捕获(原因未知)。


1
我正准备实现一个NSURLProtocol来尝试缓存.ts文件。@narohi - 你解决了这个问题吗?我也非常想在磁盘上缓存HLS片段。很高兴在浪费时间之前发现它行不通。现在我倾向于放弃AVPlayer,通过解析m3u8播放列表并使用AVQueuePlayer编写自己的HLS播放器。JWPlayer SDK for iOS看起来很有前途,但他们的“联系我们获取我们的年度合同定价”听起来有点可怕。 - ndbroadbent
1
你可以代理HLS流 - 手动下载ts并在设备上托管m3u8(localhost/xxx.m3u8)。 - Itay Kinnrot
@nathan.f77,我们目前正在使用CocoaHTTPServer原型化代理流,结果很有前途。 - Nathan Hillyer
@ItayKinnrot 谢谢!那正是我们考虑过并开始原型设计的解决方案。 - Nathan Hillyer
3
我编写了一个反向代理服务器来缓存HLS段并且它运行良好。我所在的公司刚刚将这个解决方案开源:https://github.com/StyleShare/HLSCachingReverseProxyServer - devxoul
显示剩余9条评论
4个回答

14
让我们从一个好消息开始 - iOS 10及以上版本已经默认支持此功能。很快就不需要使用hack了。更多细节请参考以下关于HTTP Live Streaming的WWDC16会议内容: https://developer.apple.com/videos/play/wwdc2016/504/ 现在回到目前的情况 - iOS 9及以下版本: 对于AVPlayer而言,无法实现。但你可以通过本地HTTP服务器缓存HLS片段并使用AVPlayer播放本地流。
AVPlayer和AVAsset在处理HLS播放时不包含必要的信息(例如与MP4静态文件的行为不同)。
简而言之 - 您需要使用HTTP请求获取片段并使用本地HTTP服务器提供服务。
包括我所在公司在内的一些公司正在使用这种策略。
使用连接以所需质量下载片段,重建清单并将其全部扁平化到一个目录和一个质量中,然后在应用程序中使用本地http服务器将其提供给AVPlayer(AVPlayer只能播放通过HTTP提供的HLS流 - 而不是文件资产)。
有一些边缘情况,比如如果您想要在一次运行中播放和下载,则需要进行缓冲,正确重建m3u8清单以及具有磁盘读取的不同AVPlayer状态。
我通过第一手知识发现了这一点,既有一个已经在生产中使用了5年的系统,也有其他在App Store中使用相同解决方案的视频产品 - 总共为许多用户提供服务。
这也是我们在Android上找到的最佳解决方案。

2
我很欣赏你的观点,我们确实代理了一个本地HLS流。然而,原始问题“是否可以使用AVPlayer缓存HLS片段?”没有得到正确回答。答案是不行,但是可以通过本地HTTP服务器缓存HLS片段。如果您更新您的答案,我会接受它。 - Nathan Hillyer
修改了答案 :) - Liviu R
顺便提一下 - 请确保为HTTP代理使用非标准端口,以避免与其他应用程序/您使用相同机制分发的其他应用程序发生冲突 :) 特别是如果您拥有某些后台权限。 - Liviu R
太棒了!这样的话,当应用程序在后台运行时,音乐/视频会继续播放(无限循环)吗? - Daan
@LiviuR,你能否分享一个开源项目或文件来演示相同的概念? - Vikas Dadheech
显示剩余7条评论

3
实际上,我们可以使用AVPlayer播放从网络下载的视频,但是如果您想将已下载的数据缓存以便在本地播放,则似乎无法使用AVPlayer。幸运的是,AVURLAsset中有一个很好的API资源加载器对象,您可以向AVPlayer提供对远程音频文件的受控访问。这类似于本地HTTP代理,但没有所有麻烦。您可以在https://gist.github.com/anonymous/83a93746d1ea52e9d23f找到更多详细信息。

1
谢谢Hung。如原问题所述,AVURLAsset的资源加载器不会为HLS视频调用其代理,因此该解决方案无法起作用。 - Nathan Hillyer
谢谢。我没有仔细阅读您的问题,关于使用AVURLAsset的资源加载器,因为我认为它的代理不会调用HLS。目前,您有任何其他解决此问题的方法吗? - HSG
1
是的,我们正在本地运行CocoaHTTPServer并代理HLS流。我希望能够只使用AVPlayer来完成这个任务,但我们还没有找到解决方案。 - Nathan Hillyer

1
从iOS 10开始,您可以使用AVFoundation在用户访问快速可靠的网络时下载和存储HLS电影,并在没有网络连接的情况下稍后观看。

AVAssetDownloadURLSession

wwdc2016/504 session介绍了有关离线HLS的内容。它涉及使用AVAssetDownloadURLSessionURLSession的子类)下载和持久化资产,并用于管理AVAssetDownloadTasks。这个session中提到的API在iOS10之后可用。

AVAggregateAssetDownloadTask

wwdc2017/504 session在iOS11中引入了AVAggregateAssetDownloadTask

用于为单个AVAsset下载多个AVMediaSelections的AVAssetDownloadTask,在单个下载任务的保护下。

苹果提供了一个使用AVFoundation播放和持久化HTTP Live流的示例项目。演示文档。该演示项目使用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)

0
关于NSURLProtocol: 据我所知,它会发出自己的请求,因此您的自定义标记/字段/标记将被删除。
我采用了另一种方式:将段请求重定向到某个自定义URL方案,并在协议的canInitWithRequest方法中检查该方案。
这样它就可以正常工作了。(花了一周时间来解决整个HLS处理问题...)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接