iOS上的HLS AVPlayer - 返回直播

7

我有一个AVPlayer正在流式传输一段直播HLS流。

当用户多任务时,我看到播放速率下降到0.0(暂停),当用户返回时,它返回到1.0(播放),但从暂停的点开始播放。

有什么最好的方法可以强制播放器回到实时状态而不完全重新启动流吗?是否有一个seekToTime方法,可以处理最接近实时时间的参数?

谢谢!

7个回答

8

我使用:

 double time = MAXFLOAT;
 [player seekToTime: CMTimeMakeWithSeconds(time, NSEC_PER_SEC)];

在我的应用程序中表现良好。


3
假设player是一个AVPlayer实例:
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)];

这是真正的答案。对我非常有效。 - davidgoli
你也可以使用CMTimeAdd,而不必将其转换为浮点数。 - Sterling Christensen
3
你也可以使用 CMTimeRangeGetEnd 代替将持续时间加到开始时间上。 - Fabian
当你等待足够长的时间时,这个解决方案会导致异常,因为时间无效。 - Jindřich Skeldal

2
Igor Kulagin的Swift版本答案:
player.seek(to: kCMTimePositiveInfinity)
player.play()

在任何情况下都可以完美运行。其他解决方案在计算“livePosition”值时会出现“NaN”错误,或者在直接使用“CMTime”时会出现“{INVALID}”错误。

在iOS 14上,这似乎不再起作用了,必须使用可寻址时间范围的解决方案。 - CiNN
这在iOS 14+上对我很有效。 - Rexam
如果等待时间很长(几分钟),则返回播放需要很长时间(几分钟)。对于短暂的停止,它可以正常工作。(iOS 16) - Jindřich Skeldal

1

Swift 3.0 版本

public func resumeLive() {
    guard let livePosition = player.currentItem?.seekableTimeRanges.last as? CMTimeRange else {
        return
    }
    player.seek(to:CMTimeRangeGetEnd(livePosition))
}

0

卡里姆·穆拉的答案的Swift版本:

let seekableRanges = player.currentItem!.seekableTimeRanges
guard seekableRanges.count > 0 else {
  return
}

let range = seekableRanges.last!.CMTimeRangeValue
let livePosition = range.start + range.duration

let minus = CMTimeMakeWithSeconds(Float64(timeOffset), Int32(NSEC_PER_SEC))
let time = livePosition - minus

player.seekToTime(time)

1
请注意,以下是翻译的文本内容: guard let lastRange = player.currentItem?.seekableRanges.last else {return;}player.seekToTime(lastRange.end) - Fabian
什么是"timeoffset"? - Hong Zhou
@HongZhou 这是一个完全可选的缓冲时间,单位为秒。您可以直接使用 livePosition,并省略带有 timeOffset 的那一行代码。 - davidgoli

0

如果使用苹果的CMTimeRange操作函数,则无需将其转换为浮点数:

NSValue *value = player.currentItem.seekableTimeRanges.lastObject;
if (value) {
    CMTimeRange seekableRange = [value CMTimeRangeValue];
    CMTime latestTime = CMTimeRangeGetEnd(seekableRange);
    [player seekToTime:latestTime];
} else {
    // there are no seekable time ranges
}

请查看下面的@Fabian's comment

2
如果您使用CMTimeRangeGetEnd,则无需添加时间。 - Fabian

0

Swift 4 版本:

if let seekableRange = player.currentItem?.seekableTimeRanges.last?.timeRangeValue {
    let seekableStart = seekableRange.start
    let seekableDuration = seekableRange.duration
    let livePosition = seekableStart + seekableDuration

    player.seek(to: livePosition, completionHandler: { [weak self] _ in
        self?.player.play()
    })
}

当您等待很长时间时,它会产生异常,因为时间无效。 - Jindřich Skeldal

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