2015-12-15 11 views
1

Я снимаю изображения с камеры iPhone с помощью AVCaptureSession, AVCaptureDeviceInput, AVCaptureVideoDataOutput.Остановка сеанса захвата камеры в iOS-камере

захвата изображения выполнен в виде

 dispatch_queue_t sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL); 
     [self setSessionQueue:sessionQueue]; 
     //we will use a separate dispatch session not to block the main queue in processing 
     dispatch_queue_t im_processingQueue = dispatch_queue_create("im_processing queue", DISPATCH_QUEUE_SERIAL); 
     [self setIm_processingQueue:im_processingQueue]; 

     dispatch_async(sessionQueue, ^{ 
      [self setBackgroundRecordingID:UIBackgroundTaskInvalid]; 

      NSError *error = nil; 

      AVCaptureDevice *videoDevice = [RecordViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack]; 

      AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error]; 

      if (error) 
      { 
       NSLog(@"%@", error); 
      } 
      [(AVCaptureVideoPreviewLayer *)[[self previewView] layer] setVideoGravity:AVLayerVideoGravityResizeAspectFill]; 
      if ([session canAddInput:videoDeviceInput]) 
      { 
       [session addInput:videoDeviceInput]; 
       [self setVideoDeviceInput:videoDeviceInput]; 

       dispatch_async(dispatch_get_main_queue(), ^{ 
        // Why are we dispatching this to the main queue? 
        // Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and UIView can only be manipulated on main thread. 
        // Note: As an exception to the above rule, it is not necessary to serialize video orientation changes on the AVCaptureVideoPreviewLayer’s connection with other session manipulation. 
        //[self previewView] layer 

        [[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] setVideoOrientation:(AVCaptureVideoOrientation)[[UIApplication sharedApplication] statusBarOrientation]]; 
       }); 
      } 

      AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject]; 
      AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error]; 

      if (error) 
      { 
       NSLog(@"%@", error); 
      } 

      if ([session canAddInput:audioDeviceInput]) 
      { 
       [session addInput:audioDeviceInput]; 
      } 

      AVCaptureVideoDataOutput *vid_Output = [[AVCaptureVideoDataOutput alloc] init]; 
      [vid_Output setSampleBufferDelegate:self queue:im_processingQueue]; 
      vid_Output.alwaysDiscardsLateVideoFrames = YES; 
      // Set the video output to store frame in BGRA (It is supposed to be faster) 
      NSDictionary* videoSettings = @{(__bridge NSString*)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]}; 
      [vid_Output setVideoSettings:videoSettings]; 
      if ([session canAddOutput:vid_Output]) 
      { 
       [session addOutput:vid_Output]; 
       AVCaptureConnection *connection = [vid_Output connectionWithMediaType:AVMediaTypeVideo]; 
       if ([connection isVideoStabilizationSupported]) 
        //[connection setEnablesVideoStabilizationWhenAvailable:YES]; 
        connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto; 
       [self setVid_Output:vid_Output]; 

      } 

     }); 

Внутри viewWillAppear, захват сеанса выполняется как

- (void)viewWillAppear:(BOOL)animated 
{ 
    //[super viewWillAppear:YES]; 
    dispatch_async([self sessionQueue], ^{ 
     [self addObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:SessionRunningAndDeviceAuthorizedContext]; 

     [self addObserver:self forKeyPath:@"vid_Output.recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext]; 
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]]; 

     __weak RecordViewController *weakSelf = self; 
     [self setRuntimeErrorHandlingObserver:[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureSessionRuntimeErrorNotification object:[self session] queue:nil usingBlock:^(NSNotification *note) { 
      RecordViewController *strongSelf = weakSelf; 
      dispatch_async([strongSelf sessionQueue], ^{ 
       // Manually restarting the session since it must have been stopped due to an error. 
       [[strongSelf session] startRunning]; 

      }); 
     }]]; 
     [[self session] startRunning]; 
    }); 
} 

Затем он остановился, как

- (void) stopCapturingCameraImages 
{ 
    dispatch_async([self sessionQueue], ^{ 
     [[self session] stopRunning]; 

     [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]]; 
     [[NSNotificationCenter defaultCenter] removeObserver:[self runtimeErrorHandlingObserver]]; 

     [self removeObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext]; 

     [self removeObserver:self forKeyPath:@"vid_Output.recording" context:RecordingContext]; 
    }); 

} 

Проблема заключается в удалении наблюдателей,

[self removeObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext]; 

[self removeObserver:self forKeyPath:@"vid_Output.recording" context:RecordingContext]; 

Программа разбилась после запуска этих двух removeObservers. Что может быть неправильным?

EDIT:

stopCapturingCameraImages is called from 
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 

    @autoreleasepool { 
     [_processing Searchobject_using_CPU_CascadeClassifier_for:img with_return_Rect:_rects]; 

dispatch_async(dispatch_get_main_queue(), ^{ 
        for (int lc = 0; lc < 
        if(_rects.count >0){ 
         [ self stopCapturingCameraImages]; 
        } 

       }); 

} 

EDIT 1:

Согласно @ SwiftArchitect-х внушения, я поставил, если ([[self session] isRunning]). Тогда это работает. я реализовал в

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:YES]; 
    [self stopCapturingCameraImages]; 
} 

- (void) stopCapturingCameraImages 
{ 
    dispatch_async([self sessionQueue], ^{ 
     if ([[self session] isRunning]){ 
     [[self session] stopRunning]; 

     [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]]; 
     [[NSNotificationCenter defaultCenter] removeObserver:[self runtimeErrorHandlingObserver]]; 

      [self removeObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext]; 

      [self removeObserver:self forKeyPath:@"vid_Output.recording" context:RecordingContext]; 
     } 
    }); 

} 
+0

@SwiftArchitect Да, когда я вызываю stopCapturingCameraImages в viewWillDisappear, никакой сбой программы. У меня есть другое место, чтобы вызвать stopCapturingCameraImages, то есть когда обнаружен объект в изображении. Мне нужно прекратить выполнение сеанса, чтобы начать работу над этим конкретным изображением. Он реализован в другой функции. Этот вызов приводит к сбою программы. Не вызов из viewWillDisappear. – batuman

+0

@SwiftArchitect Обновлено в EDIT. благодаря – batuman

ответ

1

К тому времени:

dispatch_async([self sessionQueue], ^{ 
    // ... 

    [self removeObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext]; 

    [self removeObserver:self forKeyPath:@"vid_Output.recording" context:RecordingContext]; 
}); 

выполняется, self (UIViewController), возможно, уже выполнили свою viewWillDisappear и удалили наблюдателя.

Выполнение заказов Whats выполнено в dispatch_get_main_queue и sessionQueue не обязательно, что вы ожидаете, или даже предсказуемым.


Исправление может быть столь же просто, как добавить проверку как if [[self session] isRunning] перед выполнением removeObserver, короткие добавления семафора.

 Смежные вопросы

  • Нет связанных вопросов^_^