2012-02-11 105 views
1

以下方案。使用dispatch asnyc在ios上使用openCV实时进行相机馈送处理。这里是捕获sampleBufferMethod将缓冲区转换为IplImage,然后使用它。EXC_BAD_ACCESS问题与dispatch_async使用openCV IPLimage __block

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection  
{ 

    __block IplImage *image = 0; 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 

    // get information of the image in the buffer 
    uint8_t *bufferBaseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); 
    size_t bufferWidth = CVPixelBufferGetWidth(imageBuffer); 
    size_t bufferHeight = CVPixelBufferGetHeight(imageBuffer); 

    // create IplImage 
    if (bufferBaseAddress) 
    { 
     image = cvCreateImage(cvSize(bufferWidth, bufferHeight), IPL_DEPTH_8U, 4); 
     image->imageData = (char*)bufferBaseAddress; 
    }  
    // release memory 
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0); 


    dispatch_async(dispatch_get_main_queue(), ^{ 
     IplImage *out=cvCreateImage(cvSize(568, 320), IPL_DEPTH_8U, 4); 
     cvResize(image, out, 0); 
     ... 
}); 
} 

相当直接的,除了这个位置:

 cvResize(image, out, 0); 

给我EXC_BAD_ACCESS。我有一个解决办法,我发现它永远玩:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 

    IplImage *_image = 0; 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 

    // get information of the image in the buffer 
    uint8_t *bufferBaseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); 
    size_t bufferWidth = CVPixelBufferGetWidth(imageBuffer); 
    size_t bufferHeight = CVPixelBufferGetHeight(imageBuffer); 

    // create IplImage 
    if (bufferBaseAddress) 
    { 
     _image = cvCreateImage(cvSize(bufferWidth, bufferHeight), IPL_DEPTH_8U, 4); 
     _image->imageData = (char*)bufferBaseAddress; 
    }  
    // release memory 
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0); 

    __block IplImage *image=cvCloneImage(_image); 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     IplImage *out=cvCreateImage(cvSize(568, 320), IPL_DEPTH_8U, 4); 
     cvResize(image, out, 0); 
     ... 
}); 
} 

重点线:

__block IplImage *image=cvCloneImage(_image); 

所以我不明白的是,为什么cvCloneImage使区别?我错过了什么?自从越快越好,我想摆脱这种说法。

回答

2

没有您的解决方法,imageBuffer可能无法在该块执行时有效。你从框架中获得外部信息,一旦处理程序完成,没有承诺AFAIK关于它的持续生命周期。所以你应该复制它。因此,您的克隆使代码正常工作。

另一个问题是访问在方法的堆栈帧中分配的内存。

你应该从image删除__block声明 - 否则,该块传递一个指针image结构指针,而不是只是一个副本。由于结构指针在堆栈中分配,在块运行时,之前的内存不再有效。

+0

我完全理解你的** __ block **答案,谢谢澄清这一点。问题仍然存在,仍然是同样的错误。任何其他想法? – 2012-02-11 19:38:08

+0

已更新的答案。 – Danra 2012-02-12 07:51:56

+0

是的,这是有道理的,我怀疑这样的事情。所以我想克隆毕竟是一个很好的解决方案。 – 2012-02-12 20:30:58