2011-03-23 10 views
7

Estoy utilizando la API AVFoundation para crear una vista previa de la cámara y tengo problemas para limpiar después de que haya terminado.¿Cómo puedo limpiar correctamente una sesión AVCaptureSession y AVCaptureVideoPreviewLayer?

La mejor respuesta que he encontrado para este problema es en este SO thread, gracias Codo.

Sin embargo, no aborda la desasignación de AVCaptureVideoPreviewLayer, y es allí donde tengo problemas.

En mi vista, la clase de controlador I tiene un código de inicialización en un método startCameraCapture. Al escuchar la respuesta de Codo, estoy usando dispatch_set_finalizer_f(_captureQueue, capture_cleanup); para registrar una devolución de llamada a ser llamada cuando la cola está realmente cerrada. También me estoy conservando, para asegurarme de que mi objeto no se va antes de que la cola termine de llamar a mi objeto. Luego uso la captura de llamada capture_cleanup para liberarlo.

-(void) startCameraCapture { 
    _camSession = [[AVCaptureSession alloc] init]; 
    if (_previewLayer == nil) { 
     _previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_camSession]; 
    } 
    _previewLayer.frame = self.compView.bgView.frame; 
    [self.compView.bgView.layer addSublayer:_previewLayer]; 

    // Get the default camera device 
    AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 

    // Create a AVCaptureInput with the camera device 
    NSError *error=nil; 
    AVCaptureInput* cameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:camera error:&error]; 
    if (cameraInput == nil) { 
     NSLog(@"Error to create camera capture:%@",error); 

    } 

    AVCaptureVideoDataOutput* videoOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease]; 

    // create a queue to run the capture on 
    _captureQueue=dispatch_queue_create("captureQueue", NULL); 
    dispatch_set_context(_captureQueue, self); 
    dispatch_set_finalizer_f(_captureQueue, capture_cleanup); 

    // setup our delegate 
    [videoOutput setSampleBufferDelegate:self queue:_captureQueue]; 

    dispatch_release(_captureQueue); 

    // retain self as a workouround a queue finalization bug in apples's sdk 
    // per Stackoverflow answer https://stackoverflow.com/questions/3741121/how-to-properly-release-an-avcapturesession 
    [self retain]; 

    // configure the pixel format 
    videoOutput.videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey, 
           nil]; 

    // and the size of the frames we want 
    [_camSession setSessionPreset:AVCaptureSessionPresetMedium]; 

    // Add the input and output 
    [_camSession addInput:cameraInput]; 
    [_camSession addOutput:videoOutput]; 

    [cameraInput release]; 

    // Start the session 
    [_camSession startRunning];  
} 

Aquí la devolución de llamada capture_cleanup:

static void capture_cleanup(void* p) 
    { 
     LiveCompViewController* ar = (LiveCompViewController*)p; 
     [ar release]; // releases capture session if dealloc is called 
    } 

Entonces mi código de limpieza se parece a esto:

-(void) stopCameraCapture { 
[_camSession stopRunning]; 
    [_camSession release]; 
    _camSession=nil;  

    // Remove the layer in order to release the camSession 
    [_previewLayer removeFromSuperlayer]; 
    _previewLayer = nil; 

} 

El problema que estoy teniendo es que la eliminación de la _previewLayer del superlayer en stopCameraCapture está causando el siguiente error de consola:

"...modifying layer that is being finalized..."

Pero tengo que quitar la capa para que se libere y se desasigne para que libere _camSession que a su vez libera el dispatch_queue y finalmente llama a mi captura de llamada capture_cleanup que finalmente se libera.

No entiendo por qué me aparece el error de la consola y cómo solucionarlo. ¿Por qué está finalizando la capa en el momento en que llamo al [_previewLayer removeFromSuperlayer] si no se ha llamado a self.dealloc?

Nota: self es un viewController y aún no lo he copiado, por lo que lo conserva el NavigationContoller.

Respuesta

2

Intente detener la sesión antes de soltar:

[captureSession stopRunning]; 
Cuestiones relacionadas