AVCaptureSession и потоки камеры не закрываются [iOS]

Проблема
Потоки, созданные во время сеанса AVCaptureSession, не закрываются, когда я прекращаю выполнение сеанса AVCaptureSession.

Симптомы
Обычно моя диспетчерская_очередь, получающая кадры с камеры, запускается мгновенно. Но после четырехкратного открытия и закрытия ViewController, который открывает/закрывает AVCaptureSession, запуск 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

И после того, как я открываю/закрываю ViewController с помощью AVCaptureSession, те же потоки остаются, но эти три потока имеют увеличенное количество ожидающих блоков.

<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?


person Airman00    schedule 03.11.2015    source источник
comment
У меня точно такая же проблема. Я в худшей ситуации, потому что использую библиотеку камер, которую не могу контролировать. После отключения указанного контроллера представления с камерой это приведет к глупым вещам, таким как светодиод, который иногда остается включенным. Кто знает, что еще.   -  person mskw    schedule 06.11.2015
comment
Эй, Airman, как ты просматриваешь все свои текущие треды?   -  person A O    schedule 29.11.2015
comment
@mskw: посмотри мое новое решение   -  person Airman00    schedule 30.11.2015
comment
@AO Просто приостановите работающее приложение внутри Xcode, и вы увидите список потоков на левой боковой панели.   -  person Airman00    schedule 30.11.2015


Ответы (1)


Решил!

Решение. Вызовите startRunning и stopRunning из той же dispatch_queue, которую вы использовали для очереди SampleBuffer для CaptureOutput.

Вот моя новая установка:

#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;
     });

}
person Airman00    schedule 11.11.2015