我需要做的几乎和你一样,只是使用 FireWire 摄像头的连续视频显示。在我的例子中,我使用libdc1394 库为我们的 FireWire 相机执行帧捕获和相机属性调整。我知道你也可以使用一些 Carbon Quicktime 函数来做到这一点,但我发现 libdc1394 更容易理解。
对于视频捕获循环,我尝试了许多不同的方法,从轮询相机并锁定共享资源的单独线程,到使用一个 NSOperationQueue 与相机交互,最后决定使用 CVDisplayLink 轮询相机以与屏幕刷新率相匹配的方式。
CVDisplayLink 使用以下代码进行配置:
CGDirectDisplayID displayID = CGMainDisplayID();
CVReturn error = kCVReturnSuccess;
error = CVDisplayLinkCreateWithCGDisplay(displayID, &displayLink);
if (error)
{
NSLog(@"DisplayLink created with error:%d", error);
displayLink = NULL;
}
CVDisplayLinkSetOutputCallback(displayLink, renderCallback, self);
它调用以下函数来触发新相机帧的检索:
static CVReturn renderCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp *inNow,
const CVTimeStamp *inOutputTime,
CVOptionFlags flagsIn,
CVOptionFlags *flagsOut,
void *displayLinkContext)
{
return [(SPVideoView *)displayLinkContext renderTime:inOutputTime];
}
CVDisplayLink 使用以下命令启动和停止:
- (void)startRequestingFrames;
{
CVDisplayLinkStart(displayLink);
}
- (void)stopRequestingFrames;
{
CVDisplayLinkStop(displayLink);
}
每当我需要调整曝光、增益等时,我不会在 FireWire 相机通信上使用锁定,而是更改相应的实例变量并在标志变量中设置适当的位以指示要更改的设置。在下一次检索帧时,来自 CVDisplayLink 的回调方法会更改相机上的适当设置以匹配本地存储的实例变量并清除该标志。
通过 NSOpenGLView 处理屏幕显示(CAOpenGLLayer 在以这种速率更新时引入了太多的视觉伪影,并且它的更新回调在主线程上运行)。Apple 提供了一些扩展,您可以使用DMA 将这些帧作为纹理提供,以获得更好的性能。
不幸的是,我在这里描述的都不是入门级的东西。我在我们的软件中有大约 2,000 行用于这些相机处理功能的代码,这需要很长时间才能弄清楚。如果 Apple 可以将手动相机设置调整添加到 QTKit Capture API,我可以删除几乎所有这些。