iOS - получение текущего состояния AVPlayer(Item)

Я ищу окончательный ответ, как получить текущий AVPlayer/AVPlayerItem состояние на iOS 9 и выше. Проще говоря, пусть они будут состояниями стиля Google ExoPlayer:

  • простаивает (нет носителя или ошибка)

  • буферизация (видео на самом деле не воспроизводится / не продвигается и ожидает больше данных)

  • воспроизведение (видео фактически воспроизводится / продвигается)

  • завершено (видео закончено, воспроизведение до конца)

Обратите внимание, что на данный момент я не ищу способ отслеживания изменений состояния (посредством уведомлений, наблюдения KVO или других средств), просто состояние в текущий момент времени. Рассмотрим следующий псевдокод:

typedef enum : NSUInteger {
    PlayerStateIdle,
    PlayerStateBuffering,
    PlayerStatePlaying,
    PlayerStateCompleted
} PlayerState;

+ (PlayerState)resolvePlayerState:(AVPlayer*)player {
    // Magic code here
}

Стены, до сих пор я бился головой:

  • timeControlStatus доступно с iOS 10 и выше

  • playbackBufferEmpty всегда верно

  • playbackBufferFull всегда ложно

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

1 ответ

Согласно документации

Вы можете использовать наблюдение значения ключа, чтобы наблюдать за этими изменениями состояния по мере их возникновения. Одним из наиболее важных свойств предмета игрока является его статус. Статус показывает, готов ли элемент для воспроизведения и доступен ли он для использования.

Для настройки наблюдения:

func prepareToPlay() {
    let url = <#Asset URL#>
    // Create asset to be played
    asset = AVAsset(url: url)

    let assetKeys = [
        "playable",
        "hasProtectedContent"
    ]
    // Create a new AVPlayerItem with the asset and an
    // array of asset keys to be automatically loaded
    playerItem = AVPlayerItem(asset: asset,
                              automaticallyLoadedAssetKeys: assetKeys)

    // Register as an observer of the player item's status property
    playerItem.addObserver(self,
                           forKeyPath: #keyPath(AVPlayerItem.status),
                           options: [.old, .new],
                           context: &playerItemContext)

    // Associate the player item with the player
    player = AVPlayer(playerItem: playerItem)
}

Обрабатывать:

override func observeValue(forKeyPath keyPath: String?,
                           of object: Any?,
                           change: [NSKeyValueChangeKey : Any]?,
                           context: UnsafeMutableRawPointer?) {
    // Only handle observations for the playerItemContext
    guard context == &playerItemContext else {
        super.observeValue(forKeyPath: keyPath,
                           of: object,
                           change: change,
                           context: context)
        return
    }

    if keyPath == #keyPath(AVPlayerItem.status) {
        let status: AVPlayerItemStatus

        // Get the status change from the change dictionary
        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayerItemStatus(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }

        // Switch over the status
        switch status {
        case .readyToPlay:
        // Player item is ready to play.
        case .failed:
        // Player item failed. See error.
        case .unknown:
            // Player item is not yet ready.
        }
    }
}

Не уверен, в чем твоя проблема.

Вы можете просто получить доступ к player.status или player.timeControlStatus и вернуть результат, соответствующий вашему ENUM

Это то, что вы имели ввиду?

Другие вопросы по тегам