AVCaptureSession - Stop Running - take a long long time

11,349

According to the AV Cam View Controller Example calling startRunning or stopRunning does not return until the session completes the requested operation. Since you are sending these messages to the session on the main thread, it freezes all the UI until the requested operation completes. What I would recommend is that you wrap your calls in an Asynchronous dispatch so that the view does not lock-up.

- (void)cancelled 
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self stopCapture];
    });

   //You might want to think about putting the following in another method
   //and calling it when the stop capture method finishes
   wasCancelled = YES;
   if (delegate != nil) {
        [delegate zxingControllerDidCancel:self];
   }
} 
Share:
11,349
Romain Dorange
Author by

Romain Dorange

Updated on June 22, 2022

Comments

  • Romain Dorange
    Romain Dorange about 2 years

    I use ZXing for an app, this is mainly the same code than the ZXing original code except that I allow to scan several time in a row (ie., the ZXingWidgetController is not necesseraly dismissed as soon as something is detected).

    I experience a long long freeze (sometimes it never ends) when I press the dismiss button that call

    - (void)cancelled {
      //  if (!self.isStatusBarHidden) {
      //      [[UIApplication sharedApplication] setStatusBarHidden:NO];
      //  }
    
        [self stopCapture];
    
        wasCancelled = YES;
        if (delegate != nil) {
            [delegate zxingControllerDidCancel:self];
        }
    
    
    } 
    

    with

    - (void)stopCapture {
        decoding = NO;
    #if HAS_AVFF
    
    
        if([captureSession isRunning])[captureSession stopRunning];
        AVCaptureInput* input = [captureSession.inputs objectAtIndex:0];
        [captureSession removeInput:input];
        AVCaptureVideoDataOutput* output = (AVCaptureVideoDataOutput*)[captureSession.outputs objectAtIndex:0];
        [captureSession removeOutput:output];
        [self.prevLayer removeFromSuperlayer];
    
        /*
         // heebee jeebees here ... is iOS still writing into the layer?
         if (self.prevLayer) {
         layer.session = nil;
         AVCaptureVideoPreviewLayer* layer = prevLayer;
         [self.prevLayer retain];
         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 12000000000), dispatch_get_main_queue(), ^{
         [layer release];
         });
         }
         */
    
        self.prevLayer = nil;
        self.captureSession = nil;
    #endif
    }
    

    (please notice that the dismissModalViewController that remove the view is within the delegate method)

    I experience the freeze only while dismissing only if I made several scans in a row, and only with an iPhone 4 (no freeze with a 4S)

    Any idea ?

    Cheers

    Rom

  • Krumelur
    Krumelur over 11 years
    Be careful with that! stopCapture manipulates the view hierarchy according to the code above. Never manipulate GUI from outside of the GUI thread.
  • Endama
    Endama over 11 years
    Ahh good catch @Krumelur yea the [self.prevLayer removeFromSuperlayer] calling should be done on the main thread
  • Romain Dorange
    Romain Dorange over 11 years
    Thanks for your answer. I know I am a bit late but the help was really useful !
  • NSologistic
    NSologistic about 9 years
    @Endama I am trying to implement this solution. I don't really understand your comment on [self.prevLayer removeFromSuperlayer] being done in the main thread.
  • Endama
    Endama about 9 years
    @NSologistic You can't manipulate any views unless they are done on the main thread. The stopCapture method calls removeFromSuperlayer. Removing and adding any view elements always needs to be done on the main thread.