我有一个由外部源以每秒30帧更新的基于IOSurface的CVPixelBuffer。我想在NSView中呈现图像数据的预览 - 对我来说最好的方法是什么?
我可以直接设置视图上CALayer的.contents,但这只会在视图第一次更新时(或者例如我调整视图大小时)更新。我一直在查阅文档,但我无法找出正确的needsDisplay调用方式,以便让视图基础结构知道何时刷新自身,尤其是当更新来自视图外部时。
理想情况下,我只需将IOSurface绑定到我的图层,所做的任何更改都会传播,但我不确定是否可能。
这是我尝试基于 NSView 进行缩放的版本,而不是基于 NSViewController 的版本,但它也不能正确更新(或缩放)。
我可以直接设置视图上CALayer的.contents,但这只会在视图第一次更新时(或者例如我调整视图大小时)更新。我一直在查阅文档,但我无法找出正确的needsDisplay调用方式,以便让视图基础结构知道何时刷新自身,尤其是当更新来自视图外部时。
理想情况下,我只需将IOSurface绑定到我的图层,所做的任何更改都会传播,但我不确定是否可能。
class VideoPreviewController: NSViewController, VideoFeedConsumer {
let customLayer : CALayer = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
print("Loaded our video preview")
view.layer?.addSublayer(customLayer)
customLayer.frame = view.frame
// register our view with the browser service
VideoFeedBrowser.instance.registerConsumer(self)
}
override func viewWillDisappear() {
// deregister our view from the video feed
VideoFeedBrowser.instance.deregisterConsumer(self)
super.viewWillDisappear()
}
// This callback gets called at 30fps whenever the pixelbuffer is updated
@objc func updateFrame(pixelBuffer: CVPixelBuffer) {
guard let surface = CVPixelBufferGetIOSurface(pixelBuffer)?.takeUnretainedValue() else {
print("pixelbuffer isn't IOsurface backed! noooooo!")
return;
}
// Try and tell the view to redraw itself with new contents?
// These methods don't work
//self.view.setNeedsDisplay(self.view.visibleRect)
//self.customLayer.setNeedsDisplay()
self.customLayer.contents = surface
}
}
这是我尝试基于 NSView 进行缩放的版本,而不是基于 NSViewController 的版本,但它也不能正确更新(或缩放)。
class VideoPreviewThumbnail: NSView, VideoFeedConsumer {
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
self.wantsLayer = true
// register our view with the browser service
VideoFeedBrowser.instance.registerConsumer(self)
}
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
self.wantsLayer = true
// register our view with the browser service
VideoFeedBrowser.instance.registerConsumer(self)
}
deinit{
VideoFeedBrowser.instance.deregisterConsumer(self)
}
override func updateLayer() {
// Do I need to put something here?
print("update layer")
}
@objc
func updateFrame(pixelBuffer: CVPixelBuffer) {
guard let surface = CVPixelBufferGetIOSurface(pixelBuffer)?.takeUnretainedValue() else {
print("pixelbuffer isn't IOsurface backed! noooooo!")
return;
}
self.layer?.contents = surface
self.layer?.transform = CATransform3DMakeScale(
self.frame.width / CGFloat(CVPixelBufferGetWidth(pixelBuffer)),
self.frame.height / CGFloat(CVPixelBufferGetHeight(pixelBuffer)),
CGFloat(1))
}
}
我缺少什么?
.contents
(这有效),只是更新没有发生。 - andrew.contents = ...
后面添加CATransaction.flush()
吗?请确保始终在主线程上执行。我在查看我的一些旧项目(Objective-C)时发现了这个方法...也许它有所帮助。 - LombaXvar bufferAttributes = [kCVPixelBufferIOSurfaceCoreAnimationCompatibilityKey:true] as CFDictionary; let err = CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, bufferAttributes, &pb)
参考链接:http://www.russbishop.net/cross-process-rendering - andrew