我的问题是:我正在尝试进行无缝循环(我打算使我的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(设置为:零)。但是什么都没有。
任何帮助将不胜感激:)
答案 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()