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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 04:15:51  来源:igfitidea点击:

How do you loop AVPlayer in Swift?

iosswift

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

回答by Septronic

Might be a bit late to the conversation, but for the sake of upade (in case anyone comes here again), I found this answer HERE(it's another answer on SO) that worked for me.

谈话可能有点晚了,但为了upade(以防有人再次来到这里),我在这里找到了这个答案(这是SO上的另一个答案)对我有用。