2011-06-24 12 views
7


Estoy escribiendo una aplicación de iPhone que crea imágenes fijas desde la cámara utilizando AVFoundation. Leyendo la guía de programación Encontré un código que casi tengo que hacer, así que estoy tratando de "invertir la ingeniería" y entenderlo.
Estoy encontrando algunas dificultades para comprender la parte que convierte un CMSampleBuffer en una imagen.
Así que aquí está lo que entendí y más tarde el código.
El CMSampleBuffer representa un búfer en la memoria donde se almacena la imagen con datos adicionales. Más tarde llamo a la función CMSampleBufferGetImageBuffer() para recibir un CVImageBuffer con solo los datos de la imagen.
Ahora hay una función que no entendí y solo puedo imaginar su función: CVPixelBufferLockBaseAddress (imageBuffer, 0); No puedo entender si es un "bloqueo de hilo" para evitar operaciones múltiples en él o un bloqueo a la dirección del búfer para evitar cambios durante la operación (y ¿por qué debería cambiar? ... otro fotograma, no se copian datos en otro lugar?). El resto del código es claro para mí.
Intenté buscar en google pero todavía no encontré nada útil.
¿Alguien puede traer algo de luz?CVPixelBufferLockBaseAddress ¿por qué? Capturar imagen fija usando 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); 
} 

Gracias, Andrea

Respuesta

3

El archivo de cabecera dice que CVPixelBufferLockBaseAddress hace que la memoria "accesible". No estoy seguro de lo que eso significa exactamente, pero si no lo haces, CVPixelBufferGetBaseAddress falla, así que será mejor que lo hagas.

EDITAR

Eso sí, es la respuesta corta. ¿Por qué considerar que la imagen no puede vivir en la memoria principal, puede vivir en una textura en alguna GPU en algún lugar (CoreVideo también funciona en Mac) o incluso en un formato diferente al que espera, por lo que los píxeles que obtiene son en realidad una dupdo. Sin Lock/Unlock o algún tipo de par Begin/End, la implementación no tiene forma de saber cuándo ha terminado con los píxeles duplicados para que se filtren efectivamente. CVPixelBufferLockBaseAddress simplemente da información sobre el alcance de CoreVideo, no me gustaría colgarlo demasiado.

Sí, podrían simplemente haber devuelto los píxeles de CVPixelBufferGetBaseAddress y eliminar CVPixelBufferLockBaseAddress por completo. No sé por qué no hicieron eso.

+0

Gracias, eso es una pista.Como en las funciones llamadas no hay rastro de copiar o crear, estoy empezando a pensar que el búfer se pasa por referencia, por lo que es un tipo de congelación del búfer de memoria. – Andrea

+0

Agregué algunas razones posibles sobre el por qué. –

+0

YEP, supongo que la razón principal es un punto medio entre su respuesta y la que encontré en github. "Image.lock(), que difiere todas las actualizaciones de búfer hasta que se llame de nuevo a Image.unlock()", el idioma no es ObjC, pero el significado debe ser el mismo. – Andrea

0

Me gustaría dar más pistas sobre esta función, hice algunas pruebas hasta ahora y puedo decirlo.
Cuando obtiene la dirección base, probablemente obtenga la dirección de algún recurso de memoria compartida. Esto queda claro si imprime la dirección de la base, y puede ver que las direcciones base se repiten al obtener marcos de video.
En mi aplicación, tomo marcos a intervalos específicos y paso el CVImageBufferRef a una subclase NSOperation que convierte el búfer en una imagen y la guarda en el teléfono. No bloqueo el buffer de píxeles hasta que la operación comience a convertir el CVImageBufferRef, incluso si presionar una fotograma mayor, la dirección base del píxel y la dirección del buffer CVImageBufferRef son iguales antes de la creación del NSOperation y dentro de él. Solo conservo el CVImageBufferRef. Esperaba encontrar referencias que no coinciden y, aunque no lo vi, creo que la mejor descripción es que CVPixelBufferLockBaseAddress bloquea la parte de la memoria donde se encuentra el búfer, por lo que es inaccesible desde otros recursos, por lo que conservará los mismos datos, hasta lo desbloqueas

+0

¿Podría proporcionar algún código de muestra para ver de qué está hablando? Tengo algunos problemas en el procesamiento específico de CMSampleBufferRef y al azar EXC_BAD_ACCESS mientras CVPixelBufferGetBaseAddress. –

Cuestiones relacionadas