Получите право собственности на память из CVImageBufferRef

Я делаю простой конвейер, который получает изображения из AVCaptureSession, обрабатывает их в OpenCV, а затем отображает в OpenGL. Он основан на RosyWriter, но без возможности аудио и записи. Обработка OpenCV выглядит так

- (void)processPixelBuffer: (CVImageBufferRef)pixelBuffer 
{
CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
int bufferWidth = CVPixelBufferGetWidth(pixelBuffer);
int bufferHeight = CVPixelBufferGetHeight(pixelBuffer);
unsigned char *pixel = (unsigned char *)CVPixelBufferGetBaseAddress(pixelBuffer);

cv::Mat image = cv::Mat(bufferWidth,bufferHeight,CV_8UC4,pixel);
//do any processing
[self setDisplay_matrix:image];
CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );
}

В этой функции до сих пор я не скопировал никакой памяти, и я хотел бы сохранить ее таким образом. Проблема в том, что pixelBuffer может по-прежнему владеть памятью, содержащейся в display_image. Код обработки может выделять или не выделять новую память и сохранять ее в образе. Если обработка не выделила новую память, я должен передать pixelBuffer с помощью display_matrix, чтобы данные не были стерты. Есть ли способ завладеть памятью? Я хочу уничтожить pixelBuffer, не разрушая при этом память, на которую он указывает.

Кстати, что именно делает LockBaseAddress? Если бы я передавал пару cv::Mat, CVImageBufferRef, пришлось бы мне блокировать базовый адрес каждый раз, когда я хочу изменить/использовать данные с помощью cv::Mat?


person Hammer    schedule 06.07.2012    source источник
comment
Привет, Хаммер, как вы визуализируете изображение cv::Mat в OpenGL ES, пожалуйста? Заранее спасибо   -  person lilouch    schedule 18.07.2016


Ответы (1)


Вы можете создать поставщика данных из данных базового адреса без копирования, а затем создать UIImage из этого поставщика данных. Чтобы избежать повторного использования буфера при обращении к этому изображению, вам необходимо сохранить образец буфера и заблокировать базовый адрес. Они должны быть разблокированы и освобождены автоматически, когда вы забудете этот объект изображения:

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
    // Retain sample buffer and lock base address
    CFRetain(sampleBuffer);
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);

    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    void *baseAddress = (void *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);

    UIImage *image = imageFromData(baseAddress, width, height, bytesPerRow, sampleBuffer);

    // Now you can store this UIImage as long as you want
}

У меня есть imageFromData из этого проекта https://github.com/k06a/UIImage-DecompressAndMap/blob/master/UIImage%2BDecompressAndMap.m и немного адаптировал его:

UIImage *imageFromData(void *data, size_t width, size_t height, size_t bytesPerRow, CMSampleBufferRef sampleBuffer)
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGDataProviderRef provider = CGDataProviderCreateWithData((void *)sampleBuffer, data, bytesPerRow * height, munmap_wrapper);
    CGImageRef inflatedImage = CGImageCreate(width, height, 8, 4*8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, provider, NULL, NO, kCGRenderingIntentDefault);

    CGColorSpaceRelease(colorSpace);
    CGDataProviderRelease(provider);

    UIImage *img = [UIImage imageWithCGImage:inflatedImage scale:scale orientation:UIImageOrientationUp];
    CGImageRelease(inflatedImage);
    return img;
}

Вам также необходимо предоставить unlock_function:

void unlock_function(void *info, const void *data, size_t size)
{
    // Unlock base address release sample buffer
    CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)info;
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    CFRelease(sampleBuffer);
}
person k06a    schedule 27.04.2016