AVPlayer未同步

8

我很无头绪,所以必须再次向您请教...

我正在构建一款 iPhone 应用程序,其中使用了三个 AVPlayer 实例。 它们都同时播放,这非常重要。 我曾经运行过以下代码:

CMClockRef syncTime = CMClockGetHostTimeClock();
CMTime hostTime = CMClockGetTime(hostTime);
[self.playerOne setRate:1.0f time:kCMTimeInvalid atHostTime:hostTime];
[self.playerTwo setRate:1.0f time:kCMTimeInvalid atHostTime:hostTime];
[self.playerThree setRate:1.0f time:kCMTimeInvalid atHostTime:hostTime];

这个程序以前运行得很完美,但几天前它突然停止了工作,三个播放器的延迟大约是300-400毫秒(这太多了,100毫秒以下的都可以接受)。其中两个AVPlayer有一些音频处理,需要比“正常”的AVPlayer更长的时间,但以前它们都能正常工作,currentTime属性告诉我,这些播放器已经延迟了,因此同步似乎失败了。

我不知道为什么它停止工作了,我没有真正改变什么,但我使用了一个观察者,在那里我可以询问self.playerX.currentTime属性,这给了我大约0.3-0.4秒的延迟……我已经尝试过如果delay> 0.1f就重新同步播放器,但延迟仍然存在。因此,我认为player1和2的音频处理不能对延迟负责,因为currentTime属性确实知道它们已经延迟了(希望你知道我的意思)。也许你们中的某个人知道为什么我会有这样可怕的延迟,或者能够为我提供另一个想法。

谢谢您的帮助!

2个回答

18

所以,我找到了解决方案。我忘记了[self.playerX prerollAtRate:]。我认为如果观察者是AVPlayerReadyToPlay,则意味着播放器已经“真正”准备好了。实际上,并不是这样。在AVPlayer准备好播放后,它必须进行预滚动。完成此操作后,您可以同步播放器。延迟现在约为0.000006秒。


感谢分享,这个解决方案非常有帮助。 - Jan Cássio
2
谢谢Max,你能编辑你的答案并包含原始代码吗?我不理解,setRate在prerollAtRate的完成处理程序中为每个玩家调用了吗? - Hunter Monk

0

在多个iOS设备之间同步AVPlayer的完整功能

private func startTribePlayer() {
    let dateFormatterGet = DateFormatter()
    dateFormatterGet.dateFormat = "yyyy-MM-dd"
    guard let refDate = dateFormatterGet.date(from: "2019-01-01") else { return }
    let tsRef = Date().timeIntervalSince(refDate)
    //currentDuration is avplayeritem.duration().seconds
    let remainder = tsRef.truncatingRemainder(dividingBy: currentDuration)
    let ratio = remainder / currentDuration
    let seekTime = ratio * currentDuration
    let bufferTime = 0.5
    let bufferSeekTime = seekTime + bufferTime
    let mulFactor = 10000.0
    let timeScale = CMTimeScale(mulFactor)
    let seekCMTime = CMTime(value: CMTimeValue(CGFloat(bufferSeekTime * mulFactor)), timescale: timeScale)
    let syncTime = CMClockGetHostTimeClock()
    let hostTime = CMClockGetTime(syncTime)
    tribeMusicPlayer?.seek(to: seekCMTime, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: { [weak self] (successSeek) in
        guard let tvc = self, tvc.tribeMusicPlayer?.currentItem?.status == .readyToPlay else { return }
        tvc.tribeMusicPlayer?.preroll(atRate: 1.0, completionHandler: { [tvc] (successPreroll) in
            tvc.tribePlayerDidPlay = true
            tvc.tribeMusicPlayer?.setRate(1.0, time: seekCMTime, atHostTime: hostTime)
        })
    })
}

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