J'ai le code suivant dans mon application:
NSURL *url = [NSURL fileURLWithPath: [self.DocDir stringByAppendingPathComponent: self.FileName] isDirectory: NO];
self.avPlayer = [AVPlayer playerWithURL: url];
Float64 duration = CMTimeGetSeconds(self.avPlayer.currentItem.duration);
Cela a bien fonctionné avec iOS 6 mais avec iOS 7 pour une raison quelconque, il renvoie NaN. Lors de l'inspection de self.avPlayer.currentItem.duration, l'objet CMTime a un 0 avec un indicateur de 17.
Fait intéressant, le joueur fonctionne bien, juste la durée est incorrecte.
Quelqu'un d'autre a-t-il rencontré les mêmes problèmes? J'importe les éléments suivants:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <CoreMedia/CoreMedia.h>
#import <AVFoundation/AVAsset.h>
Après avoir joué avec différentes façons d'initialiser les objets, je suis arrivé à une solution de travail:
AVURLAsset *asset = [AVURLAsset assetWithURL: url];
Float64 duration = CMTimeGetSeconds(asset.duration);
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset: asset];
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem: item];
Il semble que la valeur de la durée ne soit pas toujours immédiatement disponible à partir d'un AVPlayerItem, mais elle semble fonctionner correctement avec un AVAsset immédiatement.
Dans iOS 7, pour AVPlayerItem déjà créé, vous pouvez également obtenir la durée de l'actif sous-jacent:
CMTimeGetSeconds([[[[self player] currentItem] asset] duration]);
Au lieu de l'obtenir directement auprès d'AVPlayerItem, ce qui vous donne un NaN:
CMTimeGetSeconds([[[self player] currentItem] duration]);
La façon recommandée de le faire, comme décrit dans le manuel est d'observer l'état de l'élément du joueur:
[self.avPlayer.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial context:nil];
Ensuite, à l'intérieur 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);
// ...
}
}
Assurez-vous également que vous supprimez l'observateur lorsque vous changez l'élément du joueur:
if (self.avPlayer.currentItem) {
[self.avPlayer.currentItem removeObserver:self forKeyPath:@"status"];
}
Btw, vous pouvez également observer directement la propriété duration
; cependant, c'est mon expérience personnelle que les résultats ne sont pas aussi fiables qu'ils devraient l'être ;-)
version Swift
Vous pouvez obtenir la durée en utilisant AVAsset
qui est la propriété AVPlayerItem
:
func getVideoDuration(from player: AVPlayer) -> Double? {
guard let duration = player.currentItem?.asset.duration else { return nil }
let durationSeconds = CMTimeGetSeconds(duration)
return durationSeconds
}
ou en créant AVAsset
à partir de zéro:
func getVideoDuration(for videoUrl: URL) -> Double {
let asset = AVAsset(url: videoUrl)
let duration = asset.duration
let durationSeconds = CMTimeGetSeconds(duration)
return durationSeconds
}