如何正确清理AVCaptureSession和AVCaptureVideoPreviewLayer?

7
我正在使用AVFoundation api创建相机预览视图,但在完成后就遇到了麻烦。关于这个问题,我找到了一个最好的答案,在这个SO线程中,感谢Codo。
然而,他没有解决AVCaptureVideoPreviewLayer的释放问题,这也是我遇到的问题所在。
在我的视图控制器类中,我有一些初始化代码在startCameraCapture方法中。听从Codo的建议,我使用dispatch_set_finalizer_f(_captureQueue, capture_cleanup);来注册一个回调函数,以便在队列真正关闭时调用它。 我还保留了self,以确保在队列完成调用对象之前,我的对象不会消失。然后我使用capture_cleanup回调来释放self。
-(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://dev59.com/62865IYBdhLWcg3wlvmq
    [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会导致以下控制台错误:
"......修改正在被完成的图层......"
但我需要删除该层,以便它被释放和解除分配,从而释放_camSession,进而释放dispatch_queue,最后调用我的capture_cleanup回调函数,最终释放self。
我不明白为什么我会收到控制台错误以及如何修复它。如果self.dealloc尚未被调用,为什么在我调用[_previewLayer removeFromSuperlayer]时该层被完成了。
注意:self是一个viewController,我还没有弹出它,因此它由NavigationContoller保留。
1个回答

3

在释放之前尝试停止会话:

[captureSession stopRunning];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接