У меня есть несколько видео в моей collectionView ячейке. Я получаю их по URL-адресу и играю с помощью AVPlayer.
Все работает нормально. Но есть требование отображать значок отключения/включения звука в зависимости от того, содержит ли видео звук или нет.
Чтобы проверить, содержит ли видео звук или нет, я использовал этот код:
(self.player?.currentItem?.asset.tracks.filter({$0.mediaType == AVMediaType.audio}).count != 0)
Я получил это от: Как проверить, есть ли в AVPlayer видео или только аудио?
Как только я добавляю этот код, мой collectionView зависает в первый раз, когда я прокручиваю представление коллекции.
Я звоню из ячейки в этом. Пытался выполнить это в фоновом потоке, но все же я получаю проблему.
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)
})
}
Код для получения из 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)
}
Пожалуйста, дайте мне знать, что здесь происходит. Или есть ли другой способ определить, содержит ли видео звук или нет?
@CerlinBoss, не могли бы вы сообщить мне, как это сделать? К вашему сведению, я получаю это видео по URL-адресу и воспроизводлю его в AVPlayer.
Можете ли вы добавить логику выборки к вопросу?
Я добавил код.
Попробуйте добавить обработчик завершения в loadValuesAsynchronously, получить количество и кэшировать его. Позже внутри инициализации проверьте кешированное значение
Спасибо! Постараюсь и дам вам знать, как это происходит.
Это сработало, спасибо! @CerlinBoss Я прошу вас добавить его в качестве ответа, это может помочь другим,





Идея здесь состоит в том, чтобы кэшировать счетчик при загрузке asset вместо загрузки cell.
Таким образом, логика выборки изменится на что-то похожее на приведенный ниже код.
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)
}
И, наконец, используйте его как
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)
Вместо того, чтобы проверять текущий элемент игрока, можете ли вы проверить источник этих данных?