Search code examples
iosswiftavfoundationvideo-toolbox

Referencing `self` from within a VTCompressionOutputCallback


I'm currently trying to use VideoToolbox to encode video data from an AVCaptureVideoDataOutput, but I'm having an issue referencing self from within the VTCompressionOutputCallback.

My code is as follows:

...

var sessionRef: VTCompressionSession?

let outputCallback: VTCompressionOutputCallback = { _, _, status, _, sampleBuffer in
    guard status == noErr, let sampleBuffer = sampleBuffer else {
        return
    }

    debugPrint("[INFO]: outputCallback: sampleBuffer: \(sampleBuffer)")
}

let sessionErr = VTCompressionSessionCreate(allocator: nil,
                                            width: width,
                                            height: height,
                                            codecType: kCMVideoCodecType_H264,
                                            encoderSpecification: nil,
                                            imageBufferAttributes: nil,
                                            compressedDataAllocator: nil,
                                            outputCallback: outputCallback,
                                            refcon: nil,
                                            compressionSessionOut: UnsafeMutablePointer(&sessionRef))

...

That works fine, and the print outputs as expected, but as soon as I try and add a reference to self within the VTCompressionOutputCallback, it get a compiler error stating

A C function pointer cannot be formed from a closure that captures context

How can I use self from within the callback?

Thanks in advance for the help.


Solution

  • I figured out a solution.

    The VTCompressionSessionCreate call has a parameter for outputCallbackRefCon which gets passed along to the VTCompressionOutputCallback.

    By wrapping self in an UnsafeMutableRawPointer like so

    let unmanagedSelf = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
    

    I was able to pass that value into the VTCompressionSessionCreate under the refcon parameter. Inside of the callback I was then able to do pull that value back out using

    let scopedSelf = Unmanaged<ViewController>.fromOpaque(unmanagedSelf).takeUnretainedValue()