Threading guarantees with AVCaptureVideoDataOutput

I'm writing some camera functionality that uses AVCaptureVideoDataOutput.

I've set it up so that it calls my AVCaptureVideoDataOutputSampleBufferDelegate on a background thread, by making my own dispatch_queue and configuring the AVCaptureVideoDataOutput.

My question is then, if I configure my AVCaptureSession differently, or even stop it altogether, is this guaranteed to flush all pending jobs on my background thread? For example, does [AVCaptureSession stopRunning] imply a blocking call until all pending frame-callbacks are done?

I have a more practical example below, showing how I am accessing something from the foreground thread from the background thread, but I wonder when/how it's safe to clean up that resource.

I have setup similar to the following:

// Foreground thread logic

dispatch_queue_t queue = dispatch_queue_create("qt_avf_camera_queue", nullptr);

AVCaptureSession *captureSession = [[AVCaptureSession alloc] init];

setupInputDevice(captureSession); // Connects the AVCaptureDevice...

// Store some arbitrary data to be attached to the frame, stored on the foreground thread
FrameMetaData frameMetaData = ...; 

MySampleBufferDelegate *sampleBufferDelegate = [MySampleBufferDelegate alloc];
// Capture frameMetaData by reference in lambda
[sampleBufferDelegate setFrameMetaDataGetter: [&frameMetaData]() { return &frameMetaData; }];

AVCaptureVideoDataOutput *captureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
[captureVideoDataOutput setSampleBufferDelegate:sampleBufferDelegate
                                          queue:queue];

[captureSession addOutput:captureVideoDataOutput];

[captureSession startRunning];
[captureSession stopRunning];

// Is it now safe to destroy frameMetaData, or do we need manual barrier?

And then in MySampleBufferDelegate:

- (void)captureOutput:(AVCaptureOutput *)captureOutput
        didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
               fromConnection:(AVCaptureConnection *)connection
{
    // Invokes the callback set above
    FrameMetaData *frameMetaData = frameMetaDataGetter();
    
    emitSampleBuffer(sampleBuffer, frameMetaData);
}
Answered by DTS Engineer in 857654022

Hello @qtnpskalerud,

stopRunning is documented as:

"Clients invoke -stopRunning to stop the flow of data from inputs to outputs connected to the AVCaptureSession instance. This call blocks until the session object has completely stopped."

So, if you call stopRunning (which is a synchronous call) on Thread A, you can still receive calls to your sample buffer delegate on Thread B as long as stopRunning has not yet returned on Thread A.

Once stopRunning has returned on Thread A, you should not receive calls to your sample buffer delegate on Thread B, because the flow from inputs to outputs has completely stopped.

--Greg

Hello @qtnpskalerud,

stopRunning is documented as:

"Clients invoke -stopRunning to stop the flow of data from inputs to outputs connected to the AVCaptureSession instance. This call blocks until the session object has completely stopped."

So, if you call stopRunning (which is a synchronous call) on Thread A, you can still receive calls to your sample buffer delegate on Thread B as long as stopRunning has not yet returned on Thread A.

Once stopRunning has returned on Thread A, you should not receive calls to your sample buffer delegate on Thread B, because the flow from inputs to outputs has completely stopped.

--Greg

Does this mean that it's also guaranteed that all pending jobs on thread B, that are related to the on-going AVCaptureSession, are finished when stopRunning returns?

Or as an alternative, is it possible that some jobs may still be pending on thread B, but there won't be any new jobs submitted?

Threading guarantees with AVCaptureVideoDataOutput
 
 
Q