18

I have a main view controller and that segues to a second view controller that has an avcapturesession. The first time I segue from the main view controller to the capture session controller, it takes about 50ms (checked using 'instruments'). Then I segue back to the main view controller from the capture session and then back to the avcapturesession controller from the main controller. Each time it takes longer to segue from the main view controller to the avcapturesession and by the 5th or 6th iteration the segue takes about 10 seconds. (Compared with 50ms for first time.) I've pasted the relevant code for the avcapture session below. Can anyone help solve this? Thanks

This class (of type NSObject) manages the capture session for the second view controller
that actually implements the avcapturesession

#import "CaptureSessionManager.h"

@implementation CaptureSessionManager

@synthesize captureSession;
@synthesize previewLayer;

#pragma mark Capture Session Configuration

- (id)init {
    if ((self = [super init])) {
        [self setCaptureSession:[[AVCaptureSession alloc] init]];
    }
    return self;
}

- (void)addVideoPreviewLayer {
    [self setPreviewLayer:[[[AVCaptureVideoPreviewLayer alloc] initWithSession:[self     captureSession]] autorelease]];
    [[self previewLayer] setVideoGravity:AVLayerVideoGravityResizeAspectFill];

}

- (void)addVideoInput {
        AVCaptureDevice *videoDevice = [AVCaptureDevice   defaultDeviceWithMediaType:AVMediaTypeVideo];
     if (videoDevice) {
         NSError *error;
        AVCaptureDeviceInput *videoIn = [AVCaptureDeviceInput  deviceInputWithDevice:videoDevice error:&error];
        if (!error) {
           if ([[self captureSession] canAddInput:videoIn])
               [[self captureSession] addInput:videoIn];

        //else
        //  NSLog(@"Couldn't add video input");
    }

//  else
    //  NSLog(@"Couldn't create video input");
}
//else
//  NSLog(@"Couldn't create video capture device");
}

- (void)dealloc {

    [[self captureSession] stopRunning];

    [previewLayer release], previewLayer = nil;
    [captureSession release], captureSession = nil;

    [super dealloc];
}

 @end

The following is in the viewdidLoad method of the avcapture view controller:

[self setCaptureManager:[[CaptureSessionManager alloc] init]]; 

[[self captureManager] addVideoInput];

[[self captureManager] addVideoPreviewLayer];
CGRect layerRect = [[[self view] layer] bounds];
[[[self captureManager] previewLayer] setBounds:layerRect];
[[[self captureManager] previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),
                                                              CGRectGetMidY(layerRect))];

[[[self view] layer] addSublayer:[[self captureManager] previewLayer]];

[[captureManager captureSession] startRunning];

-(void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:YES];

    [[[self captureManager] previewLayer]removeFromSuperlayer];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [[captureManager captureSession] stopRunning];
    });

}

Memory allocation

cph2117
  • 2,651
  • 1
  • 28
  • 41
  • Sounds like a memory issue. Did you use Intrument leaks to check for potential issues? – Pedro Mancheno Oct 16 '13 at 15:28
  • I agree 100%. I think it's a memory issue as well. There were no leaks when I checked instruments. I've taken a screenshot of my allocations though and I'll post here. I feel like I might not be dismissing capture properly, so that by the time I open the capture session view controller the 5th or 6th time that all the instances are hogging some memory. – cph2117 Oct 16 '13 at 18:12
  • Hi, did you end up fixing your issue? Please post the solution. We are facing the same problem! Thanks – daivuk Nov 11 '13 at 15:46
  • Unfortunately I had to find a workaround that's not really satisfactory. (Someone on the Apple dev forum said they were having the same problem, but that it was only after xcode 5/ios7.) I ended up combining the content of two view controllers into one class. Like I said, not the purest solution, but it works. Depending on your application though that may not even be possible. – cph2117 Nov 11 '13 at 19:35

7 Answers7

12

I have encounter the same problem I have found this line is the main problem

[[[self view] layer] addSublayer:[[self captureManager] previewLayer]];

