访问iPhone视频输出图像缓冲区时FPS低

时间:2010-11-23 11:26:55

标签: iphone image-processing video-processing avfoundation

我正在尝试在iPhone上进行一些图像处理。我正在使用http://developer.apple.com/library/ios/#qa/qa2010/qa1702.html来捕捉相机帧。

我的问题是,当我试图访问捕获的缓冲区时,相机FPS从30降到大约20.有人知道我该如何修复它吗?

我使用kCVPixelFormatType_32BGRA格式中我能找到的最低捕获质量(AVCaptureSessionPresetLow = 192x144)。如果有人知道我可以使用的质量较低,我愿意尝试。

当我在其他平台(如Symbian)上进行相同的图像访问时,它可以正常工作。

这是我的代码:

#pragma mark -
#pragma mark AVCaptureSession delegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
    fromConnection:(AVCaptureConnection *)connection 
{ 
 /*We create an autorelease pool because as we are not in the main_queue our code is
  not executed in the main thread. So we have to create an autorelease pool for the thread we are in*/
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
 //Lock the image buffer
    if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess)
    {  

  // calculate FPS and display it using main thread
  [self performSelectorOnMainThread:@selector(updateFps:) withObject: (id) nil waitUntilDone:NO];


  UInt8 *base = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer); //image buffer start address

  size_t width  = CVPixelBufferGetWidth(imageBuffer); 
  size_t height = CVPixelBufferGetHeight(imageBuffer);

  int size = (height*width);
  UInt8* pRGBtmp = m_pRGBimage;

        /*
        Here is the problem; m_pRGBimage is RGB image I want to process.
        In the 'for' loop I convert the image from BGRA to RGB. As a resault, the FPS drops to 20.
        */ 
  for (int i=0;i<size;i++)
  {   
    pRGBtmp[0] = base[2];
    pRGBtmp[1] = base[1];
    pRGBtmp[2] = base[0];
    base = base+4;
    pRGBtmp = pRGBtmp+3;     
  }


  // Display received action
  [self performSelectorOnMainThread:@selector(displayAction:) withObject: (id) nil waitUntilDone:NO];
  //[self displayAction:&eyePlayOutput];
  //saveFrame( imageBuffer );

  //unlock the  image buffer
  CVPixelBufferUnlockBaseAddress(imageBuffer,0);

 }


 [pool drain];
} 

作为答案的后续,我需要实时处理图像,然后显示。

我注意到当我使用AVCaptureSessionPresetHigh时,我做的最简单的事情就像:

 for (int i=0;i<size;i++)
    x = base[0];

导致帧速率降至4-5 FPS。我猜是因为那个大小的图像没有缓存。

基本上我需要96x48图像。是否有一种简单的方法来缩小相机输出图像,这是一种使用硬件加速的方式,所以我可以使用小型的?

3 个答案:

答案 0 :(得分:8)

除了速度最快的iOS设备外,任何迭代图像中每个像素的内容都会相当慢。例如,我通过简单的逐像素颜色测试对640 x 480视频帧(307,200像素)中的每个像素进行基准测试,发现这只能在iPhone 4上以大约4 FPS的速度运行。

你正在寻找处理27,648像素的情况,它应该足够快地在iPhone 4上运行达到30 FPS,但这是一个比原来的iPhone和iPhone 3G更快的处理器。 iPhone 3G可能仍然会遇到这种处理负担。您也没有说明处理器在Symbian设备中的速度有多快。

我建议重新处理您的处理算法以避免颜色空间转换。应该不需要重新排序颜色组件以便处理它们。

此外,您可以通过在图像的行和列内以特定间隔采样来选择性地处理几个像素。

最后,如果您的目标是支持OpenGL ES 2.0(iPhone 3G S及更新版本)的较新iOS设备,您可能需要使用GLSL片段着色器来完全在GPU上处理视频帧。我描述了进程here,以及用于实时基于颜色的对象跟踪的示例代码。在我的基准测试中,GPU可以比CPU快14到28倍处理这种处理。

答案 1 :(得分:1)

免责声明:这个答案是一个GUESS:)

当缓冲区被锁定时,你正在做很多工作;这是否阻碍了从相机捕获图像的线程?

您可以在处理数据时将数据复制出缓冲区,以便尽快解锁,例如

if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess) {
    // Get the base address and size of the buffer
    UInt8 *buffer_base = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer); //image buffer start address
    size_t width  = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer);

    // Copy it's contents out
    Uint8 *base = malloc(width * height * 4);
    memcpy(base, buffer_base, size);

    // Unlock the buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    // base now points to a copy of the buffers' data - do what you want to it . . .
    ...

    // remember to free base once you're done ;)
    free(base);

如果它是阻止捕获的锁,那么这应该有帮助。

NB你可以加快速度,如果你知道所有的缓冲区都是相同的大小,你可以只调用一次malloc来获取内存,然后每次只重复使用它,只有在你完成所有缓冲区的处理后才释放它。


或者,如果这不是问题,您可以尝试降低此线程的优先级

[NSThread setThreadPriority:0.25];

答案 2 :(得分:0)

将相机框架的内容复制到专用缓冲区并从那里对其进行操作。这样可以大大提高我的体验速度。我最好的猜测是相机框架所在的存储区域具有特殊的保护功能,使读/写访问变慢。

检查相机帧数据的存储器地址。在我的设备上,相机缓冲区位于0x63ac000。这对我来说没有任何意义,除了其他堆对象在更接近0x1300000的地址中。锁定建议没有解决我的减速问题,但是memcpy确实没有。