2011-07-06 7 views
6

Estoy trabajando en más mini-proyectos que luego se incluirán en un nuevo proyecto. Básicamente es una unidad de prueba.Acelerar la imagen de guardado - iOS

Lo que estoy haciendo es crear un AVCaptureSession y luego crear un método para OutputSampleBufferDelegate. En el método, convierto el sampleBuffer en un UIImage y guardo el UIImage. Cuando ejecuto la aplicación en mi iPhone 4, solo puedo guardar 2-3 imágenes por segundo. Debe haber una manera más eficiente de guardar la imagen.

¿Alguien me puede ayudar a acelerarlo?

Gracias!

lots of the code is from here

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 
    UIImage *resultUIImage = [self imageFromSampleBuffer:sampleBuffer]; 

    NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(resultUIImage)]; 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *path = [paths objectAtIndex:0]; 

    CMTime frameTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); 

    NSString *filename = [NSString stringWithFormat:@"%f.png", CMTimeGetSeconds(frameTime)]; 

    NSString *finalPath = [path stringByAppendingString:filename]; 

    [imageData writeToFile:finalPath atomically:YES]; 
} 

// Create a UIImage from sample buffer data 
- (UIImage *)imageFromSampleBuffer:(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); 

    // Get the number of bytes per row for the pixel buffer 
    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; 
} 
+0

¿Qué tareas/llamadas toman más tiempo cuando ve su código en Insturments? – Mats

Respuesta

8

Utilizando este código, puedo obtener el tiempo que guarda la imagen hasta 0.1 segundos.

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
     fromConnection:(AVCaptureConnection *)connection 
{ 

    double frameTime = CFAbsoluteTimeGetCurrent(); 
    UIImage *resultUIImage = [self imageFromSampleBuffer:sampleBuffer]; 

    // takes freaking forever to do. 
    double pre = CFAbsoluteTimeGetCurrent(); 
    NSData *imageData = UIImageJPEGRepresentation(resultUIImage, 0.9); 
    NSLog(@"It took to write the file:%f",CFAbsoluteTimeGetCurrent()-pre); 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory 
                 ,NSUserDomainMask 
                 , YES); 
    NSString *path = [paths objectAtIndex:0]; 
    NSString *filename = [NSString stringWithFormat:@"%f.png", frameTime]; 
    NSString *finalPath = [path stringByAppendingString:filename]; 
    [imageData writeToFile:finalPath atomically:YES]; 
} 
+0

Agradable. Parece que el iPhone debe almacenar imágenes como JPG internamente, y la conversión a png fue el cuello de botella real, no escribir en el disco? – Meekohi

+0

Obtengo CGBitmapContextCreateImage: contexto inválido 0x0. Si desea ver la traza inversa, configure la variable de entorno CG_CONTEXT_SHOW_BACKTRACE. – loretoparisi

+0

¿No debería ser un .jpg en la penúltima línea? – shim

3

Podría por favor ver la cantidad de imágenes que se pueden generar si se comente la siguiente línea en su primer método:

[imageData writeToFile:finalPath atomically:YES]; 

La razón por la que digo esto es que se va pasar mucho tiempo escribiendo esa imagen en el disco. Sería interesante ver cómo funciona esto sin escribir las imágenes en el disco. Al menos de esa manera sabrá si todo el tiempo se invierte en crear la imagen en lugar de almacenar la imagen. O bien, podría hacer lo que se menciona en otro cartel y usar los instrumentos para calcular el tiempo que lleva dentro de cada método.

Si resulta que escribir las imágenes en el disco tarda demasiado, entonces sugiero tratar de implementar un mecanismo de caché que almacenará en caché las imágenes en la memoria y las escribirá en el disco más tarde.

También podría ser útil intentar llamar a writeToFile: atómicamente: en un hilo de fondo.

+0

gracias por comentar sobre esto. Eché un vistazo y medí lo que llevaba más tiempo. estaba convirtiendo la uiimage a un objeto NSData. Busqué en línea y encontré un método más eficiente (use la representación jpeg en lugar de png) – SamB

Cuestiones relacionadas