import AVKit import SwiftUI import FlixyPlayback import FlixyVLC /// Die Bildfläche des laufenden Motors. /// /// Die einzige Stelle in der App, an der der Unterschied zwischen den beiden /// Motoren sichtbar wird — weil beide ihr Bild auf unterschiedliche Weise /// ausliefern: AVPlayer über eine `AVPlayerLayer`, VLC in eine gewöhnliche /// `UIView`. struct VideoSurface: View { let engine: (any VideoPlayerEngine)? var body: some View { switch engine { case let avEngine as AVPlayerEngine: AVPlayerSurface(player: avEngine.player) case let vlcEngine as VLCPlayerEngine: UIViewContainer(view: vlcEngine.videoView) default: Color.black } } } /// Die Bildebene des Systemplayers, samt Bild-in-Bild. private struct AVPlayerSurface: UIViewRepresentable { let player: AVPlayer func makeUIView(context: Context) -> PlayerLayerView { let view = PlayerLayerView() view.playerLayer.player = player view.playerLayer.videoGravity = .resizeAspect context.coordinator.setUp(with: view.playerLayer) return view } func updateUIView(_ uiView: PlayerLayerView, context: Context) { uiView.playerLayer.player = player } func makeCoordinator() -> Coordinator { Coordinator() } final class Coordinator { private var pictureInPicture: AVPictureInPictureController? func setUp(with layer: AVPlayerLayer) { guard AVPictureInPictureController.isPictureInPictureSupported() else { return } pictureInPicture = AVPictureInPictureController(playerLayer: layer) // Beim Verlassen der App ins Bild-in-Bild wechseln, statt die // Wiedergabe anzuhalten. pictureInPicture?.canStartPictureInPictureAutomaticallyFromInline = true } } } /// Eine `UIView`, deren Ebene eine `AVPlayerLayer` ist. /// /// Der übliche Weg: eine Ebene von Hand als Unterebene einzuhängen bedeutet, /// ihre Größe bei jeder Drehung selbst nachzuführen. Als Hauptebene macht das /// UIKit. final class PlayerLayerView: UIView { override static var layerClass: AnyClass { AVPlayerLayer.self } var playerLayer: AVPlayerLayer { layer as! AVPlayerLayer } } /// Hängt eine bestehende `UIView` in den SwiftUI-Baum. private struct UIViewContainer: UIViewRepresentable { let view: UIView func makeUIView(context: Context) -> UIView { view } func updateUIView(_ uiView: UIView, context: Context) {} }