2012-02-11 48 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