Как правильно очистить AVCaptureSession и AVCaptureVideoPreviewLayer
Я использую API AVFoundation для создания предварительного просмотра камеры, и у меня возникают проблемы с очисткой после того, как я закончил.
Лучший ответ, который я нашел на эту проблему, находится в этой теме, спасибо Codo.
Тем не менее, он не обращается к освобождению AVCaptureVideoPreviewLayer, и вот где у меня возникают проблемы.
В моем классе контроллера представления у меня есть некоторый код инициализации в методе startCameraCapture. Слушая ответ Кодо, я использую dispatch_set_finalizer_f(_captureQueue, capture_cleanup);
зарегистрировать обратный вызов для вызова, когда очередь действительно закрыта. Я также сохраняю себя, чтобы убедиться, что мой объект не исчезнет до того, как очередь завершит вызов моего объекта. Затем я использую обратный вызов capture_cleanup для освобождения себя.
-(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 Stackru answer https://stackru.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];
}
Вот обратный вызов capture_cleanup:
static void capture_cleanup(void* p)
{
LiveCompViewController* ar = (LiveCompViewController*)p;
[ar release]; // releases capture session if dealloc is called
}
Тогда мой код очистки выглядит так:
-(void) stopCameraCapture {
[_camSession stopRunning];
[_camSession release];
_camSession=nil;
// Remove the layer in order to release the camSession
[_previewLayer removeFromSuperlayer];
_previewLayer = nil;
}
У меня проблема в том, что удаление _previewLayer из суперслоя в stopCameraCapture вызывает следующую ошибку консоли:
"... изменяющий слой, который завершается..."
Но мне нужно удалить слой, чтобы он был освобожден и освобожден, чтобы он освободил _camSession, который, в свою очередь, освобождает dispatch_queue, а затем, наконец, вызывает мой обратный вызов capture_cleanup, который, наконец, освобождает себя.
Я не понимаю, почему я получаю ошибку консоли и как ее исправить. Почему Слой завершается в то время, когда я звоню [_previewLayer removeFromSuperlayer]
если self.dealloc не был вызван.
Примечание: self - это viewController, и я еще не добавил его, поэтому он сохраняется NavigationContoller.
1 ответ
Попробуйте остановить сеанс перед выпуском:
[captureSession stopRunning];