如何正确释放AVCaptureSession [英] How to properly release an AVCaptureSession

查看:1790
本文介绍了如何正确释放AVCaptureSession的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用AV Foundation类来捕获来自相机的实况视频流,并处理视频样本。这工作很好。但是,一旦完成,我确实无法正确地释放AV基础实例(捕获会话,预览图层,输入和输出)。



当我不再需要会话和所有相关对象,我停止捕获会话并释放它。这在大多数时间工作。但是,有时应用程序崩溃,在调度队列创建的第二个线程中产生一个EXEC_BAD_ACCESS信号(并且处理视频样本)。崩溃主要是由于我自己的类实例,它用作示例缓冲区委托,并在我停止捕获会话后释放。



Apple文档提到问题:停止捕获会话是异步操作。这是:它不会立即发生。特别是,第二个线程继续处理视频样本,并访问不同的实例,如捕获会话或输入和输出设备。



那么如何正确释放AVCaptureSession和所有相关实例?是否有可靠的告诉我AVCaptureSession已经完成了?



这是我的代码:



声明:

  AVCaptureSession * session; 
AVCaptureVideoPreviewLayer * previewLayer;
UIView * view;

设置实例:

  AVCaptureDevice * camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
session = [[AVCaptureSession alloc] init];

AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:camera error:& error];
[session addInput:input];
AVCaptureVideoDataOutput * output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
[session addOutput:output];

dispatch_queue_t queue = dispatch_queue_create(augm_reality,NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);

previewLayer = [[AVCaptureVideoPreviewLayer layerWithSession:session] retain];
previewLayer.frame = view.bounds;
[view.layer addSublayer:previewLayer];

[session startRunning];

清理:

 code> [previewLayer removeFromSuperlayer]; 
[previewLayer release];
[session stopRunning];
[session release];


解决方案

这里是我发现的最好的解决方案。基本思想是使用调度队列的终结器。当分派队列退出时,我们可以确保在处理样例缓冲区的第二个线程中不会有任何更多的操作。

  static void capture_cleanup(void * p)
{
AugmReality * ar =(AugmReality *)p; // cast to original context instance
[ar release]; //释放捕获会话如果dealloc被调用
}

...

dispatch_queue_t queue = dispatch_queue_create(augm_reality,NULL);
dispatch_set_context(queue,self);
dispatch_set_finalizer_f(queue,capture_cleanup);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
[self retain];不幸的是,我现在不得不明确地停止捕获。。否则释放我的实例不会释放它,因为第二个线程现在递增和递减计数器。



另一个问题是我的类现在从两个不同的线程。这是可靠的,还是下一个导致崩溃的问题?


I'm using the AV Foundation classes to capture the live video stream from the camera and to process the video samples. This works nicely. However, I do have problems properly releasing the AV foundation instances (capture session, preview layer, input and output) once I'm done.

When I no longer need the session and all associated objects, I stop the capture session and release it. This works most of the time. However, sometimes the app crashes with a EXEC_BAD_ACCESS signal raised in second thread that was created by the dispatch queue (and where the video samples are processed). The crash is mainly due to my own class instance, which serves as the sample buffer delegate and is freed after I've stop the capture session.

The Apple documentation mentions the problem: Stopping the capture session is an asynchronous operation. That is: it doesn't happen immediately. In particular, the second thread continues to process video samples and access different instances like the capture session or the input and output devices.

So how do I properly release the AVCaptureSession and all related instances? Is there a notification that reliably tells me that the AVCaptureSession has finished?

Here's my code:

Declarations:

AVCaptureSession* session;
AVCaptureVideoPreviewLayer* previewLayer;
UIView* view;

Setup of instances:

AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
session = [[AVCaptureSession alloc] init];

AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice: camera error: &error];
[session addInput: input];
AVCaptureVideoDataOutput* output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
[session addOutput: output];

dispatch_queue_t queue = dispatch_queue_create("augm_reality", NULL);
[output setSampleBufferDelegate: self queue: queue];
dispatch_release(queue);

previewLayer = [[AVCaptureVideoPreviewLayer layerWithSession: session] retain];
previewLayer.frame = view.bounds;
[view.layer addSublayer: previewLayer];

[session startRunning];

Cleanup:

[previewLayer removeFromSuperlayer];
[previewLayer release];
[session stopRunning];
[session release];

解决方案

Here's the best solution I've found so far. The basic idea is to use the finalizer of the dispatch queue. When the dispatch queue quits, we can be sure that there won't be any more action in the second thread where the sample buffers are processed.

static void capture_cleanup(void* p)
{
    AugmReality* ar = (AugmReality *)p; // cast to original context instance
    [ar release];  // releases capture session if dealloc is called
}

...

dispatch_queue_t queue = dispatch_queue_create("augm_reality", NULL);
dispatch_set_context(queue, self);
dispatch_set_finalizer_f(queue, capture_cleanup);
[output setSampleBufferDelegate: self queue: queue];
dispatch_release(queue);
[self retain];

...

Unfortunately, I now have to explicitly stop capturing. Otherwise releasing my instance won't free it because the second thread now increments and decrements the counter as well.

A further problem is that my class is now released from two different threads. Is this reliable or is it the next problem causing crashes?

这篇关于如何正确释放AVCaptureSession的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