How to Detect When Avplayer Video Ends Playing

How to detect which video ended when using multiple AVPlayers?

Another idea. Updated @black_pearl's method

Different notification registration , with different notification methods.

    var player = AVPlayer()
var playerTwo = AVPlayer()



override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlay(_:)), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishMusic(_:)), name: .AVPlayerItemDidPlayToEndTime, object: playerTwo.currentItem)

}


@objc func playerDidFinishPlay(_ noti: Notification) {
if let p = noti.object as? AVPlayerItem, p == player.currentItem {
print("1")
}
}


@objc func playerDidFinishMusic(_ noti: Notification) {
if let p = noti.object as? AVPlayerItem, p == playerTwo.currentItem{
print("2")
}
}

How to detect when an AVPlayerItem is finished playing?

It uses NSNotification to alert when playback is finished.

Register for the notification:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];

Method to call when done:

-(void)itemDidFinishPlaying:(NSNotification *) notification {
// Will be called when AVPlayer finishes playing playerItem
}

Detect when AVPlayer is playing

As far as I know, I agree with you that there is a slight delay between when the play() function is called and the video actually plays (In another word, the time that the first frame of the video has been rendered). The delay depends on some criteria such as video types (VOD or live streaming), the network condition, ... However, fortunately, we are able to know whenever the first frame of the video rendered, I mean exactly when the video actually plays.

By observing the status of the current AVPlayerItem and whenever it is AVPlayerItemStatusReadyToPlay, that should be the first frame has been rendered.

[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];

-(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context {

if([self.playerItem status] == AVPlayerStatusReadyToPlay){
NSLog(@"The video actually plays")
}
}

By the way, there is another solution where we observe readyForDisplay status of AVPlayerLayer, it also indicates whenever the video rendered. However, this solution has a drawback as mentioned in Apple document

/*!
@property readyForDisplay
@abstract Boolean indicating that the first video frame has been made ready for display for the current item of the associated AVPlayer.
@discusssion Use this property as an indicator of when best to show or animate-in an AVPlayerLayer into view.
An AVPlayerLayer may be displayed, or made visible, while this propoerty is NO, however the layer will not have any
user-visible content until the value becomes YES.
This property remains NO for an AVPlayer currentItem whose AVAsset contains no enabled video tracks.
*/
@property(nonatomic, readonly, getter=isReadyForDisplay) BOOL readyForDisplay;

Here is the sample code

self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; 
[self.playerLayer addObserver:self forKeyPath:@"readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];

-(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context {
if([self.playerLayer isReadyForDisplay]){
NSLog(@"Ready to display");
}
}

Thereotically, [self.playerLayer isReadyForDisplay] should return YES, however, as the document, it is not guaranted.

I hope this would be helpful.

How to track when song finished playing in AVPlayer?

change your notification oberserver from

 NotificationCenter.default.addObserver(self, selector: Selector(("finishedPlaying:")), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem)

into swift3 syntax

  NotificationCenter.default.addObserver(self, selector: #selector(self.finishedPlaying(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem)

and call the method as

@objc func finishedPlaying( _ myNotification:NSNotification) {

}

How to rewrite code for detect when AVPlayer is closed inside WKWebKit

Need create two notificationcented observer for detect maximize and minimize avplayer

 override func viewDidLoad() {
super.viewDidLoad()

// listen for videos playing in fullscreen
NotificationCenter.default.addObserver(self, selector: #selector(onDidEnterFullscreen(_:)), name: UIWindow.didBecomeVisibleNotification, object: view.window)

// listen for videos stopping to play in fullscreen
NotificationCenter.default.addObserver(self, selector: #selector(onDidLeaveFullscreen(_:)), name: UIWindow.didBecomeHiddenNotification, object: view.window)
}

@objc func onDidEnterFullscreen(_ notification: Notification) {
print("Enter Fullscreen")
}

@objc func onDidLeaveFullscreen(_ notification: Notification) {
print("Leave Fullscreen")
}

Detect when AvPlayer is stopped

here's the swift 3 code for @Thlbaut's answer

self.avPlayer?.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions(rawValue: 0), context: nil)

then

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "rate" {
if let playRate = self.avPlayer?.rate {
if playRate == 0.0 {
print("playback paused")
} else {
print("playback started")
}
}
}
}


Related Topics



Leave a reply



Submit