neekeetab / CachingPlayerItem

Play and cache media content simultaneously on your iOS device
MIT License
520 stars 89 forks source link

An AVPlayerItem cannot be associated with more than one instance of AVPlayer #29

Closed martaGonz closed 4 years ago

martaGonz commented 4 years ago

I would like to reuse previously downloaded videos in other parts of the app, but I usually get this error. How can avoid this?

ealeksandrov commented 4 years ago

Related to https://github.com/neekeetab/CachingPlayerItem/issues/10.

Do not reuse AVPlayerItem, save and reuse actual data. CachingPlayerItem gives downloaded data to its delegate, but you're the one responsible for actual saving/caching/reusing.

Here is small example of how I do it:

let playerItem: AVPlayerItem
if let cachedAsset = Cache.Video.asset(for: mp4Url) {
    // if cached data found - just play it
    playerItem = AVPlayerItem(asset: cachedAsset)
} else {
    // if no data found - stream it from network and save to cache when it's ready
    playerItem = CachingPlayerItem(url: mp4Url)
    (playerItem as? CachingPlayerItem)?.delegate = self
}

Creating asset with previously cached (saved) data:

class Cache {
    class Video {
        //...
        static func asset(for url: Url) -> AVURLAsset? {
            guard let filePath = ... // use url as a key to find existing file
            return AVURLAsset(url: URL(fileURLWithPath: filePath))
        }
    }
}

Saving data to cache:

func playerItem(_ playerItem: CachingPlayerItem, didFinishDownloadingData data: Data) {
    guard let urlAsset = playerItem.asset as? AVURLAsset, urlAsset.isPlayable else { return }

    Cache.Video.save(data: data, for: urlAsset.url) // use url as a key to save data to file
}

For caching data to file I used Cache, but it's not maintained now, so I can't recommend it and haven't shared library-specific code.

martaGonz commented 4 years ago

Thank you for your well explained reply! and thanks to @neekeetab for making this awesome resource.