AVPlayer流式传输进度

时间:2011-10-07 19:14:54

标签: iphone ios avplayer

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

这样的事情:

enter image description here

使用AVPlayer似乎无法获得音频文件的总下载大小或当前下载量,只有当前播放时间和总播放时间。

这有什么变通方法吗?

6 个答案:

答案 0 :(得分:55)

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

- (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;
}

答案 1 :(得分:10)

它应该运作良好:

<强>目标-C:

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

Swift版本:

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

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

答案 2 :(得分:3)

就我个人而言,我不同意timeRanges值始终为1。

根据文件

  

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

所以这可能有类似于:

的值

[(start1,end1),(start2,end2)]

根据我在桌面网络世界中使用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
    }

}

答案 3 :(得分:0)

此方法将返回UISlider的缓冲时间间隔

public var bufferAvail: NSTimeInterval {

    // Check if there is a player instance
    if ((player.currentItem) != nil) {

        // Get current AVPlayerItem
        var item: AVPlayerItem = player.currentItem
        if (item.status == AVPlayerItemStatus.ReadyToPlay) {

            var timeRangeArray: NSArray = item.loadedTimeRanges
            var aTimeRange: CMTimeRange = timeRangeArray.objectAtIndex(0).CMTimeRangeValue
            var startTime = CMTimeGetSeconds(aTimeRange.start)
            var loadedDuration = CMTimeGetSeconds(aTimeRange.duration)

            return (NSTimeInterval)(startTime + loadedDuration);
        }
        else {
            return(CMTimeGetSeconds(kCMTimeInvalid))
        }
    } 
    else {
        return(CMTimeGetSeconds(kCMTimeInvalid))
    }
}

答案 4 :(得分:0)

如果返回的数组为空,则选择的答案可能会导致问题。这是一个固定的功能:

- (NSTimeInterval) availableDuration
{
    NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges];
    if ([loadedTimeRanges count])
    {
        CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
        Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
        Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval result = startSeconds + durationSeconds;
        return result;
    }
    return 0;
}

答案 5 :(得分:0)

Suresh Kansujiya在Objective C中的代码

NSTimeInterval bufferAvail;

if (player.currentItem != nil) {

    AVPlayerItem *item = player.currentItem;
    if (item.status == AVPlayerStatusReadyToPlay) {
        NSArray *timeRangeArray = item.loadedTimeRanges;
        CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
        Float64 startTime = CMTimeGetSeconds(aTimeRange.start);
        Float64 loadedDuration = CMTimeGetSeconds(aTimeRange.duration);

        bufferAvail = startTime + loadedDuration;

        NSLog(@"%@ - %f", [self class], bufferAvail);
    } else {
        NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid)); }
}
else {
    NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid));
}