Reputation: 3613
I have a few videos in my collectionView
cell. I am fetching them from an URL and playing it using AVPlayer
.
Everything works fine. But, there is a requirement to show a mute/unmute icon depending on if the video contains audio or not.
In order to check if the video contains audio or not I used this code:
(self.player?.currentItem?.asset.tracks.filter({$0.mediaType == AVMediaType.audio}).count != 0)
I got this from: How to check if AVPlayer has Video or just Audio?
As soon as I add this code my collectionView stuck for the very first time when I scroll the collection view.
I am calling it from cell's init. Tried performing it on background thread but still, I am getting the issue.
DispatchQueue.global(qos: .background).async {
let isAudioAvailable = (self.player?.currentItem?.asset.tracks.filter({$0.mediaType == AVMediaType.audio}).count != 0)
DispatchQueue.main.async {
self.audioIconButton.isHidden = !isAudioAvailable
self.player?.isMuted = isMuted
let image = isMuted ? #imageLiteral(resourceName: "Mute_Icon") : #imageLiteral(resourceName: "Unmute_Icon")
self.audioIconButton.setImage(image, for: .normal)
})
}
Code to fetch from URL:
func getAVPlayerFromUrl(view: UIView) -> AVPlayer? {
let size: CGSize = view.bounds.size.applying(CGAffineTransform(scaleX: UIScreen.main.scale, y: UIScreen.main.scale))
guard let url = URL(string: AppConfig.shared.appConfig.video_buckets.videoURL(for: self, size: size)) else { return nil }
let videoAsset = AVURLAsset(url: url)
videoAsset.loadValuesAsynchronously(forKeys: ["playable"])
let playerItem: AVPlayerItem = AVPlayerItem(asset: videoAsset)
return AVPlayer(playerItem: playerItem)
}
Please let me know what's going wrong here. Or Is there any other way to distinguish if a video contains audio or not?
Upvotes: 0
Views: 705
Reputation: 6722
The idea here is to cache the count on loading the asset
instead of loading the cell
So the fetch logic will change to something similar to below code
func getAVPlayerFromUrl(view: UIView, cellIndex: Int) -> AVPlayer? {
let size: CGSize = view.bounds.size.applying(CGAffineTransform(scaleX: UIScreen.main.scale, y: UIScreen.main.scale))
guard let url = URL(string: AppConfig.shared.appConfig.video_buckets.videoURL(for: self, size: size)) else { return nil }
let videoAsset = AVURLAsset(url: url)
videoAsset.loadValuesAsynchronously(forKeys: ["playable"]) {
// Here audioCount is the dict we are using to save the count and cellIndex is the index of the cell in collectionview
self.audioCount[cellIndex] = videoAsset.tracks.filter({$0.mediaType == AVMediaType.audio}).count
}
let playerItem: AVPlayerItem = AVPlayerItem(asset: videoAsset)
return AVPlayer(playerItem: playerItem)
}
And finally use it like
let isAudioAvailable = (self.audioCount[index] != 0)
self.audioIconButton.isHidden = !isAudioAvailable
self.player?.isMuted = isMuted
let image = isMuted ? #imageLiteral(resourceName: "Mute_Icon") : #imageLiteral(resourceName: "Unmute_Icon")
self.audioIconButton.setImage(image, for: .normal)
Upvotes: 1