2017-04-04 40 views
0

我想用LibvnccClient在Swift中实现一个简单的VNC client流远程帧缓冲到NSView

我已经创建了NSView的子类。我创建了一个CGContext并将数据指针传递给库以用作framebuffer。 libvncclient更新帧缓冲区作为屏幕内容的变化并调用我提供的回调。

下面是相关代码

class VNCClient { 

    var localClient: rfbClient 
    var view: NSView 

    init(view: NSView) { 
     guard let client_ptr = rfbGetClient(8, 3, 4) else { 
      fatalError("Trouble") 
     } 

     self.view = view 
     self.localClient = client_ptr.pointee 

     localClient.MallocFrameBuffer = resize 
     localClient.GotFrameBufferUpdate = update 
     let fbPointer = UnsafeMutablePointer<UInt8>(OpaquePointer((view as! RFBView).buffer)) 
     localClient.frameBuffer = fbPointer 
     rfbClientSetClientData(&localClient, &viewTag, &self.view) 
     var argc: Int32 = 0 
     let b = rfbInitClient(&localClient, &argc, nil) 
     if b == RFB_TRUE { 
      print("Connected!") 
     } 
     Timer.scheduledTimer(withTimeInterval: 0.001, repeats: true) {_ in 
      if WaitForMessage(&self.localClient, 1) > 0 { 
       HandleRFBServerMessage(&self.localClient) 
      } 
     } 
    } 

func update(client: UnsafeMutablePointer<rfbClient>?, x: Int32, y: Int32, w: Int32, h: Int32) -> Void { 
    let cl = client!.pointee 
    let view_ptr = rfbClientGetClientData(client, &viewTag) 
    let view = view_ptr?.assumingMemoryBound(to: RFBView.self).pointee 
    view?.setNeedsDisplay(NSRect(x: Int(x), y: Int(y), width: Int(w), height: Int(h))) 
} 


class RFBView: NSView { 

    let ctx = CGContext(data: nil, width: 800, height: 600, bitsPerComponent: 8, bytesPerRow: 4 * 800, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue)! 

    var buffer: UnsafeMutableRawPointer? { 
     return ctx.data 
    } 
    override func draw(_ dirtyRect: NSRect) { 

     let image = ctx.makeImage() 

     NSGraphicsContext.current()?.cgContext.draw(image!, in: frame) 

    } 

它的工作原理,但显示效果并不顺利。服务器在虚拟机中的同一台计算机上运行,​​因此没有网络问题。

我正在重新绘制整个图像的每个更新,我认为是问题的原因。那么我怎么才能重新绘制更新后的framebuffer部分呢?

CoreGraphics不够快,或者我应该使用NSOpenGLView

+0

无需每秒重绘1000次。尝试15fps'Timer.scheduledTimer(withTimeInterval:1/15,'越小越好。它不需要看起来像电影 –

+0

我尝试使用帧速率播放,但我无法获得可接受的性能。 – a2bk

回答

0

我认为HandleRFBServerMessage会调用update函数每次迭代,如果有更新。但事实并非如此。

我将update替换为打印到控制台的存根,并且发现当屏幕上出现大量活动时,它被称为超过一千次。

但是,setNeedsDisplay呼叫update,它只被称为几百次。由于它花费了太多的时间,所以在它们之间的几帧中错过了它。

我将Timer中的绘图代码移开了,它现在完美运行。

localClient.GotFrameBufferUpdate = { _, _, _, _, _ in needs_update = true } 
Timer.scheduledTimer(withTimeInterval: 0.016, repeats: true) {_ in 
    if needs_update { 
     view.display() 
     needs_update = false 
    } 
    if WaitForMessage(&self.localClient, 1) > 0 { 
     HandleRFBServerMessage(&self.localClient) 
    } 
}