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 串流进度的主要内容,如果未能解决你的问题,请参考以下文章