EXC_BAD_ACCESS проблема с dispatch_async с использованием openCV IPLimage __block - PullRequest
1 голос
/ 11 февраля 2012

Следующий сценарий. Обработка видеопотока в реальном времени с openCV на ios с использованием диспетчеризации asnyc. Вот захват 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 Ответ

2 голосов
/ 11 февраля 2012

Без вашего обходного пути, imageBuffer может быть недействительным к моменту выполнения блока.Вы получаете его извне из фреймворка, без каких-либо обещаний AFAIK относительно его продолжительного срока службы после завершения работы вашего обработчика.Поэтому вы должны скопировать его.Следовательно, ваш клон заставляет код работать.

Другая проблема заключается в доступе к памяти, выделенной в кадре стека метода.

Вы должны удалить объявление __block из image - В противном случаеблоку передается указатель на указатель структуры image, а не просто копия.Поскольку указатель структуры размещается в стеке, к моменту запуска вашего блока память, в которой он был раньше, больше не действительна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...