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.