Just remove the previewlayer from the super layer while deallocating and there is no memory issue. My deallocating function is as follow

 -(void)deallocSession
{
[captureVideoPreviewLayer removeFromSuperlayer];
for(AVCaptureInput *input1 in session.inputs) {
    [session removeInput:input1];
}

for(AVCaptureOutput *output1 in session.outputs) {
    [session removeOutput:output1];
}
[session stopRunning];
session=nil;
outputSettings=nil;
device=nil;
input=nil;
captureVideoPreviewLayer=nil;
stillImageOutput=nil;
self.vImagePreview=nil;

}

i called this function before popping and pushing any other view. It solved my issue.

souvickcse
  • 7,742
  • 5
  • 37
  • 64
  • Hello, I am using storyboard and when I present another view over my camera view , making preview view nil, preview view remains nil when reappear camera view. – Sushil Sharma Apr 26 '16 at 12:26
5

Removing session inputs and outputs seems to solve this problem for me

[captureSession stopRunning];
for(AVCaptureInput *input in captureSession.inputs) {
    [captureSession removeInput:input];
}

for(AVCaptureOutput *output in captureSession.outputs) {
    [captureSession removeOutput:output];
}
TUNER88
  • 923
  • 1
  • 20
  • 36
3

Swift version TUNER88's answer

func stopRecording() {
    captureSession.stopRunning()
    for input in captureSession.inputs {
        captureSession.removeInput(input)
    }
    for output in captureSession.outputs {
        captureSession.removeOutput(output)
    }
}
iwasrobbed
  • 46,496
  • 21
  • 150
  • 195
drpawelo
  • 2,348
  • 23
  • 17
3

What worked for me was setting the previewLayer of type AVCaptureVideoPreviewLayer() as a weak variable, then in the stopCaptureSession() function I have:

func stopCaptureSession() {
    self.previewLayer?.removeFromSuperlayer()
    self.previewLayer = nil
    self.captureSession.stopRunning()
    for input in captureSession.inputs {
        self.captureSession.removeInput(input)
    }
    for output in captureSession.outputs {
        self.captureSession.removeOutput(output)
    }
}

It turned out all my problems were connected to the previewLayer

Nikita Alexander
  • 527
  • 6
  • 11
0

You don't appear to be removing the previewLayer in the avcaptureViewController, which would keep a reference to the capture session internally. Make sure you remove the previewLayer from that view hierarchy.

RyanR
  • 7,728
  • 1
  • 25
  • 39
  • Do you mean remove the previewLayer from the SuperLayer? Because I've added my viewDidDisappear method, which does do that. Or do you mean something else? – cph2117 Oct 16 '13 at 18:30
  • Yep, that's what I was looking for. Going through my project that uses AVCapture to see if there's anything else, brb. – RyanR Oct 16 '13 at 18:41
  • ok, doesn't look like you're nilling the reference to captureManager in your -viewDidDisappear for the view controller. Make sure any references the controller has to any capture objects are nilled. – RyanR Oct 16 '13 at 18:47
  • I added "captureManager=nil;" in the same thread as [[captureManager captureSession] stopRunning]; in viewDidDisappear, but the problem persists. – cph2117 Oct 16 '13 at 18:58
0

Swift 3

    let session = AVCaptureSession()
    if let outputMovie = outputMovie, outputMovie.isRecording {
        outputMovie.stopRecording()
    }

    self.session.stopRunning()
    if let inputs = self.session.inputs as? [AVCaptureDeviceInput] {
        for input in inputs {
            self.session.removeInput(input)
        }
    }

    if let outputs = self.session.outputs as? [AVCaptureOutput] {
        for output in outputs {
            self.session.removeOutput(output)
        }
    }
Giang
  • 3,553
  • 30
  • 28
-1

here is the swift version of TUNER88 answer

session.stopRunning()

    for(var i = 0 ; i < session.inputs.count ; i++){

        session.removeInput(session.inputs[i] as! AVCaptureInput)

    }

    for(var i = 0 ; i < session.outputs.count ; i++){

        session.removeOutput(session.outputs[i] as! AVCaptureOutput)

    }
Qadir Hussain
  • 8,721
  • 13
  • 89
  • 124