AVPlayerLoop无法无缝循环-Swift 4

时间:2018-12-20 21:45:30

标签: ios swift video avfoundation avplayerlooper

我的问题是:我正在尝试进行无缝循环(我打算使我的AVPlayer或AVPlayerQueue循环,而两次回放之间没有任何延迟)。因此,例如,如果我制作视频并转到播放,则它应该无休止地循环播放,而在循环之间没有任何尖锐现象或延迟。

我已经编写了以下代码(也直接来自示例代码):

    var playerQQ: AVQueuePlayer!
    var playerLayur: AVPlayerLayer!
    var playerEyetem: AVPlayerItem!
    var playerLooper: AVPlayerLooper!

    func playRecordedVideo(videoURL: URL) {

        playerQQ = AVQueuePlayer()
        playerLayur = AVPlayerLayer(player: playerQQ)
        playerLayur.frame = (camBaseLayer?.bounds)! 
       camBaseLayer?.layer.insertSublayer(playerLayur, above: previewLayer) 

       playerEyetem = AVPlayerItem(url: videoURL)
        playerLooper = AVPlayerLooper(player: playerQQ, templateItem: playerEyetem)
        playerQQ.play()

    }

上面的代码无法无缝循环;在当前播放器的末尾和下一个播放器之间有闪点。我已经做了很多尝试来找到问题,并在网上进行搜索,但没有找到解决方案。另外,我一直在尝试NSNotifications和其他方法,包括在播放器完成播放时将Player.seek(设置为:零)。但是什么都没有。

任何帮助将不胜感激:)

4 个答案:

答案 0 :(得分:1)

如果在最后播放,请尝试

NotificationCenter.default.addObserver(self,
                                       selector: #selector(playerItemDidReachEnd(notification:)),
                                       name: Notification.Name.AVPlayerItemDidPlayToEndTime,
                                       object: avPlayer?.currentItem)

 @objc func playerItemDidReachEnd(notification: Notification) {
        if let playerItem: AVPlayerItem = notification.object as? AVPlayerItem {
            playerItem.seek(to: kCMTimeZero, completionHandler: nil)
        }
    }

如果没有,我建议您使用dTime(触发NSTimer 1/30秒之类的时间)来管理自己的游戏,并设置为像这样玩

    player.seekToTime(seekTimeInProgress, toleranceBefore: kCMTimeZero,
            toleranceAfter: kCMTimeZero, completionHandler: ...

kCMTimeZero非常重要,否则时间将不准确。 最后,我发现重新启动vid时会有加载时间,具体取决于iOS手机的类型和视频的长度以及播放的次数,因此,如果在消除计时问题后仍然滞后,可能会被迫在您的UX中使用。

答案 1 :(得分:1)

在循环播放资产时要记住的一件事是,音频和视频轨道可能具有不同的偏移量和不同的持续时间,从而导致在循环播放时出现“斑点”。如此小的差异在记录资产中非常普遍。

遍历曲目并打印时间范围可以帮助检测以下情况:for track in asset.tracks { print( track.mediaType); CMTimeRangeShow( track.timeRange); }

要将音频和视频轨道修整为相等的开始时间和相同的持续时间,请获取轨道的公共时间范围,然后将该时间范围从原始资产插入到新的AVMutableComposition中。通常,您还希望保留诸如视频轨道方向之类的属性:

let asset: AVAsset = (your asset initialization here)

let videoTrack: AVAssetTrack = asset.tracks(withMediaType: .video).first!
let audioTrack: AVAssetTrack = asset.tracks(withMediaType: .audio).first!

// calculate common time range of audio and video track
let timeRange: CMTimeRange = CMTimeRangeGetIntersection( (videoTrack.timeRange), (audioTrack.timeRange))

let composition: AVMutableComposition = AVMutableComposition()

try composition.insertTimeRange(timeRange, of: asset, at: kCMTimeZero)

// preserve orientation
composition.tracks(withMediaType: .video).first!.preferredTransform = videoTrack.preferredTransform

由于AVMutableComposition是AVAsset的子类,因此可用于基于AVPlayerLooper的循环播放,或与AVAssetExportSession一起导出。

我在github上放置了更完整的修整实现:https://github.com/fluthaus/NHBAVAssetTrimming。它更强大,可以处理多个轨道,保留更多属性,并且可以轻松集成到项目中,也可以作为独立的macOS命令行电影修整实用程序来构建。

答案 2 :(得分:1)

@NoHalfBits的答案很好,但我也找到了另一种解决方案。我基本上从playerItem的资产中获得了视频和声音mediaTypes的交集时间范围。之后,我在调用时在参数中添加交集TimeRange作为timeRange:

playerLooper = AVPlayerLooper(playerQueue:_, playerItem:_, timeRange: intersectionTimeRange)

这将起作用!要获取每个时间范围的timeRanges,请为playerItem的资产设置一个for循环。

答案 3 :(得分:0)

这似乎是.mp4文件问题,请将.mp4文件转换为.mov文件。带有.mp4文件的AVPlayer或AVQueuePlayer都可以正常工作。这是我的代码:

NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { [weak self] (noty) in
   self?.player?.seek(to: CMTime.zero)
   self?.player?.play() }

let asset = AVAsset(url: URL(fileURLWithPath: movPath))
let playerItem = AVPlayerItem(asset: asset)
let player = AVQueuePlayer(playerItem: playerItem)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
plyerLayer.frame = CGRect(x: 0, y: 88, width: kWidth, height: kWidth * 0.75)
plyerLayer.videoGravity = .resizeAspectFill
plyerLayer.player = player
view.layer.addSublayer(plyerLayer)
player.play()