How to stream a video with AVURLAsset and save to disk the cached data

前端 未结 2 512
抹茶落季
抹茶落季 2020-12-13 22:54

Some days ago I was asked to check how difficult is to play a video while downloading it from Internet. I know it\'s an easy task because someone told me a while ago. So, I

相关标签:
2条回答
  • 2020-12-13 23:12

    The team at Calm has open-sourced our implementation to this. It's available as a CocoaPod. It's called PersistentStreamPlayer.

    Features include:

    • streaming of audio file, starting playback as soon as first data is available
    • also saves streamed data to a file URL as soon as the buffer completes exposes timeBuffered, helpful for displaying buffer progress bars in the UI
    • handles re-starting the audio file after the buffer stream stalls (e.g. slow network)
    • simple play, pause and destroy methods (destroy clears all memory resources)
    • does not keep audio file data in memory, so that it supports large files that don't fit in RAM

    You can find it here: https://github.com/calmcom/PersistentStreamPlayer

    0 讨论(0)
  • 2020-12-13 23:15

    The solution for this problem is to use AVAssetExportSession and AVAssetResourceLoaderDelegate:

    First step is to add a notification to know when the video finish. Then we can start saving it to disk.

    override func viewDidLoad() {
    
        super.viewDidLoad()
    
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(playerItemDidReachEnd(_:)), name: AVPlayerItemDidPlayToEndTimeNotification, object: nil)
    
        ...
    }
    
    deinit {
    
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    

    The implementation of our function:

    func playerItemDidReachEnd(notification: NSNotification) {
    
        if notification.object as? AVPlayerItem  == player.currentItem {
    
            let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)
    
            let filename = "filename.mp4"
    
            let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last!
    
            let outputURL = documentsDirectory.URLByAppendingPathComponent(filename)
    
            exporter?.outputURL = outputURL
            exporter?.outputFileType = AVFileTypeMPEG4
    
            exporter?.exportAsynchronouslyWithCompletionHandler({
    
                print(exporter?.status.rawValue)
                print(exporter?.error)
            })
        }
    }
    

    Finally we need to make our AVURLAsset delegate of AVAssetResourceLoaderDelegate:

    lazy var asset: AVURLAsset = {
    
        var asset: AVURLAsset = AVURLAsset(URL: self.url)
    
        asset.resourceLoader.setDelegate(self, queue: dispatch_get_main_queue())
    
        return asset
    }()
    

    And:

    extension ViewController : AVAssetResourceLoaderDelegate {
    
    }
    

    I created a small demo with this code in GitHub.

    0 讨论(0)
提交回复
热议问题