アプリに次のコードがあります。
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>
オブジェクトを初期化するさまざまな方法を試した後、実用的なソリューションにたどり着きました。
AVURLAsset *asset = [AVURLAsset assetWithURL: url];
Float64 duration = CMTimeGetSeconds(asset.duration);
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset: asset];
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem: item];
期間の値がAVPlayerItemからすぐに利用できるとは限らないようですが、AVAssetですぐに正常に動作するようです。
IOS 7では、すでに作成されているAVPlayerItemの場合、下にあるアセットから期間を取得することもできます。
CMTimeGetSeconds([[[[self player] currentItem] asset] duration]);
NaVを与えるAVPlayerItemから直接取得する代わりに:
CMTimeGetSeconds([[[self player] currentItem] duration]);
マニュアル で説明されている、これを行うための推奨方法は、プレーヤーのアイテムのステータスを監視することです。
[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
プロパティを直接監視することもできます。ただし、結果が期待どおりに信頼できないのは私の個人的な経験です;-)
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
}