AVPlayerLayer не показывает графику - PullRequest
0 голосов
/ 10 апреля 2020

Я использую AVPlayer и AVPlayerLayer для отображения живого контента HLS. Проблема в том, что AVPlayerLayer - , даже если он отображается на экране и правильно прикреплен как подпредставление , не отображает контент / графику, но вместо этого воспроизводит только аудио . Проблема возникает только на реальном устройстве , но на симуляторе все работает отлично.

При тестировании того же кода с некоторыми другими образцами URL ( .mp4, .m3u8), найденными в inte rnet, он отлично работает как на устройстве, так и на симуляторе.

Для случаев, когда проигрыватель не показывает никакого контента, а только аудио, я использую прямой эфир клиента HLS версии 7, 25 кадров в секунду.

У меня есть сомнения в том, что с момента запуска приложения до появления первого кадра графики (на симуляторе) возникает огромная задержка, вызывающая срыв. Я рассмотрел, добавив automaticallyWaitsToMinimizeStalling к false. Полный пример кода здесь:

import UIKit
import AVFoundation

class PlayerView: UIView {

  private var playerItem: AVPlayerItem?
  private var playerItemContext = 0

  var player: AVPlayer? {
    get { return playerLayer.player }
    set { playerLayer.player = newValue }
  }

  var playerLayer: AVPlayerLayer {
    return layer as! AVPlayerLayer
  }

  override static var layerClass: AnyClass {
    return AVPlayerLayer.self
  }

  func play(with url: URL) {
    setUpAsset(with: url) { [weak self] (asset: AVAsset) in
        self?.setUpPlayerItem(with: asset)
    }
  }

  private func setUpAsset(with url: URL, completion: ((_ asset: AVAsset) -> Void)?) {
    let asset = AVAsset(url: url)
    asset.loadValuesAsynchronously(forKeys: ["playable"]) {
        var error: NSError? = nil
        let status = asset.statusOfValue(forKey: "playable", error: &error)
        switch status {
        case .loaded:
            completion?(asset)
            print("--- Loaded ---")
        case .failed:
            print("--- Failed ---")
        case .cancelled:
            print("--- Cancelled ---")
        default: break
        }
    }
  }

  private func setUpPlayerItem(with asset: AVAsset) {
    playerItem = AVPlayerItem(asset: asset)
    playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.old, .new], context: &playerItemContext)

    DispatchQueue.main.async { [weak self] in
        self?.player = AVPlayer(playerItem: self?.playerItem!)
        self?.player?.automaticallyWaitsToMinimizeStalling = false
    }
  }

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

    if keyPath == #keyPath(AVPlayerItem.status) {
        let status: AVPlayerItem.Status
        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayerItem.Status(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }

        switch status {
        case .readyToPlay: player?.play()
        case .failed: print(".failed")
        case .unknown: print(".unknown")
        @unknown default: print("@unknown default")
        }
    }
  }

  deinit {
    playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status))
  }

}

// MARK: - View Controller -

class ViewController: UIViewController {

 private var playerView: PlayerView!

 @IBOutlet weak var videoView: UIView!

 override func viewDidLoad() {
   super.viewDidLoad()
   self.setUpPlayerView()
   self.playVideo()
 }

 private func setUpPlayerView() {
    playerView = PlayerView()
    playerView.backgroundColor = UIColor.black
    playerView.frame = self.videoView.bounds
    videoView.addSubview(playerView)
 }

 func playVideo() {
    playerView.play(with: url)
 }

}
...