2012-07-06 8 views
5

Tworzę prosty potok, który pobiera obrazy z AVCaptureSession, przetwarza je w OpenCV, a następnie renderuje w OpenGL. Oparty jest na RosyWriterze, ale bez funkcji audio i nagrywania. Przetwarzanie OpenCV wygląda jakPrzejmij prawa własności do pamięci z CVImageBufferRef

W tej funkcji do tej pory nie skopiowałem żadnej pamięci i chciałbym zachować ją w ten sposób. Problem polega na tym, że pixelBuffer może nadal posiadać pamięć zawartą w display_image. Kod przetwarzający może lub nie może przydzielić nowej pamięci i przechowywać ją w obrazie. Jeśli przetwarzanie nie przydzieliło nowej pamięci, muszę przekazać pixelBuffer dookoła za pomocą parametru display_matrix, aby dane nie zostały usunięte. Czy istnieje sposób na przejęcie własności pamięci? Chcę zniszczyć pixelBuffer bez niszczenia pamięci, którą ona również wskazuje.

Co dokładnie robi LockBaseAddress? Gdybym przechodził wokół cv :: Mat, para CVImageBufferRef musiałbym zablokować adres bazowy za każdym razem, gdy chcę zmodyfikować/użyć danych z cv :: Mat?

+0

Cześć Hammer, jak renderujesz swój obraz cv :: Mat w OpenGL ES, proszę? Z góry dziękuję – lilouch

Odpowiedz

0

Można utworzyć dostawcę danych z danych adresu bazowego bez kopiowania, a następnie utworzyć obiekt UIImage od tego dostawcy danych. Aby uniknąć ponownego użycia bufora podczas przywoływania tego obrazu, musisz zachować bufor próbek i zablokować adres bazowy. Powinny one zostać odblokowane i zwolniony automatycznie, kiedy użytkownik zapomni tego obiektu obrazu:

- (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 
} 

ja mam imageFromData z tego projektu https://github.com/k06a/UIImage-DecompressAndMap/blob/master/UIImage%2BDecompressAndMap.m i przyjęła go trochę:

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; 
} 

trzeba także zapewnić 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); 
}