ios 你如何在 Swift 中循环 AVPlayer?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27808266/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you loop AVPlayer in Swift?
提问by Jonathan Plackett
Simple question I can't seem to find an answer to for some reason.
由于某种原因,我似乎无法找到答案的简单问题。
How do you loop AVPlayer in Swift?
你如何在 Swift 中循环 AVPlayer?
numberOfLoops = -1 only works for AVAudioPlayer
numberOfLoops = -1 仅适用于 AVAudioPlayer
I do need it to loop without any delay / black flash etc. That's why I'm not using MPMoviePlayerViewController.
我确实需要它在没有任何延迟/黑色闪光等的情况下循环。这就是我不使用 MPMoviePlayerViewController 的原因。
Thanks for any help.
谢谢你的帮助。
Code:
代码:
let url_1 = NSURL.fileURLWithPath(outputFilePath_1)
let asset_1 = AVAsset.assetWithURL(url_1) as? AVAsset
let playerItem_1 = AVPlayerItem(asset: asset_1)
let player_1 = AVPlayer(playerItem: self.playerItem_1)
let playerLayer_1 = AVPlayerLayer(player: self.player_1)
playerLayer_1!.frame = self.view.frame
self.view.layer.addSublayer(self.playerLayer_1)
player_1!.play()
回答by Alexander Volkov
Swift 4
斯威夫特 4
var player: AVPlayer!
...
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: .main) { [weak self] _ in
self?.player?.seek(to: CMTime.zero)
self?.player?.play()
}
Swift 3
斯威夫特 3
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: .main) { [weak self] _ in
self?.player?.seek(to: kCMTimeZero)
self?.player?.play()
}
Swift 2
斯威夫特 2
After AVPlayerItem is configured and player is created:
配置完 AVPlayerItem 并创建播放器后:
var player: AVPlayer!
...
// Invoke after player is created and AVPlayerItem is specified
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "playerItemDidReachEnd:",
name: AVPlayerItemDidPlayToEndTimeNotification,
object: self.player.currentItem)
...
func playerItemDidReachEnd(notification: NSNotification) {
self.player.seekToTime(kCMTimeZero)
self.player.play()
}
Don't forget to import AVFoundation
不要忘记 import AVFoundation
回答by Bright Future
Starting from iOS 10, there's no need to use notifications to loop a video, simply use a AVPlayerLooper, just like this:
从 iOS 10 开始,不需要使用通知来循环播放视频,只需使用AVPlayerLooper,就像这样:
let asset = AVAsset(url: videoURL)
let item = AVPlayerItem(asset: asset)
let player = AVQueuePlayer(playerItem: item)
videoLooper = AVPlayerLooper(player: player, templateItem: item)
make sure this looper is created outside of a function scope, in case it stops when function returns.
确保这个循环器是在函数作用域之外创建的,以防它在函数返回时停止。
回答by Ben Stahl
@Christopher Pickslay's answer updated for Swift 4:
@Christopher Pickslay 为Swift 4更新了答案:
func loopVideo(videoPlayer: AVPlayer) {
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
videoPlayer.seek(to: CMTime.zero)
videoPlayer.play()
}
}
But, as I mentioned below his answer, be sure to specify the object as the AVPlayer's player item if you have multiple players.
但是,正如我在他的回答下面提到的,如果您有多个玩家,请务必将该对象指定为 AVPlayer 的播放器项目。
回答by Christopher Pickslay
Alternatively, you can use the block-based NSNotificationCenter API:
或者,您可以使用基于块的 NSNotificationCenter API:
func loopVideo(videoPlayer: AVPlayer) {
NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: nil, queue: nil) { notification in
videoPlayer.seekToTime(kCMTimeZero)
videoPlayer.play()
}
}
回答by Jonathan Plackett
OK I have worked it out. Thanks Msencenb for pointing me in the right direction with an Objective C answer.
好的,我已经解决了。感谢 Msencenb 用 Objective C 的答案为我指明了正确的方向。
player_1?.actionAtItemEnd = .None
//set a listener for when the video ends
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "restartVideoFromBeginning",
name: AVPlayerItemDidPlayToEndTimeNotification,
object: player_1?.currentItem)
//function to restart the video
func restartVideoFromBeginning() {
//create a CMTime for zero seconds so we can go back to the beginning
let seconds : Int64 = 0
let preferredTimeScale : Int32 = 1
let seekTime : CMTime = CMTimeMake(seconds, preferredTimeScale)
player_1!.seekToTime(seekTime)
player_1!.play()
}
回答by Just A Minnion
I've managed to create a seamless video looping for OSX in swift 3. It should work on iOS and with little modification on swift 2 as well.
我已经设法在 swift 3 中为 OSX 创建了一个无缝视频循环。它应该可以在 iOS 上运行,并且在 swift 2 上也几乎没有修改。
var player : AVQueuePlayer!
// Looping video initial call
internal func selectVideoWithLoop(url : URL)
{
let asset = AVAsset(url: url)
player.pause()
let playerItem1 = AVPlayerItem(asset: asset)
let playerItem2 = AVPlayerItem(asset: asset)
player.removeAllItems()
player.replaceCurrentItem(with: playerItem1)
player.insert(playerItem2, after: playerItem1)
player.actionAtItemEnd = AVPlayerActionAtItemEnd.advance
player.play()
let selector = #selector(ViewController.playerItemDidReachEnd(notification:))
let name = NSNotification.Name.AVPlayerItemDidPlayToEndTime
// removing old observer and adding it again for sequential calls.
// Might not be necessary, but I like to unregister old notifications.
NotificationCenter.default.removeObserver(self, name: name, object: nil)
NotificationCenter.default.addObserver(self, selector: selector, name: name, object: nil)
}
// Loop video with threadmill pattern
// Called by NotificationCenter, don't call directly
func playerItemDidReachEnd(notification: Notification)
{
let item = player.currentItem!
player.remove(item)
item.seek(to: kCMTimeZero)
player.insert(item, after: nil)
}
When you want to change the video, just call selectVideoWithLoop with a different url again.
当您想更改视频时,只需再次使用不同的 url 调用 selectVideoWithLoop 即可。
回答by Akhilesh Sharma
Swift 3.0:
斯威夫特 3.0:
First check for video end point:-
首先检查视频终点:-
NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
func videoDidReachEnd() {
//now use seek to make current playback time to the specified time in this case (O)
let duration : Int64 = 0 (can be Int32 also)
let preferredTimeScale : Int32 = 1
let seekTime : CMTime = CMTimeMake(duration, preferredTimeScale)
player!.seek(to: seekTime)
player!.play()
}