Использование NotificationCenter для чередования файлов видео в AVPlayer

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

Здесь я настроил игрока, активы и предметы игрока:

    //Create URLs
    let movieOneURL: URL = URL(fileURLWithPath: movieOnePath)
    let movieTwoURL: URL = URL(fileURLWithPath: movieTwoPath)

    //Create Assets
    let assetOne = AVAsset(url: movieOneURL)
    let assetTwo = AVAsset(url: movieTwoURL)

    //Create Player Items
    avPlayerItemOne = AVPlayerItem(asset: assetOne)
    avPlayerItemTwo = AVPlayerItem(asset: assetTwo)

    avplayer = AVPlayer(playerItem: avPlayerItemOne)
    let avPlayerLayer = AVPlayerLayer(player: avplayer)
    avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
    avPlayerLayer.frame = UIScreen.main.bounds
    movieView.layer.addSublayer(avPlayerLayer)

    //Config player
    avplayer .seek(to: kCMTimeZero)
    avplayer.volume = 0.0

И здесь я настроил уведомление, чтобы определить, достиг ли проигрыватель конца видеофайла:

    NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: avplayer.currentItem)

... который вызывает этот селектор:

    func playerItemDidReachEnd(_ notification: Notification) {
//        avplayer.seek(to: kCMTimeZero)
        changePlayerAsset()
//        avplayer.play()
    }

... который затем отключит актив:

func changePlayerAsset(){
    if avplayer.currentItem == avPlayerItemOne {
        avplayer.replaceCurrentItem(with: avPlayerItemTwo)
        avplayer.play()

    } else if avplayer.currentItem == avPlayerItemTwo {
        avplayer.replaceCurrentItem(with: avPlayerItemOne)
        avplayer.play()
    }
}

Это отлично работает с первого раза - когда первый фильм закончил воспроизведение, следующий начнет воспроизводиться.

Проблема, с которой я сталкиваюсь, заключается в том, что мой наблюдатель уведомлений, кажется, регистрируется только один раз; в конце первого видео ... уведомление не срабатывает, когда второе видео вообще перестает воспроизводиться.

У кого-нибудь есть идея, почему это так


person narner    schedule 21.12.2016    source источник


Ответы (1)


Причина, по которой ваш обработчик уведомлений не вызывается для второго элемента, заключается в следующем бите, в конце которого вы регистрируете обработчик уведомлений: object: avplayer.currentItem. Обработчик вызывается один раз, когда завершается воспроизведение этого элемента, но затем, когда завершается воспроизведение следующего элемента, уведомление публикуется с другим object — другим элементом, — который не соответствует тому, для чего вы зарегистрировались, и поэтому ваш обработчик не вызывается. Если вы измените object на nil при регистрации обработчика, он будет вызываться по завершении любого элемента, что ближе к тому, что вам нужно.

Тем не менее, это не лучший способ делать то, что вы хотите — ручная замена элементов, вероятно, повлечет за собой затраты и задержку загрузки каждого элемента каждый раз, когда он собирается воспроизвести. Гораздо лучше использовать встроенную функциональность для последовательного воспроизведения видео и их зацикливания, а именно AVQueuePlayer и AVPlayerLooper. В ответе на этот вопрос есть пример того, как использовать оба варианта.

person Noah Witherspoon    schedule 21.12.2016