【问题标题】:AVPlayer videos not loading all the timeAVPlayer 视频一直没有加载
【发布时间】:2020-05-19 17:25:57
【问题描述】:

我的应用程序使用 AVPlayer 播放我的视频,但它们并非每次都播放。我只是在某些视频上出现黑屏。但是,不播放的视频每次都不相同。我不明白为什么前一分钟有效,而下一分钟却无效。我正在使用HCVimeoVideoExtractor 从 Vimeo 中提取视频。

import UIKit
import HCVimeoVideoExtractor
import Foundation
import AVKit
import AVFoundation

class Arms : UITableViewController{

    @IBOutlet var Tableview: UITableView!

    //video outlet
    let playerController = AVPlayerViewController()

    //@IBOutlet var mypic: UIImageView!

    let sectionName = ["Day 0","Day 1","Day 2","Day 3","Day 4","Day 5","Day 6","7"]

    let foodTitleArray = ["1 and a Half Cable Bicep Curl", "Barbell Bicep Curls", "Cable Bicep Curl","Dumbbell Bicep Curl","Bench Press Close Grip","Across The Body Tricep Extension","EZ Bar Curl", "Dumbbell Hammer Curl", "Low Pulley Cable Curl", "Preacher Curl Machine", "Skull Crusher", "Straight Bar Tricep Extension", "Rope Tricep Extension"]

    let foodImageArray = ["Bicep Curl 1 and half Cable", "Bicep Curl Barbell", "Bicep Curl Cable","Bicep Curl Dumbbell","Close Grip Bench Press","Cross body tricep extension","EZ Bar Curl", "Hammer Curl Dumbbell", "Low Cable Pulley Curl", "Preacher Curl Machine", "Skull Crusher", "Tricep extension Cable", "Tricep Extension rope"]


    var rowselected = Int()


    //-----vids-----
    //video links
    var calledVideo: String?

    let vids = ["https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345","https://vimeo.com/12345", "https://vimeo.com/12345", "https://vimeo.com/12345", "https://vimeo.com/12345"]
    //-----vids-----


    override func viewDidLoad() {
        super.viewDidLoad()
    }


    @IBAction func Back(_ sender: Any) {

        NotificationCenter.default.removeObserver(self)

        self.dismiss(animated: true, completion: nil)
    }


    //setting up tableview rows
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //return sectionName.count
        return foodTitleArray.count
    }


    //what cell is & how it looks
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = Tableview.dequeueReusableCell(withIdentifier: "cellarms") as! UITableViewCell1


        // cell.foodImage.image = UIImage(named: foodImageArray[indexPath.row] + ".jpg") //this is origionally how memory images are used added to cell. this way caches the images building memory.
        cell.foodTitle.text = foodTitleArray[indexPath.row] //this is how to the uitableviews titles are added to cells

        //shows the images in cells without storing image in cache
        let bundlePath = Bundle.main.path(forResource: foodImageArray[indexPath.row], ofType: "jpg")
        let image = UIImage(contentsOfFile: bundlePath!)
        cell.foodImage.image = image

        return (cell)
    }


    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        rowselected = indexPath.row

        //indexpath.row is the code to get a number of the row selected this number then is selected from vids array and sets calledvideo to this number.
        print(indexPath.row)
        let number = indexPath.row
        calledVideo = vids[number]
        print(calledVideo)
        geturl()


        //making desleected row not highlighted
        tableView.deselectRow(at: indexPath, animated: true)
    }

    //Getting url info for video by using exractor
    func geturl() {
        if let url = URL(string: calledVideo!) {
            HCVimeoVideoExtractor.fetchVideoURLFrom(url: url, completion: { ( video:HCVimeoVideo?, error:Error?) -> Void in
                if let err = error {
                    DispatchQueue.main.async() {
                        let alert = UIAlertController(title: "Error", message: err.localizedDescription, preferredStyle: .alert)
                        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                        self.present(alert, animated: true, completion: nil)
                    }
                    return
                }


                guard let vid = video else {
                    print("Invalid video object")
                    return
                }



                //play video
                let player = AVPlayer(url: vid.videoURL[.Quality360p]!)
                self.playerController.player = player
                self.present(self.playerController, animated: true) {
                    player.play()
                }
            })   
        }
    }
}

它是一个不同的视频,每次我都被取消。它似乎是完全随机的。以下是我在取消视频时发生的错误示例:

Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://gcs-vimeo.akamaized.net/exp=1581445783~acl=%2Fvimeo-prod-skyfire-std-us%2F01%2F3120%2F14%2F365604762%2F1507711789.mp4~hmac=ac26b711525132b93ce5b4c33db5f04efc84feab53f3c07ec324d15962a9f5dd/vimeo-prod-skyfire-std-us/01/3120/14/365604762/1507711789.mp4?source=1, NSErrorFailingURLKey=https://gcs-vimeo.akamaized.net/exp=1581445783~acl=%2Fvimeo-prod-skyfire-std-us%2F01%2F3120%2F14%2F365604762%2F1507711789.mp4~hmac=ac26b711525132b93ce5b4c33db5f04efc84feab53f3c07ec324d15962a9f5dd/vimeo-prod-skyfire-std-us/01/3120/14/365604762/1507711789.mp4?source=1, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <A7D7517F-1F77-495B-80A1-2F61FE5B723D>.<1>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <A7D7517F-1F77-495B-80A1-2F61FE5B723D>.<1>, NSLocalizedDescription=cancelled} [-999]

