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

烂漫一生 提交于 2019-11-27 11:23:25

问题


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 checked and it was super easy.

The problem was that I wanted to save to disk the video to do not force the user to download it again and again.

The problem was to access the buffer and store it to disk.

Many answers in Stackoverflow says it is nor possible. Specially with videos.

My original code to play the video:

import AVFoundation

....

//MARK: - Accessors

lazy var player: AVPlayer = {

    var player: AVPlayer = AVPlayer(playerItem: self.playerItem)

    player.actionAtItemEnd = AVPlayerActionAtItemEnd.None

    return player
}()

lazy var playerItem: AVPlayerItem = {

    var playerItem: AVPlayerItem = AVPlayerItem(asset: self.asset)

    return playerItem
}()

lazy var asset: AVURLAsset = {

    var asset: AVURLAsset = AVURLAsset(URL: self.url)

    return asset
}()

lazy var playerLayer: AVPlayerLayer = {

    var playerLayer: AVPlayerLayer = AVPlayerLayer(player: self.player)

    playerLayer.frame = UIScreen.mainScreen().bounds
    playerLayer.backgroundColor = UIColor.clearColor().CGColor

    return playerLayer
}()

var url: NSURL = {

    var url = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")

    return url!
}()

//MARK: - ViewLifeCycle

override func viewDidLoad() {

    super.viewDidLoad()

    view.layer.addSublayer(playerLayer)

    player.play()
}

回答1:


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.




回答2:


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



来源:https://stackoverflow.com/questions/37611488/how-to-stream-a-video-with-avurlasset-and-save-to-disk-the-cached-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!