Подтвердить что ты не робот

IOS 7 AVPlayer AVPlayerItem длительность, некорректная в iOS 7

В моем приложении есть следующий код:

NSURL *url = [NSURL fileURLWithPath: [self.DocDir stringByAppendingPathComponent: self.FileName] isDirectory: NO];
self.avPlayer = [AVPlayer playerWithURL: url];

Float64 duration = CMTimeGetSeconds(self.avPlayer.currentItem.duration);

Это отлично работает с iOS 6, но с iOS 7 почему-то возвращает NaN. При проверке self.avPlayer.currentItem.duration объект CMTime имеет 0 с флагом 17.

Интересно, что плеер отлично работает, просто продолжительность не соответствует.

Кто-нибудь еще испытывал те же проблемы? Я импортирую следующее:

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <CoreMedia/CoreMedia.h>
#import <AVFoundation/AVAsset.h>
4b9b3361

Ответ 1

После игры с различными способами инициализации объектов я пришел к рабочему решению:

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

Похоже, что значение продолжительности не всегда доступно сразу из AVPlayerItem, но похоже, что он работает отлично с AVAsset сразу.

Ответ 2

В iOS 7 для уже созданного AVPlayerItem вы также можете получить длительность от подстилающего актива:

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

Вместо того, чтобы получать его непосредственно из AVPlayerItem, который дает вам NaN:

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

Ответ 3

Рекомендуемый способ сделать это, как описано в руководстве, это наблюдать за статусом предмета игрока:

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

Затем внутри 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);
        // ...
    }
}

Также убедитесь, что вы удаляете наблюдателя при смене элемента игрока:

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

Кстати, вы также можете наблюдать свойство duration напрямую; однако, по моему личному опыту, результаты не настолько надежны, как следовало бы ;-)

Ответ 4

Вы можете получить продолжительность по-другому:

private func getVideoDuration(for videoUrl: URL) -> Double {
    let asset = AVAsset(url: videoUrl)
    let duration = asset.duration
    let durationSeconds = CMTimeGetSeconds(duration)
    return durationSeconds
}

Ответ 5

Swift версия

Вы можете получить продолжительность, используя AVAsset который является свойством AVPlayerItem:

func getVideoDuration(from player: AVPlayer) -> Double? {
    guard let duration = player.currentItem?.asset.duration else { return nil }
    let durationSeconds = CMTimeGetSeconds(duration)
    return durationSeconds
}

или создав AVAsset с нуля:

func getVideoDuration(for videoUrl: URL) -> Double {
    let asset = AVAsset(url: videoUrl)
    let duration = asset.duration
    let durationSeconds = CMTimeGetSeconds(duration)
    return durationSeconds
}