我试图了解
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
为粉色。
如有任何帮助,我们将不胜感激!我感到很困惑,无法弄清楚这一点。
我必须明确地将位置和大小作为参数推入
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)
}
}