Cómo liberar correctamente una AVCaptureSession
Estoy usando las clases de AV Foundation para capturar la transmisión de video en vivo desde la cámara y procesar las muestras de video. Esto funciona muy bien. Sin embargo, tengo problemas para liberar correctamente las instancias de la base AV (sesión de captura, capa de vista previa, entrada y salida) una vez que haya terminado.
Cuando ya no necesito la sesión y todos los objetos asociados, detengo la sesión de captura y la libero. Esto funciona la mayor parte del tiempo. Sin embargo, a veces la aplicación se bloquea con una señal EXEC_BAD_ACCESS generada en el segundo subproceso creado por la cola de envío (y donde se procesan las muestras de video). El bloqueo se debe principalmente a mi propia instancia de clase, que sirve como delegado del búfer de muestra y se libera después de detener la sesión de captura.
La documentación de Apple menciona el problema: detener la sesión de captura es una operación asincrónica. Es decir: no sucede de inmediato. En particular, el segundo hilo continúa procesando muestras de video y accede a diferentes instancias como la sesión de captura o los dispositivos de entrada y salida.
Entonces, ¿cómo libero correctamente AVCaptureSession y todas las instancias relacionadas? ¿Hay alguna notificación que me diga de manera confiable que AVCaptureSession ha finalizado?
Aquí está mi código:
Declaraciones:
AVCaptureSession* session;
AVCaptureVideoPreviewLayer* previewLayer;
UIView* view;
Configuración de instancias:
AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
session = [[AVCaptureSession alloc] init];
AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice: camera error: &error];
[session addInput: input];
AVCaptureVideoDataOutput* output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
[session addOutput: output];
dispatch_queue_t queue = dispatch_queue_create("augm_reality", NULL);
[output setSampleBufferDelegate: self queue: queue];
dispatch_release(queue);
previewLayer = [[AVCaptureVideoPreviewLayer layerWithSession: session] retain];
previewLayer.frame = view.bounds;
[view.layer addSublayer: previewLayer];
[session startRunning];
Limpiar:
[previewLayer removeFromSuperlayer];
[previewLayer release];
[session stopRunning];
[session release];