如何正确清理 AVCaptureSession 和 AVCaptureVideoPreviewLayer
Posted
技术标签:
【中文标题】如何正确清理 AVCaptureSession 和 AVCaptureVideoPreviewLayer【英文标题】:How do I properly cleanup an AVCaptureSession and AVCaptureVideoPreviewLayer 【发布时间】:2011-03-23 18:52:18 【问题描述】:我正在使用 AVFoundation api 创建相机预览视图,完成后我无法清理。
我发现这个问题的最佳答案是SO thread,感谢 Codo。
但是,他没有解决 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 *** answer https://***.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 的超级层中删除 _previewLayer 会导致以下控制台错误:
"...修改正在完成的层..."
但是我需要删除层,以便它被释放和解除分配,以便它释放 _camSession,这反过来又释放 dispatch_queue,然后最终调用我的 capture_cleanup 回调,最终释放自我。
我不明白为什么我会收到控制台错误以及如何解决它。如果 self.dealloc 没有被调用,为什么在我打电话给[_previewLayer removeFromSuperlayer]
的时候图层正在完成。
注意:self是一个viewController,我还没有弹出它,所以它被NavigationContoller保留了。
【问题讨论】:
【参考方案1】:尝试在释放之前停止会话:
[captureSession stopRunning];
【讨论】:
以上是关于如何正确清理 AVCaptureSession 和 AVCaptureVideoPreviewLayer的主要内容,如果未能解决你的问题,请参考以下文章
如何让 AVCaptureSession 和 AVPlayer 尊重 AVAudioSessionCategoryAmbient?
如何在 AVCaptureSession 上设置音频采样率?
如何将多个音频 AVCaptureDevice 添加到 AVCaptureSession
如何记录使用 AVCaptureSession 捕获的第一个和最后一个电影帧的确切时间?