I am looping a video within my avfoundation video player:
NSString *loopPath = @"SubView/introCycle";
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:loopPath withExtension:@"mp4"];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
NSString *tracksKey = @"tracks";
[asset loadValuesAsynchronouslyForKeys:@[tracksKey] completionHandler:^{
// The completion block goes here.
//NSLog(@"asset loaded asynchronously completed!");
// Completion handler block.
dispatch_async(dispatch_get_main_queue(),
^{
NSError *error;
AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error];
if (![self avPlayer] && status == AVKeyValueStatusLoaded) {
if(![self playerItem]){
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
[self.playerItem addObserver:self forKeyPath:@"status" options:0 context:AVMoviePlayerViewControllerStatusObservationContext];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.avPlayer currentItem]];
}
self.avPlayer = [AVPlayer playerWithPlayerItem:self.playerItem];
[self.VideoLoopView setPlayer:self.avPlayer];
}
else {
// You should deal with the error appropriately.
NSLog(@"The asset's tracks were not loaded:\n%@", [error localizedDescription]);
}
});
}];
at the end of the loop the following method restarts the video
int countRounds = 0;
- (void)playerItemDidReachEnd:(NSNotification *)notification {
*//block 1 - this is what we like*
if (notification.object == self.playerItem) {
countRounds++;
[self.playerItem seekToTime:kCMTimeZero];
[self.avPlayer play];
}
}
*// block 2 - this we don't like*
else {
NSInteger reason = [[notification.userInfo objectForKey:AVPlayerItemDidPlayToEndTimeNotification] integerValue];
NSLog(@"reason: %i", reason);
}
NSLog(@"playerItemDidReachEnd, starting round %i", countRounds);
}
which works fine. only block 1 is executed. log shows
MainView did load
playerItemDidReachEnd, starting round 1
playerItemDidReachEnd, starting round 2
...
I then load another view and come back to the video loop view. when I leave the main view I do
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.avPlayer currentItem]];
[self.avPlayer pause];
self.avPlayer = nil;
self.playerItem = nil;
[super viewDidDisappear:animated];
NSLog(@"MainView DidDisappear");
}
when I reload the mainview the video is reloaded and the loop is playing well. but now at the end of the loop both block 1 and block 2 are executed, logging
MainView did load (from old log above)
playerItemDidReachEnd, starting round 1 *(from old log above)*
playerItemDidReachEnd, starting round 2 *(from old log above)*
MainView DidDisappear *(leaving the main view and loading a new one)*
MainView did load *(coming back to main view)*
reason: 0 *(block 2 is executed, triggered by what exactly? WHERE DOES THIS COME FROM?)*
playerItemDidReachEnd, starting round 2
playerItemDidReachEnd, starting round 3 *(this comes from block 1 - we like)*
reason: 0
playerItemDidReachEnd, starting round 3
playerItemDidReachEnd, starting round 4
reason: 0
playerItemDidReachEnd, starting round 4
playerItemDidReachEnd, starting round 5
so at the end of the loop the playerItemDidReachEnd-method is triggered twice. why is that? where does this come from?
You can avoid triggering from the wrong notificator by using