2011-06-24 10 views
7


Piszę aplikację na iPhone'a, która tworzy zdjęcia z kamery za pomocą AVFoundation. Czytanie przewodnika programowania Znalazłem kod, który prawie powinienem wykonać, więc próbuję "odwrócić inżynierię" i zrozumieć.
Występują pewne trudności w zrozumieniu części, która przekształca CMSampleBuffer w obraz.
Oto, co zrozumiałem, a później kod.
CMSampleBuffer reprezentuje bufor w pamięci, w którym przechowywany jest obraz z dodatkowymi danymi. Później nazywam funkcję CMSampleBufferGetImageBuffer(), aby odebrać CVImageBuffer z powrotem tylko z danymi obrazu.
Teraz jest funkcja, której nie rozumiem i mogę sobie tylko wyobrazić jej funkcję: CVPixelBufferLockBaseAddress (imageBuffer, 0); Nie mogę zrozumieć, czy jest to "blokada wątku", aby uniknąć wielu operacji na nim lub blokadę adresu bufora, aby uniknąć zmian podczas działania (i dlaczego powinna się zmienić? .. kolejna klatka, nie są skopiowane dane w innej lokalizacji?). Reszta kodu jest dla mnie jasna.
Próbowałem szukać w Google, ale nadal nie znalazłem nic przydatnego.
Czy ktoś może przynieść trochę światła?CVPixelBufferLockBaseAddress dlaczego? Przechwytywanie nieruchomego obrazu za pomocą AVFoundation

-(UIImage*) getUIImageFromBuffer:(CMSampleBufferRef) sampleBuffer{ 

// Get a CMSampleBuffer's Core Video image buffer for the media data 
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 

// Lock the base address of the pixel buffer 
CVPixelBufferLockBaseAddress(imageBuffer, 0); 

void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer); 

// Get the number of bytes per row for the pixel buffer 
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
// Get the pixel buffer width and height 
size_t width = CVPixelBufferGetWidth(imageBuffer); 
size_t height = CVPixelBufferGetHeight(imageBuffer); 

// Create a device-dependent RGB color space 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

// Create a bitmap graphics context with the sample buffer data 
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, 
bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
// Create a Quartz image from the pixel data in the bitmap graphics context 
CGImageRef quartzImage = CGBitmapContextCreateImage(context); 
// Unlock the pixel buffer 
CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

// Free up the context and color space 
CGContextRelease(context); 
CGColorSpaceRelease(colorSpace); 

// Create an image object from the Quartz image 
UIImage *image = [UIImage imageWithCGImage:quartzImage]; 

// Release the Quartz image 
CGImageRelease(quartzImage); 

return (image); 
} 

Dzięki Andrea

Odpowiedz

3

Plik nagłówek mówi, że CVPixelBufferLockBaseAddress sprawia, że ​​pamięć "dostępny". Nie jestem pewien, co to dokładnie oznacza, ale jeśli tego nie zrobisz, CVPixelBufferGetBaseAddress nie powiedzie się, więc lepiej to zrobić.

EDIT

Wystarczy zrobić to krótka odpowiedź. Po co uważać, że obraz może nie żyć w głównej pamięci, może on żyć w jakimś miejscu na jakimś GPU (CoreVideo działa również na macu) lub nawet w innym formacie, niż oczekiwano, więc otrzymywane piksele są w rzeczywistości Kopiuj. Bez Lock/Unlocka lub jakiejś pary Begin/End implementacja nie ma możliwości dowiedzenia się, kiedy skończysz z duplikatami pikseli, aby skutecznie zostały one przeciekające. CVPixelBufferLockBaseAddress po prostu podaje informacje o zakresie CoreVideo, nie będę zbytnio na nim zawieszony.

Tak, mogli po prostu zwrócić piksele z CVPixelBufferGetBaseAddress i całkowicie wyeliminować CVPixelBufferLockBaseAddress. Nie wiem, dlaczego tego nie zrobili.

+0

Dziękuję, to jest wskazówka.Ponieważ w wywołanych funkcjach nie ma śladu na temat kopiowania lub tworzenia, zaczynam myśleć, że bufor jest przekazywany przez odniesienie, więc jest rodzajem zatrzymania bufora pamięci. – Andrea

+0

Dodałem kilka możliwych powodów dlaczego. –

+0

YEP, domyślam się, że głównym powodem jest środek między twoją odpowiedzią a tą odpowiedzią, którą znalazłem na githubie. "Image.lock(), który odrzuca wszystkie aktualizacje buforów, dopóki Image.unlock() nie zostanie wywołany" język nie jest ObjC, ale znaczenie powinno być takie samo. – Andrea

0

Chciałbym podać więcej wskazówek na temat tej funkcji, wykonałem już kilka testów i mogę ci to powiedzieć.
Po znalezieniu adresu bazowego prawdopodobnie otrzymujesz adres jakiegoś zasobu pamięci współdzielonej. Staje się to jasne, jeśli drukujesz adres bazowy, dzięki czemu możesz zauważyć, że adresy bazowe powtarza się podczas pobierania klatek wideo.
W mojej aplikacji pobieram ramki w określonych odstępach czasu i przekazuję CVImageBufferRef do podklasy NSOperation, która konwertuje bufor na obraz i zapisuje go w telefonie. Nie blokuję bufora pikseli, dopóki operacja nie rozpocznie konwersji CVImageBufferRef, nawet jeśli przesunie się do wyższych ramek, adres bazowy piksela i adres bufora CVImageBufferRef są równe przed utworzeniem NSOperation i wewnątrz niego. Zachowuję tylko CVImageBufferRef. Spodziewałem się odznaczenia referencji i nawet jeśli nie widziałem, domyślam się, że najlepszym opisem jest to, że CVPixelBufferLockBaseAddress blokuje część pamięci, w której znajduje się bufor, co uniemożliwia dostęp z innych zasobów, więc zachowa te same dane, dopóki odblokujesz to.

+0

Czy możesz podać przykładowy kod, aby zobaczyć, o czym mówisz? Mam pewne problemy w specyficznym przetwarzaniu CMSampleBufferRef i losowe EXC_BAD_ACCESS podczas CVPixelBufferGetBaseAddress. –