主线程被 HTTP(S) 资产尚未加载的属性 (assetProperty_MediaPlaybackValidation) 的同步属性查询阻塞。如果从慢速网络读取该资产,这可能会成为问题。
在 iOS 和 tvOS 更新后,我在 iPad 和 Apple TV 中使用 AVPlayer 播放视频时遇到此错误。
视频有时播放速度快了 2 倍,后来完全停止播放。
我试图避免在主线程中调用播放函数。
我遇到了同样的问题,并在深入研究文档一段时间后解决了这个问题。据我所知,问题在于 play 方法获取了您尚未获取的播放资产所需的所有元数据。就我而言,这是一个视频。
这是 Apple 的相关文档。 https://developer.apple.com/documentation/avfoundation/media_assets/retriving_media_metadata
这是我用来加载元数据的实际函数。 https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading/3747326-load
这是我拥有的视频播放器,它在尝试播放资产之前异步加载元数据。加载视频时可能会有一点延迟,视频播放器上会显示黑屏,但不会阻止任何 UI,警告也会消失。
import SwiftUI
import AVKit
struct VideoPlayerView: View {
private var videoURL : URL
@State private var player: AVPlayer?
@State private var isMuted: Bool = true
var showMuteButton: Bool
init(url: URL, showMuteButton: Bool = true) {
self.videoURL = url
self.showMuteButton = showMuteButton
}
var body: some View {
VideoPlayer(player: player)
.onAppear() {
Task {
player = AVPlayer()
await loadPlayerItem(self.videoURL)
player?.isMuted = true
self.isMuted = player?.isMuted ?? false
player?.play()
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: .main) { _ in
self.player?.seek(to: .zero)
self.player?.play()
}
}//: Task
}//: onAppear
.onDisappear() {
Task {
// Stop the player when the view disappears
player?.pause()
}
}
.onChange(of: videoURL) { oldValue, newValue in
Task {
await loadPlayerItem(newValue)
}
}
.overlay(alignment: .topTrailing) {
if showMuteButton {
Image(systemName: isMuted ? "speaker.slash.fill" : "speaker.wave.2.fill")
.font(.footnote)
.foregroundColor(.white)
.padding(8)
.background(Color.gray.opacity(0.3))
.clipShape(Circle())
.padding()
.onTapGesture {
player?.isMuted.toggle()
self.isMuted = player?.isMuted ?? false
}
}
}
}
func loadPlayerItem(_ videoURL: URL) async {
let asset = AVAsset(url: videoURL)
do {
let (_, _, _) = try await asset.load(.tracks, .duration, .preferredTransform)
} catch let error {
print(error.localizedDescription)
}
let item = AVPlayerItem(asset: asset)
player?.replaceCurrentItem(with: item)
}
}
关键函数是“loadPlayerItem”。您实际上不需要加载函数的返回值,但加载它们后会缓存它们,以便播放函数拥有播放资产所需的一切。
我希望这有帮助。