【问题标题】:Should I use NSOperation or NSRunLoop?我应该使用 NSOperation 还是 NSRunLoop?
【发布时间】:2011-03-15 18:46:06
【问题描述】:

我正在尝试监控 FireWire 摄像机的视频输出流。我创建了一个带有按钮和NSImageView 的 Interface Builder 界面。在无限循环中进行图像监控时,我想:

  • 动态更改一些相机参数(增益、伽马等)
  • 告诉监控停止,这样我就可以将图像保存到文件中(设置一个标志来停止 while 循环)

使用按钮功能,我无法循环视频帧监视器,同时仍在寻找按钮按下(很像使用 C 中的按键功能。)出现两个选项:

  1. 启动一个新的运行循环(我无法让自动释放池运行...)
  2. 发起NSOperation - 如何以允许我通过 Xcode 按钮连接的方式执行此操作?

文档对于此类对象的创建非常迟钝。如果我根据我找到的示例创建一个NSOperation,似乎没有办法与来自 Interface Builder 的对象进行通信。当我创建一个NSRunLoop 时,我得到一个对象泄漏错误,并且我找不到如何创建一个实际响应我创建的 RunLoop 的自动释放池的示例。没关系,我什至没有尝试选择辅助运行循环对哪些对象进行采样...

因为 Objective C (显然!)不是我的母语,所以我正在寻找带有小步骤的解决方案,抱歉... 提前致谢

【问题讨论】:

    标签: cocoa nsoperation nsrunloop


    【解决方案1】:

    我需要做的几乎和你一样,只是使用 FireWire 摄像头的连续视频显示。在我的例子中,我使用libdc1394 library 为我们的 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 有一些 extensions you can use 使用 DMA 将这些帧作为纹理提供,以获得更好的性能。

    很遗憾,我在这里描述的内容都不是入门级的东西。我的软件中有大约 2,000 行代码用于这些相机处理功能,这需要很长时间才能弄清楚。如果 Apple 可以将手动相机设置调整添加到 QTKit Capture API,我可以删除几乎所有这些。

    【讨论】:

      【解决方案2】:

      如果您只想查看/获取已连接相机的输出,那么答案可能都不是。

      使用QTKit's QTCaptureView。问题解决了。想grab a frame?也没有问题。不要试图自己动手——QTKit 的东西已经过优化并且是操作系统的一部分。我很确定你可以随心所欲地影响相机属性,但如果不能,那么计划 B 应该可以工作。

      计划 b:使用预定的、重复出现的 NSTimer 让 QTKit 每隔一段时间抓取一个帧(上面链接的“如何”),然后在显示之前将图像处理应用于帧(可能使用 Core Image) NSImageView。

      【讨论】:

      • 目前无法通过 QTKit Capture API 更改连接的 FireWire 相机的曝光、增益等参数(重复 rdar://5760371 “能够设置亮度、增益等。用于 QTKit Capture API 中的相机”,如果您想要此功能)。
      • 我在“Cocoa is my Girlfriend”中使用 QTKit 遇到了以下示例:[link]cimgf.com/2008/02/23/nsoperation-example 这看起来很有希望。我也使用了 libdc1394 的东西,而且我已经到了看起来我已经捕捉到图像的地方。我无法以我可以使用的形式访问数据(将指向 unsigned char 的指针从 14 位相机转换为 16 位整数数组,最终保存为 tiff 文件......)
      • 如果你想要绝对控制,Brad 的方法是一个不错的方法,但我确实认为 QTKit 是要走的路。使用 NSOperation 执行此操作非常好,但它非常快,可能没有必要使用单独的线程。
      • 不过,我不确定我是否理解为什么您无法获得 QTKit 为您提供的捕获帧的 TIFF 表示。图像采集卡示例的第 12 步和第 13 步我链接了你以获得一个 NSImage;获取 tiff 表示就像向它询问 -TIFFRepresentation(一个 NSData 实例)一样简单,就像调用 -[myImage TIFFRepresentation] 一样简单,并且 NSData 可以使用自己的方法轻松保存到文件中......
      猜你喜欢
      • 1970-01-01
      • 2018-09-05
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 2015-10-16
      • 2023-03-06
      • 2013-02-20
      • 2011-07-31
      相关资源
      最近更新 更多