I just solved a somewhat non-obvious issue with using AVCaptureSession to capture live video. I had what I thought was a memory leak, but it turned out not to be...well, sort of.
The structure of the code was roughly:
* set up session with AVCaptureSession
* set up delegate captureOutput to grab & convert the image, do a little bit of fiddling with it, and exit
Pretty straightforward, but what was happening in instruments is that the CGDataProvider object was growing astronomically, and after about 3 minutes the app would crash.
After several other tests, I surmised that this is actually the queue filling up, so what I did as a solution looked roughly like this:
each frame:
// now push an async task to tell us when we're done
proctr++;
if ((proctr % 20) == 0){
deferImageProcessing = true;
dispatch_sync(queue, ^{
[self queueFlushed];
});
}
- (void)queueFlushed {
deferImageProcessing = false;
}
Effectively, each 20th processed frame, we suspend output, send a little message through the queue, and un-suspend output when it's received. If the queue is empty, this will have no effect,since it will take one frame. If it's not empty, though, it might take a few frames to clear out. Obviously you can adjust the modulus intelligently (probably something near the frame rate)
Then it's just a matter of skipping the updates inside the delegate:
- (void)captureOutput

AVCaptureOutput *)captureOutput didOutputSampleBuffer

CMSampleBufferRef)sampleBuf fer fromConnection

AVCaptureConnection *)connection
{
if (deferImageProcessing)
return;
// fiddle with image, update live image, whatever you're doing...
}
-Sean