【macOS High Sierra 10.13.5+Xcode 9.3+iPhoneSE(iOS 11.1.2)】
カメラロールからビデオを検索して、AVPlayerで再生するデモを作っていて、ハマったのでメモ。
ビデオの再生して、もう一度同じビデオを再生しようとするとエラーになってアプリが落ちてしまうという現象に遭遇。表示されるエラーがこちら。
1 | 'NSInvalidArgumentException' , reason: 'An AVPlayerItem cannot be associated with more than one instance of AVPlayer' |
翻訳すると「AVPlayerItemを複数のAVPlayerインスタンスに関連付けることはできません」とのこと
何のことか理解できずにいろいろ試してみたところ、AVPlayerItemをそのままAVPlayerに使ってはいけないらしい。
・エラーになったコード(AVPlayerItemをそのままAVPlayerに渡す)
1 2 3 4 5 6 7 8 9 10 11 12 | var avPlayerItem: AVPlayerItem! var player:AVPlayer! var playerItem:AVPlayerItem? var playerController:AVPlayerViewController? func initItem(item:AVPlayerItem) { playerItem = item player = AVPlayer(playerItem:playerItem) playerController = AVPlayerViewController() playerController?.player = player } |
・正しく動いたコード1(AVPlayerItemをurlで初期化して、AVPlayerに渡す)
1 2 3 4 5 6 7 8 9 10 11 12 | var avPlayerItem: AVPlayerItem! var player:AVPlayer! var playerItem:AVPlayerItem? var playerController:AVPlayerViewController? func initItem(item:AVPlayerItem) { playerItem = AVPlayerItem.init(url: (item.asset.value(forKey: "URL" ) as! NSURL ) as URL) player = AVPlayer(playerItem:playerItem) playerController = AVPlayerViewController() playerController?.player = player } |
・正しく動いたコード2(AVPlayerItemをassetで初期化して、AVPlayerに渡す)
1 2 3 4 5 6 7 8 9 10 11 12 | var avPlayerItem: AVPlayerItem! var player:AVPlayer! var playerItem:AVPlayerItem? var playerController:AVPlayerViewController? func initItem(item:AVPlayerItem) { playerItem = AVPlayerItem.init(asset: item.asset) player = AVPlayer(playerItem:playerItem) playerController = AVPlayerViewController() playerController?.player = player } |
もう一つの初期化の方法として、
init(asset: AVAsset, automaticallyLoadedAssetKeys: [String]?)
Initializes a player item with the specified asset and the asset keys to be automatically
てのがあったんだけど、「automaticallyLoadedAssetKeys」がよくわからず割愛。
要するに「AVPlayerに使うAVPlayerItemは何らかの方法で初期化してから渡せ」と理解しました。勘違いがあったらご指摘いただけると喜びます。
【補足】
ちなみにカメラロールから動画を取得する処理はこんな感じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var videos: NSMutableArray ? //カメラロールから動画を読み込む func loadVideos() { //メディアタイプをビデオに絞って取得 let assets:PHFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.video, options: nil ) //取得したアセットを変換 assets.enumerateObjects({(obj, index, stop) -> Void in //PHImageManagerを使ってplayerItemに self .phmov.requestPlayerItem(forVideo: assets[index], options: nil , resultHandler: {(playerItem, info) -> Void in //配列に追加 videos!.add(playerItem!) //最後の処理が終わったらメインスレッドでコレクションビューをリロード if index == assets.count-1{ //終了時に呼び出す処理はココに書く }) }) } |
ボタンが押されたら配列(videos)からAVPlayerItemを取りだして、再生するViewに移動
1 2 3 4 5 6 7 8 9 10 11 12 | @IBAction func tapBtn1(_ sender: UIButton) { gotoViewView(item: videos![0] as! AVPlayerItem) } func gotoViewView(item:AVPlayerItem) { let sb = UIStoryboard.init(name: "Main" , bundle: nil ) let vc = sb.instantiateViewController(withIdentifier: "videoVC" ) as! VideoViewController vc.initItem(item: item) self .present(vc, animated: false , completion: nil ) } |
【参考】
ios – 自作アルバムの動画をAVPlayerで再生するとsignal SIGABRT発生(iPad) – スタック・オーバーフロー
AVPlayerItem – AVFoundation | Apple Developer Documentation