使用 AVAssetDownloadTask 进行 HLS 缓存

Posted

技术标签:

【中文标题】使用 AVAssetDownloadTask 进行 HLS 缓存【英文标题】:HLS caching using AVAssetDownloadTask 【发布时间】:2020-08-18 11:34:41 【问题描述】:

我正在关注 Apple 关于缓存 HLS (.m3u8) 视频的文档。

https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MediaPlaybackGuide/Contents/Resources/en.lproj/HTTPLiveStreaming/HTTPLiveStreaming.html

在文档的Playing Offline Assets下,指示使用AVAssetDownloadTask的asset同时开始播放。

func downloadAndPlayAsset(_ asset: AVURLAsset) 
    // Create new AVAssetDownloadTask for the desired asset
    // Passing a nil options value indicates the highest available bitrate should be downloaded
    let downloadTask = downloadSession.makeAssetDownloadTask(asset: asset,
                                                         assetTitle: assetTitle,
                                                         assetArtworkData: nil,
                                                         options: nil)!
    // Start task
    downloadTask.resume()

    // Create standard playback items and begin playback
    let playerItem = AVPlayerItem(asset: downloadTask.urlAsset)
    player = AVPlayer(playerItem: playerItem)
    player.play()

问题是同一个资源被下载了两次

在 AVPlayer 初始化之后,它开始缓冲资源。最初,我假设缓冲区中的数据必须用于创建缓存,但 AVAssetDownloadTask 直到 AVPlayer 播放完资产后才开始下载数据进行缓存。缓冲的数据基本被丢弃。

我在 currentItem.loadedTimeRanges 上使用了 KVO 来检查缓冲区的状态。

playerTimeRangesObserver = currentPlayer.observe(\.currentItem?.loadedTimeRanges, options: [.new, .old])  (player, change) in

    let time = self.currentPlayer.currentItem?.loadedTimeRanges.firs.                                                
    if let t = time 
         print(t.timeRangeValue.duration.seconds)
    

下面的方法来检查 AVAssetDownloadTask 的下载状态。

/// Method to adopt to subscribe to progress updates of an AVAssetDownloadTask.
func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange) 

    // This delegate callback should be used to provide download progress for your AVAssetDownloadTask.
    guard let asset = activeDownloadsMap[assetDownloadTask] else  return 

    var percentComplete = 0.0
    for value in loadedTimeRanges 
        let loadedTimeRange: CMTimeRange = value.timeRangeValue
        percentComplete +=
            loadedTimeRange.duration.seconds / timeRangeExpectedToLoad.duration.seconds
    
    
    print("PercentComplete for \(asset.stream.name) = \(percentComplete)")

这是正确的行为还是我做错了什么? 我希望能够使用正在缓存的视频数据(正在下载 AVAssetDownloadTask)在 AVPlayer 中播放。

【问题讨论】:

你弄明白了吗? 您是否尝试按照here 的建议重新初始化 AVPlayerItem? 【参考方案1】:

您的 AVAssetDownloadTask 必须配置为下载不同于 AVPlayerItem 请求的 HLS 变体。

如果您已经通过 AVAssetDownloadTask 下载了一些数据,您的 AVPlayerItem 将随后使用它。 但是如果你已经通过 AVPlayerItem 下载了一些数据,你的 AVAssetDownloadTask 可能会忽略它,因为它需要满足你的下载配置的要求。

【讨论】:

以上是关于使用 AVAssetDownloadTask 进行 HLS 缓存的主要内容,如果未能解决你的问题,请参考以下文章

使用 Crypto++ 进行 RSA 编码并使用 c# RSACryptoServiceProvider 进行解码

AES GCM 使用 web 微妙加密进行加密并使用颤振加密进行解密

如何使用STM32提供的DSP库进行FFT

使用 C++ 原子库,我应该使用啥内存顺序进行加载,然后进行比较交换?

为啥要使用 toString() 对可以使用 typeof 进行检查的参数进行类型检查?

使用计算机视觉进行产品检测 - 使用 opencv 进行边缘检测