使用openCV IPLimage __block的dispatch_async的EXC_BAD_ACCESS问题

时间:2012-02-11 16:30:48

标签: ios asynchronous opencv dispatch

以下方案。使用dispatch asnyc在ios上使用openCV进行实时摄像机馈送处理。这是捕获sampleBufferMethod,它将缓冲区转换为IplImage然后使用它。

- (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会有所不同?我错过了什么?我想摆脱这种说法,因为越快越好。

1 个答案:

答案 0 :(得分:2)

如果没有您的解决方法,imageBuffer可能在块执行时无效。你是从框架外部获得它,没有承诺AFAIK关于它的处理程序完成后它的持续生命周期。因此你应该复制它。因此,您的克隆使代码有效。

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

您应该从__block中删除image声明 - 否则该块会将指针传递给image结构指针,而不仅仅是副本。由于struct指针是在堆栈上分配的,所以当块运行时,它之前的内存不再有效。