AVPlayer 串流进度

Posted

技术标签:

【中文标题】AVPlayer 串流进度【英文标题】:AVPlayer streaming progress 【发布时间】:2011-10-07 19:14:53 【问题描述】:

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

类似这样的:

对于AVPlayer,似乎无法获取音频文件的总下载大小或当前下载量,只能获取当前播放时间和总播放时间。

有什么解决方法吗?

【问题讨论】:

你有没有实现过这个的 UI 部分?我正是需要这个,如果已经有东西了,我宁愿不自己推出。 查看 UI 部分此问题的最佳答案:***.com/questions/4495433/… 实现上述 UI 的简单解决方案是简单地将 UIProgressBar 放在 UISlider 下方,并将滑块的 maximumTrackTintColor 设置为 [UIColor clearColor] 关注这个答案。 ***.com/questions/4218090/…可能对你有帮助。 【参考方案1】:

我只是在做这个,到目前为止有以下内容:

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

【讨论】:

要补充一点,您要查找的值是 AVPlayerItem 属性loadedtimeRanges。它是一个包含 CMTimeRange 的 NSValue 的 NSArray。这个代码块是我想出来的,也就是说,如何把这些数据变成有用的东西。 为什么你是第一次而不是最后一次? [loadedTimeRanges lastObject] 我记得我写了一个函数来观察它的行为,并且总是只看到数组中的一个元素,所以这可能是没有意义的/任意的。理论上更“正确”的计算是使用此数组,并根据最大开始时间 + 持续时间找到最大持续时间,但实际上没有必要。 这里的回答者也确认了数组有1个元素,所以我的记性很好:***.com/questions/3999228/… 仔细检查数组是否为非空。在 ios 8 上,它有时会返回一个空数组,导致上述代码崩溃。【参考方案2】:

应该很好用:

目标-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()) (for swift)

【讨论】:

【参考方案3】:

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

根据文档

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

所以这可能具有类似于以下的值:

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

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

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

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

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
    


【讨论】:

【参考方案4】:

此方法将为您的 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))
    

【讨论】:

您能否再解释一下代码的作用以及它如何解决 OP 的问题?以目前的格式,阅读起来有点困难【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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));

【讨论】:

以上是关于AVPlayer 串流进度的主要内容,如果未能解决你的问题,请参考以下文章

具有缓冲进度的 UISlider - AVPlayer

AVPlayer添加播放进度监听

AVPlayer 进度滑块随用户拖动而变化

UISlider Swift 的 AVPlayer 进度

如何在 tableViewCell 中控制 AVPlayer(通过滑块和搜索播放、暂停、进度)?

AVPlayer播放网络音乐