AVPlayer在UIImagePickerController播放前无法播放视频

3
我遇到了一个问题,但在这里还没有看到类似的帖子。我有一个AVPlayerViewController,它根据来自我的Firebase Database(而不是Storage)的路径播放视频。视频按照我想要的方式完美地播放,但只有当我在应用程序的其他位置观看被点击的UIImagePickerController中的视频时才会如此。
例如,AVPlayer将显示黑色背景(所有AVPlayer都会出现这种情况),除非我从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()
    }
}

}

你的问题只是当尝试从Firebase存储加载视频路径时,AVPlayer会显示黑色背景。否则,播放器可以从UIImagePickerViewController中选择视频并正常播放。我认为我是正确的吧? - Ram
@Ram 视频路径可以正常工作,但只有在我从UIImagePickerViewController中选择一个视频之后,在应用程序的其他地方才会播放。因此,我在选择器中选择的视频与我想观看的视频完全无关,但好像我必须观看选择器中的视频(我可以在开始后单击取消,然后一切都正常工作),才能使AVPlayer正常工作。这有意义吗?这非常奇怪。 - Jaqueline
@Ram 是的,AVPlayer会显示黑屏,但是一旦我从UIImagePickerViewController中选择一个视频,然后返回到我的AVPlayer,它就不再是黑屏了,而是显示我想要展示的视频(与图像选择器中选择的视频无关)。好像在选择选择器中的视频会启动或加载AVPlayer并允许其显示视频,即使我想观看的视频路径相同。这样说清楚了吗? - Jaqueline
@Jaqueline,你能添加视频或GIF吗?我们需要更好地理解问题。 - a.masri
2个回答

0
你有检查子控制器视图的大小吗?
playerController!.view.frame = view.frame 

把它放进去

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        playerController!.view.frame = view.frame
    }

或者使用约束。


0
问题在于当您的视图出现时,它可能还没有准备好进行播放。为了正确处理这个问题,您应该对播放器进行KVO以确保它已经准备好播放。
我之前在类似的问题中回答过这个问题: 使用HLS视频时,AVPlayerViewController和AVPlayer仅在iOS 13上存在视频播放问题
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.
        }
    }
}

您可以在此处找到有关此文档的苹果公司文档: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.
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接