如何在AVPlayer中获取直播流的准确时间位置

14

我正在使用AVPlayer播放直播流。这个流支持一小时的追赶功能,也就是说用户可以跳到一小时前并进行播放。但是我有一个问题,如何知道播放器当前准确的播放位置。我需要在播放器视图上显示当前位置。例如,如果用户正在播放半小时前的内容,则显示-30:00;如果用户正在播放最新的内容,则播放器将显示00:00或“直播”。谢谢。

3个回答

15

Swift解决方案:

   override func getLiveDuration() -> Float {
    var result : Float = 0.0;

    if let items = player.currentItem?.seekableTimeRanges {

        if(!items.isEmpty) {
            let range = items[items.count - 1]
            let timeRange = range.timeRangeValue
            let startSeconds = CMTimeGetSeconds(timeRange.start)
            let durationSeconds = CMTimeGetSeconds(timeRange.duration)

            result = Float(startSeconds + durationSeconds)
        }

    }
    return result;
}

这对我来说非常有效,但是这个时间的准确性只有10秒钟。因此,结果总是十的倍数,而不是更精确的时间点。您知道是否有任何方法可以更精确地测量用户落后于实时流的程度吗? - Allan Weir
@AllanWeir,你能和内容团队讨论一下吗?他们给你的直播源,尝试修改m3u8播放列表清单上的片段持续时间。 - Hsiao-Ting

9
使用AVPlayerItemseekableTimeRanges属性,您可以获取实时位置,然后进行跳转:
CMTimeRange seekableRange = [player.currentItem.seekableTimeRanges.lastObject CMTimeRangeValue];
CGFloat seekableStart = CMTimeGetSeconds(seekableRange.start);
CGFloat seekableDuration = CMTimeGetSeconds(seekableRange.duration);
CGFloat livePosition = seekableStart + seekableDuration;

[player seekToTime:CMTimeMake(livePosition, 1)];

此外,如果您想要追溯某个时间点,可以通过调用 currentTime 方法获取当前播放位置。

CGFloat current = CMTimeGetSeconds([self.player.currentItem currentTime]);
CGFloat diff = livePosition - current;

很棒的解决方案,但我很好奇为什么在我的情况下(AVPlayerItem:loadedTimeRanges start + duration)的值比livePosition略大。 - Hsiao-Ting

5

我知道这个问题旧了,但我有同样的需求,我认为现有的解决方案没有很好地解决问题的意图。

为了满足相同的要求,我收集了当前时间点、起始时间和流的总时长。

在进一步解释之前,我想说明一件事,当前时间可能会超过(起始时间+总时长),这是由于hls结构中ts分段的方式。 Ts分段是可播放视频的小块,您可以在可寻址范围内拥有10秒钟的5个ts分段。这并不意味着50秒是直播流的完整长度,还有一个完整的分段(因此总共60秒的播放时间),但它不是被归类为可寻址的,因为您不应该寻找那个分段。如果您这样做,您会注意到在大多数情况下重新缓冲(因为当您已经达到播放结束时,源可能仍在创建下一个ts段)。

我的做法是检查当前流的时间是否超过可寻址范围,如果超过,则意味着我们正在直播。 如果没有,您可以轻松计算距离实时的落后时间,只需要从当前时间、开始时间和总时长减去即可。

let timeRange:CMTimeRange = player.currentItem?.seekableTimeRanges.last
let start = timeRange.start.seconds
let totalDuration = timeRange.duration.seconds
let currentTime = player.currentTime().seconds
let secondsBehindLive = currentTime - totalDuration - start

上述代码将给出一个负数,这个负数表示当前播放位置距离“实时”或者更具体地说,最新ts分段的开始时间之间的秒数差。而当正在播放最新的ts分段时,它将返回一个正数或零。
说实话,我不太清楚seekableTimeRanges什么时候会有多于1个值,对于我测试过的流媒体文件,它总是只有一个值。但如果你发现在你的流媒体文件中有多个值,你可能需要考虑是否要添加所有范围的持续时间,使用哪个时间范围作为起始值等。至少对于我的用例来说,这已经足够了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接