Hi,
In my SwiftUI app, I'm using AVPlayer and a UIViewRepresentable view to play back a video from a network server.
There are many videos on the server, so I have a LazyHStack
for the video thumbnails. Only one video is shown on screen at a time.
When the user scrolls between videos, I will create a new AVPlayerItem
and replace the current player item in the AVPlayer.
The problem is: the first video plays back without any problems. But when the user scrolls over to the next video, the new video would play for 1 second and then freezes while the audio track continues. The video track would resume after a few seconds.
One note is that if I drag the video view a bit without fully scrolling to another video, the video track will resume after I released the drag. So it seems maybe somehow the AVPlayerLayer was not rendering?
Related code pieces:
struct PlayerView: UIViewRepresentable {
let player: Player
let width: CGFloat
let height: CGFloat
@Binding var updateCount: Int
func makeUIView(context: Context) -> UIView {
print("\(#function)")
let playerLayer = AVPlayerLayer(player: player)
let view = UIView()
view.frame = CGRectMake(0, 0, width, height)
playerLayer.frame = view.bounds
view.layer.addSublayer(playerLayer)
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
print("\(#function)")
guard let playerLayer = uiView.layer.sublayers?.first as? AVPlayerLayer else { return }
uiView.frame = CGRectMake(0, 0, width, height)
if updateCount > 0 {
playerLayer.player = player
playerLayer.frame = uiView.bounds
}
}
}
updateCount
was added to force updateUIView
called when the parent View increases the updateCount. But it seems not helping much.
My question: Is there any known issue about replacing the current item in AVPlayer
in SwiftUI app?
Here is my code of replacing the current item:
let asset = AVURLAsset(url: url)
asset.resourceLoader.setDelegate(urlDelegate, queue: urlDelegate.resourceLoaderQueue)
let assetKeys = ["playable", "hasProtectedContent"]
let playerItem = AVPlayerItem(asset: asset, automaticallyLoadedAssetKeys: assetKeys)
player.replaceCurrentItem(with: playerItem)
Note that I have a custom delegate to handle the resource loader for the URLAsset. This delegate is the same for all videos. They always plays well when selected first time (i.e. without replacing another video).
One more data point: I have an ObjC version of the same design, and it worked without problems.