我以Apple提供的AVPlayerLooper example code为基础,特别是利用了他们在PlayerLooper.swiftLooperViewController.swiftLooper.swift协议中为您提供的示例AVPlayerLooper设置。

我想做的就是能够更新在PlayerLooper.swift文件中实例化的AVPlayerLooper上的timeRange属性。

为此,我对以下函数进行了一些修改,该函数实例化并启动了播放器循环程序:

func start(in parentLayer: CALayer, loopTimeRange: CMTimeRange) {
        player = AVQueuePlayer()
        playerLayer = AVPlayerLayer(player: player)

        guard let playerLayer = playerLayer else { fatalError("Error creating player layer") }
        playerLayer.frame = parentLayer.bounds
        parentLayer.addSublayer(playerLayer)

        let playerItem = AVPlayerItem(url: videoURL)
        playerItem.asset.loadValuesAsynchronously(forKeys: [ObserverContexts.playerItemDurationKey], completionHandler: {()->Void in
            /*
             The asset invokes its completion handler on an arbitrary queue when
             loading is complete. Because we want to access our AVPlayerLooper
             in our ensuing set-up, we must dispatch our handler to the main queue.
             */
            DispatchQueue.main.async(execute: {
                guard let player = self.player else { return }

                var durationError: NSError? = nil
                let durationStatus = playerItem.asset.statusOfValue(forKey: ObserverContexts.playerItemDurationKey, error: &durationError)
                guard durationStatus == .loaded else { fatalError("Failed to load duration property with error: \(String(describing: durationError))") }

                //self.playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)

                self.playerLooper = AVPlayerLooper(player: player, templateItem: playerItem, timeRange: loopTimeRange)

                self.startObserving()
                player.play()
            })
        })
    }

为了演示,我在LooperViewController中创建了一个简单的按钮,它使用新的CMTimeRange来触发looper?.start(),如下所示:
looper?.start(in: view.layer, loopTimeRange: CMTimeRange(start: CMTime(value: 0, timescale: 600), duration: CMTime(value: 3000, timescale: 600)))

但是,在调用该函数之前,我先调用looper?.stop(),它执行以下操作:
func stop() {
        player?.pause()
        stopObserving()

        playerLooper?.disableLooping()
        playerLooper = nil

        playerLayer?.removeFromSuperlayer()
        playerLayer = nil

        player = nil
    }

为了设置新的timeRange属性,我基本上是完全重新实例化AVPlayerLooper,因为在第一次设置该属性后,我看不到任何实际访问和重置该属性的方法。

问题是,尽管这似乎最初可行,并且循环播放器播放器会进行调整并开始循环播放新的时间范围,但最终会在循环几次后停止播放。没有错误抛出到任何地方,并且代码中已经设置的观察者都没有报告循环正在停止或循环中存在一些错误。

我的方法在这里完全错误吗?是要以这种方式调整AVPlayerLooper还是应该寻找具有可调循环播放器的另一种方法?

最佳答案

实际上,您可以更新AVPlayerLooper而不用拆散整个内容。您需要做的是先从AVQueuePlayer中删除所有项目,然后使用新的时间范围重新初始化循环器。像这样:

if self.avQueuePlayer.rate == 0 {
   self.avQueuePlayer.removeAllItems()
   let range = CMTimeRange(start: self.startTime, end: self.endTime)
   self.avPlayerLooper = AVPlayerLooper(player: self.avQueuePlayer, templateItem: self.avPlayerItem, timeRange: range)
   self.avQueuePlayer.play()
}

您必须确定removeAllItems()否则它将崩溃。否则,这将更改时间范围,同时允许您使用当前图层等设置来查看播放器。

10-08 11:53