简体   繁体   English

你如何在 Swift 中循环播放 AVPlayer?

[英]How do you loop AVPlayer in Swift?

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()

Swift 5 (iOS 10.0+)斯威夫特 5 (iOS 10.0+)

var playerLooper: AVPlayerLooper! // should be defined in class
var queuePlayer: AVQueuePlayer!
...

let asset: AVAsset = ... // AVAsset with its 'duration' property value loaded
let playerItem = AVPlayerItem(asset: asset)
self.queuePlayer = AVQueuePlayer(playerItem: playerItem)

// Create a new player looper with the queue player and template item
self.playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)

< iOS 10.0 < iOS 10.0

All below works in any iOS version.以下所有内容均适用于任何 iOS 版本。 But, for > iOS 10.0 it's the only solution.但是,对于 > iOS 10.0,这是唯一的解决方案。

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

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.确保这个循环器是在函数作用域之外创建的,以防它在函数返回时停止。

@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 的播放器项目。

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()
    }
}

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()

}

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 即可。

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()
    }

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()

Swift 5.5:斯威夫特 5.5:

func loopVideo(videoPlayer: AVPlayer) {
  NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
    videoPlayer.seek(to: .zero)
    videoPlayer.play()
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM