AVPlayer流式传输进度

pab*_*sso 35 iphone ios avplayer

我成功地使用AVPlayer从服务器流式传输音频,我现在要做的是显示一个UISlider显示缓冲进度的自定义.

像这样的东西:

在此输入图像描述

随着AVPlayer似乎有不被一种方式来获得总下载大小或音频文件的当前下载量,仅当前播放时间和总播放时间.

这有什么变通方法吗?

And*_*icz 56

我正在努力解决这个问题,到目前为止还有以下几点:

- (NSTimeInterval) availableDuration;
{
  NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
  CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
  Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
  Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
  NSTimeInterval result = startSeconds + durationSeconds;
  return result;
}
Run Code Online (Sandbox Code Playgroud)

  • 仔细检查数组是否为非空.在iOS 8上,它有时会返回一个空数组,导致上面的代码崩溃. (8认同)

pki*_*kis 11

它应该运作良好:

Objective-C的:

- (CMTime)availableDuration
{
    NSValue *range = self.player.currentItem.loadedTimeRanges.firstObject;
    if (range != nil){
        return CMTimeRangeGetEnd(range.CMTimeRangeValue);
    }
    return kCMTimeZero;
}
Run Code Online (Sandbox Code Playgroud)

Swift版本:

func availableDuration() -> CMTime
{
    if let range = self.player?.currentItem?.loadedTimeRanges.first {
        return CMTimeRangeGetEnd(range.timeRangeValue)
    }
    return .zero
}
Run Code Online (Sandbox Code Playgroud)

要观察当前时间值,您可以使用: CMTimeShow([self availableDuration]); CMTimeShow(availableDuration()) (对于swift)


小智 7

我个人不同意 timeRanges 值的计数始终为 1。

根据文档

该数组包含 NSValue 对象,该对象包含一个 CMTimeRange 值,该值指示播放器项目具有随时可用的媒体数据的时间范围。返回的时间范围可能不连续。

因此,这可能具有类似于以下内容的值:

[(开始1,结束1),(开始2,结束2)]

根据我在桌面网络世界中使用 hls.js 框架的经验,这些时间范围之间的差距可能非常小或大,这取决于多种因素,例如:寻找、不连续性等。

因此,要正确获得总缓冲区长度,您需要遍历数组并获取每个项目和连接的持续时间。

如果您正在寻找当前播放头的缓冲区值,您需要过滤开始时间大于当前时间和结束时间小于当前时间的时间范围。

public extension AVPlayerItem {

    public func totalBuffer() -> Double {
        return self.loadedTimeRanges
            .map({ $0.timeRangeValue })
            .reduce(0, { acc, cur in
                return acc + CMTimeGetSeconds(cur.start) + CMTimeGetSeconds(cur.duration)
            })
    }

    public func currentBuffer() -> Double {
        let currentTime = self.currentTime()

        guard let timeRange = self.loadedTimeRanges.map({ $0.timeRangeValue })
            .first(where: { $0.containsTime(currentTime) }) else { return -1 }

        return CMTimeGetSeconds(timeRange.end) - currentTime.seconds
    }

}
Run Code Online (Sandbox Code Playgroud)