"AVPlayerItem не может быть связан с более чем одним экземпляром AVPlayer"

Я знаю, что этот вопрос полностью исчерпан Stack Overflow, но, тем не менее, большинство из них старые и не связаны с тем, что я собираюсь здесь задать.

Итак, у меня есть массив с AVPlayerItems и AVQueuePlayer, Сначала я установил AVQueuePlayer для воспроизведения элементов массива:

func mediaPicker(mediaPicker: MPMediaPickerController!, didPickMediaItems mediaItemCollection: MPMediaItemCollection!) {

    mediaItems = mediaItemCollection.items

    for thisItem in mediaItems as [MPMediaItem] {

        var itemUrl = thisItem.valueForProperty(MPMediaItemPropertyAssetURL) as? NSURL
        var playerItem = AVPlayerItem(URL: itemUrl)
        mediaArray.append(playerItem)           

    }

    updateMetadata()

    audioPlayer = AVQueuePlayer(items: mediaArray)


    self.dismissViewControllerAnimated(true, completion: nil)

}

Но когда пользователь, например, добавляет новый элемент или удаляет его, я пытаюсь обновить проигрыватель (так же, как я установил его в первую очередь), но он выдает ошибку. Я хочу знать, есть ли способ обойти это или какое-либо решение. Вот как пользователь удаляет песню:

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == UITableViewCellEditingStyle.Delete{
            mediaArray.removeAtIndex(indexPath.row)
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
            audioPlayer = AVQueuePlayer(items: mediaArray) //here gives the error
        }
    }

Я убиваю себя из-за этого, поэтому, если кто-то может мне помочь, я был бы признателен.

3 ответа

Проблема в том, что вы создаете новый объект проигрывателя при обновлении массива элементов с помощью этой строки (в tableView:commitEditingStyle:forRowAtIndexPath:),

audioPlayer = AVQueuePlayer(items: mediaArray)

Кажется, что предметы игрока все еще связаны с оригинальным игроком, когда вы делаете это. Вы должны иметь возможность удалить эту строку, чтобы она работала правильно. Вставки или удаления элементов из mediaArray должно быть достаточно, чтобы делать то, что вы хотите; вам не нужно создавать нового игрока.

То, как я решил эту проблему, это то, что я сохранил ссылку на AVAsset объекты в массиве, а затем mapпед это [AVPlayerItem] (тип, который AVQUeuePlayer init принимает).

Чтобы уточнить, нам нужно было сделать аудио-рекордер ( код на GitHub), который может быть приостановлен, поэтому я использовал AVQueuePlayer, но столкнулся с теми же проблемами, что и OP, и единственное чистое решение - воссоздать этот объект проигрывателя с новым массивом.

Соответствующий код в Swift 4.1:

class RecordViewController: UIViewController {

    var audioRecorder: AVAudioRecorder?

    var audioChunks = [AVURLAsset]()
    var queuePlayer:  AVQueuePlayer?

// irrelevant code omitted

    func stopRecorder() {
        self.audioRecorder?.stop()
        let assetURL  = self.audioRecorder!.url

        self.audioRecorder = nil

        let asset = AVURLAsset(url: assetURL)
        self.audioChunks.append(asset)

        let assetKeys = ["playable"]
        let playerItems = self.audioChunks.map {
            AVPlayerItem(asset: $0, automaticallyLoadedAssetKeys: assetKeys)
        }

        self.queuePlayer = AVQueuePlayer(items: playerItems)
        self.queuePlayer?.actionAtItemEnd = .advance
    }

    func startPlayer() {
        self.queuePlayer?.play()
    }

    func stopPlayer() {
        self.queuePlayer?.pause()
        self.queuePlayer = nil
    }
}

(В конце, AVAssetExportSession используется для сшивания фрагментов аудио вместе, поэтому хранение AVAssetсундук с AVPlayerItemв конце концов, было еще выгоднее.)

Использование этого кода решило для меня проблему:

player?.pause()                     
let playerItem = AVPlayerItem(asset: myAsset) 
player = nil 
player = AVPlayer()
player?.replaceCurrentItem(with: playerItem)

Вместо того:

player?.pause()                     
player = nil player = AVPlayer()
player?.replaceCurrentItem(with: availablePlayerItem) //
availablePlayerItem is a playerItem which has been created before and
played once with this AVPlayer

Примечание. В обоих кодах "player" - это глобальная переменная в моем классе:

var player: AVPlayer? = ноль

Из документации Apple:

Прежде чем добавить элемент:

canInsertItem(_:afterItem:)

Возвращает логическое значение, которое указывает, может ли данный элемент игрока быть вставлен в очередь игрока.

func canInsertItem(_ item: AVPlayerItem!, afterItem afterItem: AVPlayerItem!) -> Bool

Добавление предмета:

insertItem(_:afterItem:)

Размещает данный предмет игрока после указанного предмета в очереди.

 func insertItem(_ item: AVPlayerItem!, afterItem afterItem: AVPlayerItem!)

Удаление предмета:

removeItem(_:)

Удаляет данный предмет игрока из очереди.

func removeItem(_ item: AVPlayerItem!)

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

if player.canInsert(playerItem, after: nil) == true {

            player = AVQueuePlayer(playerItem: playerItem)

        } else {

            player.remove(self.playerItem)

            player.replaceCurrentItem(with: playerItem)
}

Сначала я инициализировал AVPlayerItem внутри ячейки и добавил его в AVPlayer (также внутри ячейки). Позже я представил новый виртуальный компьютер и передал AVPlayerItem той же ячейки другому AVPlayer внутри нового виртуального канала и получил сбой. Чтобы исправить это, я просто сделал копию playerItem, используя.copy() as? AVPlayerItem. Копия дает новой копии адрес памяти, отличный от адреса оригинала.

ячейка:

var cellPlayer: AVPlayer?
var cellsPlayerItem: AVPlayerItem?

cellsPlayerItem = AVPlayerItem(asset: AVAsset(url: url)) // cellsPlayerItem's memory address 0x1111111
cellPlayer = AVPlayer(playerItem: cellsPlayerItem!)

представлены vc:

var vcPlayer: AVPlayer?

let playerItemCopy = cellsPlayerItem.copy() as? AVPlayerItem // playerItemCopy's memory address 0x2222222
let vcPlayer = AVPlayer(playerItem: playerItemCopy)
Другие вопросы по тегам