swift AVPlayer在iOS和tvOS更新到17.0后出现意外行为

sg24os4d  于 11个月前  发布在  Swift
关注(0)|答案(1)|浏览(145)

主线程被HTTP(S)资产的尚未加载的属性(assetProperty_MediaPlaybackValidation)上的同步属性查询阻塞。如果从慢速网络读取此资产,则可能会出现问题。
在iOS和tvOS更新后,我在iPad和Apple TV中使用AVPlayer播放视频时出现此错误。
视频播放速度有时快2倍,后来完全停止播放。
我尽量避免在主线程中调用play函数。

izkcnapc

izkcnapc1#

我也遇到了同样的问题,在深入研究了一段时间的文档后,我发现了这个问题。据我所知,问题在于play方法获取了播放资产所需的所有元数据,而这些元数据是你还没有获取的。在我的例子中,它是一个视频。
这是来自Apple的相关文档。https://developer.apple.com/documentation/avfoundation/media_assets/retrieving_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”。实际上,您并不需要load函数的返回值,但加载它们后会缓存它们,以便play函数拥有播放资源所需的一切。
我希望这能帮上忙。

相关问题