iOS 7 AVPlayer AVPlayerItem duration incorrect in iOS 7

The recommended way of doing this, as described in the manual is by observing the player item status:

[self.avPlayer.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial context:nil];

Then, inside observeValueForKeyPath:ofObject:change:context:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    // TODO: use either keyPath or context to differentiate between value changes
    if (self.avPlayer.currentItem.status == AVPlayerStatusReadyToPlay) {
        Float64 duration = CMTimeGetSeconds(self.avPlayer.currentItem.duration);
        // ...
    }
}

Also, make sure that you remove the observer when you change the player item:

if (self.avPlayer.currentItem) {
    [self.avPlayer.currentItem removeObserver:self forKeyPath:@"status"];
}

Btw, you can also observe the duration property directly; however, it's been my personal experience that the results aren't as reliable as they should be ;-)


In iOS 7, for AVPlayerItem already created, you can also get duration from the underlaying asset:

CMTimeGetSeconds([[[[self player] currentItem] asset] duration]);

Instead of get it directly from AVPlayerItem, which gives you a NaN:

CMTimeGetSeconds([[[self player] currentItem] duration]);

After playing around with different ways of initializing the objects I arrived at a working solution:

AVURLAsset *asset = [AVURLAsset assetWithURL: url];
Float64 duration = CMTimeGetSeconds(asset.duration);
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset: asset]; 
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem: item];

It appears the duration value isn't always immediately available from an AVPlayerItem but it seems to work fine with an AVAsset immediately.