2011-03-23 129 views
7

我正在使用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保留。

回答

2

嘗試釋放之前停止該會話:

[captureSession stopRunning];