web-dev-qa-db-fra.com

iOS 7 AVPlayer AVPlayer La durée de l'item est incorrecte dans iOS 7

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>
28
Matt Wolfe

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.

50
Matt Wolfe

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]);
27
Derek Li

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 ;-)

5
Ja͢ck

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
}
0
Trzy Gracje