我正在使用AVFoundation api創建相機預覽視圖,並且在完成後我遇到了清理問題。如何正確清理AVCaptureSession和AVCaptureVideoPreviewLayer
我發現這個問題的最佳答案是在SO thread,謝謝科多。
但是,他沒有解決AVCaptureVideoPreviewLayer的重新分配問題,這就是我遇到麻煩的地方。
在我的視圖控制器類中我有startCameraCapture方法中的一些初始化代碼。聽着Codo的回答,我使用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 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];
}
這裏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;
}
我遇到的問題是,從stopCameraCapture的superlayer去除_previewLayer導致以下控制檯錯誤:
"...modifying layer that is being finalized..."
但我需要刪除該層,以便它釋放並釋放,以便它釋放_camSession,然後釋放dispatch_queue,最後調用我的capture_cleanup回調,最終釋放self。
我不明白爲什麼我得到控制檯錯誤以及如何解決它。爲什麼當我打電話給[_previewLayer removeFromSuperlayer]
時,如果self.dealloc沒有被調用,該圖層正在最終確定。
注意:self是viewController,我還沒有彈出它,所以它由NavigationContoller保留。