将所有NSWindows捕获为活动图像,如Mac OS X中的Mission Control

时间:2014-03-25 01:25:52

标签: macos opengl window core-graphics mission-control

我希望汇总所有窗口的实时表示。就像Mission Control(Exposé)一样,我想非常快地访问任何给定的NSWindow或屏幕的图像缓冲区。理想情况下,我想在我自己的OpenGL上下文中合成这些实时图像,以便我可以操作它们(缩放并移动窗口屏幕捕获)。

太慢的事情:

  • CGDisplayCreateImage
  • CGWindowListCreateImage
  • CGDisplayIDToOpenGLDisplayMask& CGLCreateContext& CGBitmapContextCreate

还有其他想法吗?我正在努力实现60 fps捕获/复合/输出,但我能用这些方法获得的最佳效果是~5 fps(在视网膜显示器上捕获整个屏幕)。

1 个答案:

答案 0 :(得分:5)

不幸的是,我还没有找到快速捕获单个窗口的帧缓冲区,但我发现了下一个最好的东西。这是一种快速捕获整个屏幕的实时视图到OpenGL中的方法:

AVFoundation设置

_session = [[AVCaptureSession alloc] init];
_session.sessionPreset = AVCaptureSessionPresetPhoto;
AVCaptureScreenInput *input = [[AVCaptureScreenInput alloc] initWithDisplayID:kCGDirectMainDisplay];
input.minFrameDuration = CMTimeMake(1, 60);
[_session addInput:input];
AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
[output setAlwaysDiscardsLateVideoFrames:YES];
[output setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
[_session addOutput:output];
[_session startRunning];

在每个AVCaptureVideoDataOutput框架

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
  CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
  const size_t bufferWidth = CVPixelBufferGetWidth(pixelBuffer);
  const size_t bufferHeight = CVPixelBufferGetHeight(pixelBuffer);

  CVOpenGLTextureRef texture;
  CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, pixelBuffer, NULL, &texture);
  CVOpenGLTextureCacheFlush(_textureCache, 0);

  // Manipulate and draw the texture however you want...
  const GLenum target = CVOpenGLTextureGetTarget(texture);
  const GLuint name = CVOpenGLTextureGetName(texture);

  // ...

  glEnable(target);
  glBindTexture(target, name);

  CVOpenGLTextureRelease(texture);
}

<强>清理

[_session stopRunning];
CVOpenGLTextureCacheRelease(_textureCache);

AVCaptureVideoDataOutput图像作为纹理导入OpenGL的其他一些实现之间的巨大差异在于它们可能使用CVPixelBufferLockBaseAddressCVPixelBufferGetBaseAddressglTexImage2D和{ {1}}。这种方法的问题在于它通常非常冗余和缓慢。 CVPixelBufferUnlockBaseAddress将确保它所传递的内存不是GPU内存,并将其全部复制到通用CPU内存。这是不好的!毕竟,我们只是使用CVPixelBufferLockBaseAddress将其复制回GPU。

因此,我们可以利用glTexImage2D已经位于GPU内存CVPixelBuffer的事实。

我希望这可以帮助其他人...... CVOpenGLTextureCacheCreateTextureFromImage套件的文档非常完整,其iOS对应CVOpenGLTextureCache只有更好的文档记录。

60%CPU,20%CPU捕获2560x1600桌面!