2015-11-03 66 views
4

问题
当我停止运行AVCaptureSession时,在我的AVCaptureSession中创建的线程不会关闭。AVCaptureSession和摄像头线程不关闭[iOS]

症状
通常我的dispatch_queue从相机获取帧即刻开始。但是在打开和关闭打开/关闭AVCaptureSession的ViewController大约四次后,dispatch_queue需要大约十秒钟才能启动。

预后
看来,与AVCaptureSession相关的线程不被清除。

后,我关闭AVCaptureSession我看到这些线程保持:

com.apple.coremedia.capturesource.connections(serial) 1 Pending Block 
com.apple.coremedia.capturesession.connections(serial) 1 Pending Block 
<AVCMNotificationDispatcher: 0x16bce00> serial queue(serial) 4 Pending Blocks 
com.apple.avfoundation.videocapturedevice.observed_properties_queue(serial) 
com.apple.tcc.cache_queue(serial) 1 Pending Block 
com.apple.tcc.preflight.kTCCServiceCamera(serial) 1 Pending Block 

并与AVCaptureSession我打开后/关闭的ViewController,同一线程保持,但是这三个线程都增加待定块

<AVCMNotificationDispatcher: 0x17c441a0> serial queue (serial) 9 Pending Blocks 
com.apple.avfoundation.videocapturedevice.observed_properties_queue(serial) 
com.apple.tcc.preflight.kTCCServiceCamera(serial) 5 Pending Blocks 

代码设置

VideoSource.h和VideoSource.mm

在我的ViewController我初始化这样的:

self.videoSource = [[VideoSource alloc] init]; 
self.videoSource.delegate = self; 
[self.videoSource setResolution:AVCaptureSessionPreset352x288]; // was 640 
[self.videoSource startWithDevicePosition:AVCaptureDevicePositionFront]; 

我开始和停止captureSession如下所示,启动和停止好了。实际的抓图效果非常好。

[self.videoSource.captureSession startRunning]; 
    [self.videoSource.captureSession stopRunning]; 

VideoSource的相关部分,如果您需要了解更多信息,请告诉我们。

从VideoSource.mm

- (void)dealloc { 
NSLog(@"Cleaning Up Video Source"); 
[_captureSession stopRunning]; 

AVCaptureInput* input = [_captureSession.inputs objectAtIndex:0]; 
[_captureSession removeInput:input]; 
input = nil; 

AVCaptureVideoDataOutput* output = (AVCaptureVideoDataOutput*)[_captureSession.outputs objectAtIndex:0]; 
[_captureSession removeOutput:output]; 
output = nil; 

_captureSession = nil; 
_deviceInput = nil; 
_delegate = nil; 

// [super dealloc]; // compiler handles this for you with ARC 
} 


- (void) addVideoDataOutput { 
// (1) Instantiate a new video data output object 
AVCaptureVideoDataOutput * captureOutput = [[AVCaptureVideoDataOutput alloc] init ]; 
// captureOutput.alwaysDiscardsLateVideoFrames = YES; 

NSLog(@"Create Dispatch Queue"); 


// (2) The sample buffer delegate requires a serial dispatch queue 
dispatch_queue_t queue; 
queue = dispatch_queue_create("com.name.test", DISPATCH_QUEUE_SERIAL); 
[captureOutput setSampleBufferDelegate:self queue:queue]; 

// dispatch_release(queue); // compiler handles this for you with ARC 

// (3) Define the pixel format for the video data output 
NSString * key = (NSString*)kCVPixelBufferPixelFormatTypeKey; 
NSNumber * value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; 
NSDictionary * settings = @{key:value}; 

NSLog(@"Set Video Settings"); 

[captureOutput setVideoSettings:settings]; 

NSLog(@"Always Discard Late Video Frames"); 

[captureOutput setAlwaysDiscardsLateVideoFrames:YES]; 
// (4) Configure the output port on the captureSession property 

[self.captureSession addOutput:captureOutput]; 
} 

而且从VideoSource.h

@interface VideoSource : NSObject 

@property (nonatomic, strong) AVCaptureSession * captureSession; 
@property (nonatomic, strong) AVCaptureDeviceInput * deviceInput; 
@property (nonatomic, weak) id<VideoSourceDelegate> delegate; 

- (BOOL)startWithDevicePosition:(AVCaptureDevicePosition)devicePosition; 
- (void) setResolution:(NSString*)resolution; 

@end 

请求

如何确保这些线程关闭的时候我解除分配VideoSource?

+0

我有同样的问题。我处于更糟糕的情况,因为我正在使用我无法控制的相机库。在用照相机解散所述视图控制器之后,它会导致愚蠢的东西,例如有时候呆在那里。谁知道还有什么。 – mskw

+0

嗨Airman,你是如何看待你目前所有的线程? –

+0

@mskw:查看我的新解决方案 – Airman00

回答

2

解决了!

解决方案:调用startRunning并停止从您用于CaptureOutput的SampleBuffer队列的相同dispatch_queue中运行。

这是我的新格局:

#import "VideoSource.h" 

@interface VideoSource() <AVCaptureVideoDataOutputSampleBufferDelegate> 

// Session management. 
@property (nonatomic) dispatch_queue_t sessionQueue; 
@property (nonatomic) AVCaptureSession *captureSession; 
@property (nonatomic) AVCaptureDeviceInput *deviceInput; 

/*@property (nonatomic, strong) AVCaptureSession * captureSession; 
@property (nonatomic, strong) AVCaptureDeviceInput * deviceInput; */ 

@end 

@implementation VideoSource 


-(id) init{ 
    if(self = [super init]){ 
     self.captureSession = [[AVCaptureSession alloc] init]; 
     self.sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL); 

    } 
    return self; 
} 

然后使用同样的sessionQueue您setSampleBufferDelegate队列。

[captureOutput setSampleBufferDelegate:self queue:self.sessionQueue]; 

现在到了最重要的部分,确保从最相同的队列调用startRunning/stopRunning:同样

dispatch_async(self.sessionQueue, ^{ 
    [self.captureSession startRunning]; 

}); 

,你可以创建一个不错的小功能来清理和停止captureSession :

-(void)closeCaptureSession { 

    dispatch_async(self.sessionQueue, ^{ 

     if([_captureSession isRunning])[_captureSession stopRunning]; 

     [_captureSession stopRunning]; 

     // Remove all inputs 
     for(AVCaptureInput *input1 in _captureSession.inputs) { 
      [_captureSession removeInput:input1]; 
     } 

     // Remove all outputs 
     for(AVCaptureVideoDataOutput *output1 in _captureSession.outputs) { 
      [output1 setSampleBufferDelegate:nil queue:NULL]; 
      [_captureSession removeOutput:output1]; 
     } 

     // Set to Nil to make ARC's job a little easier 
     self.captureSession = nil; 
     self.deviceInput = nil; 
     self.delegate = nil; 
     self.sessionQueue=nil; 
    }); 

}