【问题讨论】:

    标签: ios swift avplayer vimeo


    【解决方案1】:

    首先,您应该在打印“无效视频对象”时显示警报,以便用户也可以获取此信息。

    您尝试流式传输视频。有时这可能会立即开始,但大多数情况下玩家需要一些时间来缓冲前几秒才能开始游戏。

    你需要观察你的玩家currentItem的status。这将向您显示您的播放器正在做什么,如果它正在加载、加载失败或准备就绪。当状态变为“readyToPlay”时,您可以致电playerController.play()

    如何观察此属性如下所示: https://stackoverflow.com/a/47787854

    编辑:观察者实现
    在你的 ViewController 类中声明这个变量:

    var observer: NSKeyValueObservation? {
        willSet {
            guard let observer = observer else { return }
            observer.invalidate()
        }
    }
    

    替换此代码:

    //play video
    let player = AVPlayer(url: vid.videoURL[.Quality360p]!)
    self.playerController.player = player
    self.present(self.playerController, animated: true) {
        player.play()
    }
    

    以下:

    let url = vid.videoURL[.Quality360p]!
    // Create asset to be played
    let 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
    let playerItem = AVPlayerItem(asset: asset,
                              automaticallyLoadedAssetKeys: assetKeys)
    
    // Associate the player item with the player
    let player = AVPlayer(playerItem: playerItem)
    self.playerController.player = player
    
    // Register as an observer of the player item's status property
    self.observer = playerItem.observe(\.status, options:  [.new, .old], changeHandler: { (playerItem, change) in
        if playerItem.status == .readyToPlay {
            self.present(self.playerController, animated: true) {
                player.play()
            }
        }
    })
    

    【讨论】:

    • 我似乎无法让您的方法发挥作用。我已经更新了我的答案,并举例说明了为我加载视频凹痕时出现的错误。
    • 我将更新我的答案以展示如何在您的案例中实施观察
    • 这会导致在player.play() 没有解析标识符player
    • 当然,抱歉.. 更新:播放器现在在观察块之前初始化
    • @pete800 你有进步吗?
    【解决方案2】:

    当您滚动tableview 时,您的链接已更改。滚动后检查您的url。如果一切正常,请尝试下面的代码。

    快速:

    let url = URL(string: "https://vimeo.com/254597739")!
    HCVimeoVideoExtractor.fetchVideoURLFrom(url: url, completion: { ( video:HCVimeoVideo?, error:Error?) -> Void in                
        if let err = error {                    
           print("Error = \(err.localizedDescription)")                    
           return
        }
    
        guard let vid = video else {
            print("Invalid video object")
            return
        }
    
        print("Title = \(vid.title), url = \(vid.videoURL), thumbnail = \(vid.thumbnailURL)")
    
        if let videoURL = vid.videoURL[.Quality540p] {
            let player = AVPlayer(url: videoURL)
            let playerController = AVPlayerViewController()
            playerController.player = player
            self.present(playerController, animated: true) {
                player.play()
            }
        }                            
    })
    

    【讨论】:

    • 我似乎无法让您的方法发挥作用。我已经更新了我的答案,其中举例说明了为我加载视频凹痕时出现的错误。
    • @pete800 我认为是tableview 滚动问题,当您滚动项目时,您的链接不匹配!
    • @pete800 如果你有section 并且你的链接是从section 生成的,点击你的号码应该是indexPath.section。请附上您应用的屏幕截图。
    【解决方案3】:

    代码不能按原样测试,所以只能通过心理分析......

    代码的修改部分在您的//play video 评论之后。它需要显式转发 UI 操作并连接到主线程:

    //play video
    DispatchQueue.main.async {
        let player = AVPlayer(url: vid.videoURL[.Quality360p]!)
        self.playerController.player = player
        self.present(self.playerController, animated: true) {
            player.play()
        }
    }
    

    【讨论】:

    • 为什么不会导致某些视频加载而其他视频不加载?
    • 如果提取器使用默认全局队列进行处理,它可能有时在主线程中,有时不在。
    • 似乎不太好用。有些仍然加载,有些则没有
    • @pete800,那么它不在提供的代码中,我相信......你是同时播放它们还是一个接一个?您不认为可能存在一些限制或限制,内存或服务器端。
    • @pete800,我已经使用您提供的代码 + 我的修复创建了一个测试项目,并使用在网络中找到的一些免费 Vimeo 视频对其进行了测试......并且所有作品,好吧,几乎 - 唯一的额外我添加的条件是提取的 videoURL 质量,因为这些免费视频具有不同的质量,并且强制展开会引发异常。所以...如果您仍然对我应用的修复有问题,并且您确定 Quality360p 始终出现在您的视频中,那么同样,问题不在提供的代码中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    相关资源
    最近更新 更多