如何检测AVPlayer视频何时结束播放?


Answers:


98

要获取AVPlayerItemDidPlayToEndTimeNotification您的对象,您需要将其设置为AVPlayerItem

为此,只需.currentItem在您的AVPlayer

现在,一旦视频结束,您将收到通知!

看我的例子:

let videoPlayer = AVPlayer(URL: url)       

NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerDidFinishPlaying:",
        name: AVPlayerItemDidPlayToEndTimeNotification, object: videoPlayer.currentItem)

func playerDidFinishPlaying(note: NSNotification) {
    print("Video Finished")
}

迅捷3

let videoPlayer = AVPlayer(URL: url)       

NotificationCenter.default.addObserver(self, selector: Selector(("playerDidFinishPlaying:")), 
       name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: videoPlayer.currentItem)

func playerDidFinishPlaying(note: NSNotification) {
    print("Video Finished")
}

不要忘记删除您的观察者 deinit

斯威夫特4,5

NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: nil)

您知道使用此方法和使用AVPlayer方法有什么区别addPeriodicTimeObserver(TimeInterval:)吗?
MikeG

3
如何将其删除
Martian2049 '17

3
来自developer.apple.com/library/archive/releasenotes/Foundation/…在OS X 10.11和iOS 9.0中,NSNotificationCenter和NSDistributedNotificationCenter将不再向可能释放的注册观察者发送通知。
约书亚·博伊德

1
object参数传递currentItem是重要的部分-检查是否有问题。
Jan Schlorf '19

1
错在两个方面:(1)你其实不必现在通过什么作为多年的物体(2),无需DEINIT通知
Fattie

37

斯威夫特3.0

let videoPlayer = AVPlayer(URL: url)

NotificationCenter.default.addObserver(self, selector:#selector(self.playerDidFinishPlaying(note:)),name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)

@objc func playerDidFinishPlaying(note: NSNotification){
        print("Video Finished")
    }

1
但是它说[myClass playerDidFinishPlaying:]:无法识别的选择器发送到实例
Chanchal Raj

1
#selector(playerDidFinishPlaying)
djv

多次使用时,此addObserver是否会引起内存泄漏?
Martian2049年

我应该删除观察者吗?我怎么做?
罗斯,

15

Swift 4.2版本:

var player: AVPlayer!
  //
  //
// Configure Player
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let filepath: String? = Bundle.main.path(forResource: "selectedFileName", ofType: "mp4")
    if let filepath = filepath {
        let fileURL = URL.init(fileURLWithPath: filepath)
        player = AVPlayer(url: fileURL)
        let playerLayer = AVPlayerLayer(player: player)
        // Register for notification
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(playerItemDidReachEnd),
                                                         name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
                                                         object: nil) // Add observer

        playerLayer.frame = self.view.bounds
        self.view.layer.addSublayer(playerLayer)
        player.play()
    }
}
// Notification Handling
@objc func playerItemDidReachEnd(notification: NSNotification) {
    player.seek(to: CMTime.zero)
    player.play()
}
// Remove Observer
deinit {
    NotificationCenter.default.removeObserver(self)
}

2019-4-20,XCode 10.2.1,Swift 5,为我工作,谢谢
NamNamNam

8

对于SWIFT 3.0 ,一切正常

class PlayVideoViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PlayVideoViewController.finishVideo), name: NSNotification.Name.AVPlayerItemDidPlayToEndTimeNotification, object: nil)
    }

    func finishVideo()
    {
        print("Video Finished")
    }
}

nil是魔术字,否则您必须在添加的每个项目中添加/删除👌–
eonist

8

迅捷4.0

这对我有用。感谢@Channel

    private func playVideo(fileURL: String) {

            // Create RUL object
            let url = URL(string: fileURL)

            // Create Player Item object
            let playerItem: AVPlayerItem = AVPlayerItem(url: url!)
            // Assign Item to Player
            let player = AVPlayer(playerItem: playerItem)

            // Prepare AVPlayerViewController
            let videoPlayer = AVPlayerViewController()
            // Assign Video to AVPlayerViewController
            videoPlayer.player = player

            NotificationCenter.default.addObserver(self, selector: #selector(myViewController.finishVideo), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

            // Present the AVPlayerViewController
            present(videoPlayer, animated: true, completion: {
                    // Play the Video
                    player.play()
            })

    }

    @objc func finishVideo()
    {
            print("Video Finished")
    }

5

2019年

真的很简单

NotificationCenter.default.addObserver(
    self,
    selector: #selector(fileComplete),
    name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
    object: nil
)

(该对象可以为零。)

接着

@objc func fileComplete() {
    print("IT'S DONE!")
}

4

斯威夫特3.0

let videoPlayer = AVPlayer(URL: url)
NotificationCenter.default.addObserver(self, selector:#selector(self.playerDidFinishPlaying(note:)),name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)

func playerDidFinishPlaying(note: NSNotification){
    //Called when player finished playing
}

3

对于SWIFT 3.0

这里的“ fullUrl”是视频的URL,请确保URL中没有空格,您应该将“ Space”替换为“%20”,以便URL可以正常工作。

  let videoURL = NSURL(string: fullUrl)
  let player = AVPlayer(url: videoURL! as URL)

  playerViewController.delegate = self
  playerViewController.player = player
  self.present(playerViewController, animated: false) {

    self.playerViewController.player!.play()

    NotificationCenter.default.addObserver(self, selector: #selector(yourViewControllerName.playerDidFinishPlaying), name: Notification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
  }

在视图控制器中的给定方法下面添加此方法。

func playerDidFinishPlaying(){    
print("Video Finished playing in style")
}

多次使用时,此addObserver是否会引起内存泄漏?
Martian2049年

3

我知道这里有很多公认的答案...

但是,另一种方法可能是向AVPlayer添加边界时间观察者。您必须拥有视频的时长,可以从中获取视频的时长player.currentItem,然后将其添加为所需的时间范围。

fileprivate var videoEndObserver: Any?

func addVideoEndObserver() {
    guard let player = YOUR_VIDEO_PLAYER else { return }

    // This is just in case you are loading a video from a URL.
    guard let duration = player.currentItem?.duration, duration.value != 0 else {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: { [weak self] in
            self?.addVideoEndObserver()
        })

        return
    }

    let endTime = NSValue(time: duration - CMTimeMakeWithSeconds(0.1, duration.timescale))
    videoEndObserver = player.addBoundaryTimeObserver(forTimes: [endTime], queue: .main, using: {
        self.removeVideoEndObserver()

        // DO YOUR STUFF HERE...
    })
}

func removeVideoEndObserver() {
    guard let observer = videoEndObserver else { return }

    videoPlayer.player?.removeTimeObserver(observer)
    videoEndObserver = nil
}

这是个好主意,实际上,这样做通常更好。对于长素材(歌曲等),通常最好在结束前一秒钟(如果可以的话,少一点)捕捉它,而不是在文件实际“结束”时处理全部(未记录)的Apple混乱。
Fattie

2

在Swift 3和RxSwift 3.5中,您要做的就是:

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.rx.notification(Notification.Name.AVPlayerItemDidPlayToEndTime)
        .asObservable().subscribe(onNext: { [weak self] notification in

            //Your action

        }).addDisposableTo(disposeBag)
}

2

如果您喜欢使用Combine:

private var cancelBag: Set<AnyCancellable> = []

NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime)
.sink { _ in
    player.seek(to: CMTime.zero)
    player.play()
}
.store(in: &cancelBag)

一个很棒的代码示例!
Fattie
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.