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.
For Video:
AVPlayer
have an argument called rate (Float)
, if the rate
is greater than 0.0, there a video that currently playing.
You can check the if the rate
is !=0
: (the rate can be negative if the player goes backwards)
if vidPlayer != nil && vidPlayer.rate != 0 {
println("playing")
}
AVPlayer class reference