如何调整 CALayer (AVSampleBufferDisplayLayer) 的大小以适合 UIView,为 SwiftUI 包装

问题描述 投票:0回答:1

我试图了解

CALayer
(特别是
AVSampleBufferDisplayLayer
)如何调整其缩放比例以适应我添加到的
UIView
的范围内。我正在开发一个项目,该项目使用 C++ 库将数据写入
CMSampleBuffer
并将这些数据排入队列以由
AVSampleBufferDisplayLayer
显示。我使用 SwiftUI 来执行前端代码,因此 UIView 被包装以允许这样做。

我遇到的问题是

UIView
会缩小以正确适应屏幕,但添加到其中的
CALayer
不会缩放以匹配视图,因此正在播放的大多数视频都会运行超出视图范围并最终被 iPhone 屏幕剪切。

我的目标是让

CALayer
比例来填充视图的边界,以便我可以缩小或放大视图以及在
CALayer
比例中播放的视频以匹配。

我正在使用以下内容创建视图:

struct VideoPlayer: UIViewRepresentable {
    var player: AVSampleBufferDisplayLayer
    
    var view: some UIView {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 1920, height: 1080))

        player.frame = view.bounds
        player.bounds = view.bounds
        player.videoGravity = .resizeAspect

        view.layer.addSublayer(player)
        return view
    }
    
    func makeUIView(context: Context) -> UIView {
        return view
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {}
}

并使用此代码对其进行设置,以便它定期调用库函数以用新数据填充缓冲区:

struct VideoView: View {
    let timer = Timer.publish(every: 0.015, on: .main, in: .common).autoconnect()

    var body: some View {
        let sampleLayer = AVSampleBufferDisplayLayer()
        let player = VideoPlayer(player: sampleLayer)

        return player.onReceive(timer) { _ in
            let buffer = retrieve_video_buffers()
            if buffer != nil {
                player.player.enqueue(buffer!)
            }
        }
    }
}

最后,为了在 SwiftUI 中显示视图,我使用以下内容。

struct ContentView: View {
    var body: some View {
        VStack {
            VideoView()
                .aspectRatio(CGSize(width: 1920, height: 1080),
                             contentMode: ContentMode.fit)
        }
    }
}

为了查看剪切发生的位置,我向

UIView
CALayer
添加了背景颜色。
UIView
为绿色,
CALayer
为粉色。

iPhone Simulator in Portrait mode showing CALayer extending past View bounds

iPhone Simulator in Landscape mode showing CALayer extending past View bounds

如有任何帮助,我们将不胜感激!我感到很困惑,无法弄清楚这一点。

ios swift uikit
1个回答
0
投票

我必须明确地将位置和大小作为参数推入

UIView
中的
VideoPlayer
。所以我的
VideoPlayer
如下。

struct VideoPlayer: UIViewRepresentable {
    @Binding var displayLayer: AVSampleBufferDisplayLayer
    var x: CGFloat
    var y: CGFloat
    var width: CGFloat
    var height: CGFloat
    
    var view: some UIView {
        let view = UIView(frame: CGRect(x:x, y:y, width: width, height:height))

        displayLayer.frame = view.bounds
        displayLayer.bounds = view.bounds
        displayLayer.videoGravity = .resize
        
        view.layer.addSublayer(displayLayer)
        return view
    }
    
    func makeUIView(context: Context) -> some UIView {
        return view
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
    }
}

在 SwiftUI 中,我创建了一个

View
,其中
Rectangle
代表
VideoPlayer
的范围,并使用
GeometryReader
收集位置和大小值以插入视频播放器。

struct VideoView: View {
    @Binding var displayLayer : AVSampleBufferDisplayLayer
    
    var body: some View {
        VStack {
            Rectangle()
                .strokeBorder(Color.black, lineWidth: 1.0)
                .background(Color.white)
                .frame(height: 240.0)
                .overlay {
                    GeometryReader { geometry in
                        let frame = geometry.frame(in: CoordinateSpace.local)
                        VideoPlayer(displayLayer: $displayLayer, x: frame.origin.x, y: frame.origin.y,  width: frame.size.width, height: frame.size.height )
                    }
                }
        }.padding(.horizontal)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.