AVPlayer не воспроизводит видео, пока не будет воспроизведено видео из UIImagePickerController.

У меня возникла проблема, о которой я не видел подобного сообщения здесь. У меня есть AVPlayerViewController, который воспроизводит видео на основе пути из моей базы данных Firebase (не хранилища). Видео воспроизводится идеально, как я и хочу, но только один раз, когда я смотрю видео, на которое нажимают в UIImagePickerController в другом месте приложения.

Так, например, AVPlayer будет показывать черный фон (это происходит со всеми AVPlayer's в приложении), за исключением случаев, когда я смотрю видео из UIImagePickerController, которое не имеет ничего общего ни с одним из других представлений. Я понятия не имею, с чего начать. Я ценю всю вашу помощь и предложения!

Вот пример кода моего AVPlayerViewController:

import UIKit
import AVFoundation
import AVKit

class VideoView: UIViewController {

private var videoURL: URL
var player: AVPlayer?
var playerController : AVPlayerViewController?

init(videoURL: URL) {
    self.videoURL = videoURL
    super.init(nibName: nil, bundle: nil)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.gray
    player = AVPlayer(url: videoURL)
    playerController = AVPlayerViewController()

    guard player != nil && playerController != nil else {
        return
    }
    playerController!.showsPlaybackControls = false

    playerController!.player = player!
    self.addChild(playerController!)
    self.view.addSubview(playerController!.view)
    playerController!.view.frame = view.frame
    NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player!.currentItem)

    let cancelButton = UIButton(frame: CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0))
    cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControl.State())
    cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside)
    view.addSubview(cancelButton)


    // Allow background audio to continue to play
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
    } catch let error as NSError {
        print(error)
    }

    do {
        try AVAudioSession.sharedInstance().setActive(true)
    } catch let error as NSError {
        print(error)
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    player?.play()
}

@objc func cancel() {
    dismiss(animated: true, completion: nil)
}

@objc fileprivate func playerItemDidReachEnd(_ notification: Notification) {
    if self.player != nil {
        self.player!.seek(to: CMTime.zero)
        self.player!.play()
    }
}

}

person Jaqueline    schedule 16.03.2020    source источник
comment
Таким образом, ваша проблема заключается только в AVPlayer will show a black background при попытке загрузить путь к видео из хранилища Firebase. В противном случае плеер играет хорошо, выберите видео из UIImagePickerViewController/ Я думаю, что я прав?   -  person Ram    schedule 17.03.2020
comment
@Ram, путь к видео работает, но воспроизводится только после того, как в другом месте приложения я выбираю видео из UIImagePickerViewController. Таким образом, видео, которое я выбираю в средстве выбора, совершенно не связано с тем, которое я хочу посмотреть, но это похоже на то, что я должен смотреть средство выбора (я могу нажать кнопку «Отмена» после его запуска, и все работает), чтобы заставить AVPlayer работать. Имеет ли это смысл? Это очень странно.   -  person Jaqueline    schedule 17.03.2020
comment
@Ram да, так что AVPlayer показывает черный экран, но как только я выбираю видео из UIImagePickerViewController, а затем возвращаюсь к моему AVPlayer, это больше не черный экран и показывает видео, которое я хотел показать (не связанное с выбранным тогда подборщик изображений). Это как если бы выбор видео в средстве выбора запускал или загружал AVPlayer и позволял ему показывать видео, даже если путь для видео, которое я хочу посмотреть, тот же. Это имеет больше смысла?   -  person Jaqueline    schedule 21.03.2020
comment
@ Жаклин, можешь добавить видео или гифку, нам нужно больше понять проблему?   -  person a.masri    schedule 29.03.2020


Ответы (2)


Вы проверили размер представления дочернего контроллера?

playerController!.view.frame = view.frame 

Положите это в

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        playerController!.view.frame = view.frame
    }

или использовать ограничения.

person isHidden    schedule 30.03.2020

Проблема в том, что когда появляется ваше представление, оно может быть не готово к воспроизведению. Что вы должны сделать, чтобы правильно справиться с этим, так это KVO на плеере, чтобы убедиться, что он готов к игре.

Я ответил на это раньше здесь для аналогичного вопроса:

Только проблемы с воспроизведением видео в iOS 13 с AVPlayerViewController и AVPlayer при использовании видео HLS

playerItem.addObserver(self,
                           forKeyPath: #keyPath(AVPlayerItem.status),
                           options: [.old, .new],
                           context: &playerItemContext)


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
        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayerItemStatus(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }

        // Switch over status value
        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.
        }
    }
}

Вы можете найти документацию об этом от Apple здесь: https://developer.apple.com/documentation/avfoundation/media_assets_playback_and_editing/responding_to_playback_state_changes

Другой пример использования здесь:

        playerItem?.observe(\AVPlayerItem.status, options: [.new, .initial]) { [weak self] item, _ in
            guard let self = self else { return }
            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.
        }
person Lunarchaos42    schedule 01.04.2020