AVURLAsset(url:, options:) Freeze the Main Thread

56 Views Asked by At

I am using AVQueuePlayer to play the items in a queue in my app. So when there are suppose 10 items to add to queue, I simply use a for loop to add them to queue. Most of the time it works fine but sometimes it freezes the whole app. Thread always hangs here let asset = AVURLAsset(url: url), then freeze

Here is my code -

func loadAssets() {
    let URLS = ["http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4","http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4","http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4","http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4"]
    for urlString in URLS {
        let contentURL = URL(string: urlString)!
        self.createAVAsset(url: contentUrl, completion: ({ [weak self] asset in
            guard let self = self else { return }
            let playerItem = self.createPlayerItemForAsset(asset)
            self.queuePlayer?.insert(playerItem, after: nil)
        }))
    }
}

func createAVAsset(url: URL, completion: @escaping ((AVURLAsset) -> Void)) {
    let asset = AVURLAsset(url: url) /*THREAD HANGS ON THIS LINE*/
    asset.resourceLoader.setDelegate(self, queue: self.queue)
    completion(asset)
}

I have tried many different things in the method createAVAsset but nothing happened also this happens all of a sudden not reproducible each time.

Varients I tried to fix the issue are -

  1. Using background thread - Not working properly
func createAVAsset(url: URL, completion: @escaping ((AVURLAsset) -> Void)) {
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let self = self else { return }
            let asset = AVURLAsset(url: url) /*THREAD HANGS ON THIS LINE*/
            asset.resourceLoader.setDelegate(self, queue: self.queue)
            DispatchQueue.main.async {
                completion(asset)
            }
    }
}
  1. Using loadValuesAsynchronously - Not working properly
func createAVAsset(url: URL, completion: @escaping ((AVURLAsset) -> Void)) {
        let asset = AVURLAsset(url: url) /*THREAD HANGS ON THIS LINE*/
        let keys: [String] = ["playable"]
        //Control doesn't reach below, it hangs on above line already
        asset.loadValuesAsynchronously(forKeys: keys, completionHandler: {
        var error: NSError? = nil
        let status = asset.statusOfValue(forKey: "playable", error: &error)
        switch status {
            case .loaded:
                DispatchQueue.main.async {
                 //do something, show alert, put a placeholder image etc.
                 completion(asset)
                }
            break
            case .failed:
                DispatchQueue.main.async {
                 //do something, show alert, put a placeholder image etc.
                }
            break
            case .cancelled:
                DispatchQueue.main.async {
                //do something, show alert, put a placeholder image etc.
                }
            break
            default:
            break
       }
    })
}
0

There are 0 best solutions below