swiftunsafe-pointerscvpixelbufferunsafemutablepointer

Is there a way to utilize Swift commands within a low-level C method call?


I am maintaining a set of data obtained from a AVCaptureSynchronizedData. One of the methods I use modifies the CVPixelBuffers obtained from the AVCaptureSynchronizedData. While modifying. the CVPixelBuffer, I create a copy of the CVPixelBuffer via

let status = CVPixelBufferCreateWithBytes(nil, scaleWidth, scaleHeight,
                                                  pixelFormat, destData,
                                                  destBytesPerRow, releaseCallback,
                                                  nil, nil, &dstPixelBuffer)

The releaseCallBack is referenced as

let releaseCallback: CVPixelBufferReleaseBytesCallback = { _, ptr in
    if let ptr = ptr {
        free(UnsafeMutableRawPointer(mutating: ptr))
    }
}

However, I would like to be able to keep up with how many times this is called. But, if I add something like

var num:Int = 0
let releaseCallback: CVPixelBufferReleaseBytesCallback = { _, ptr in
    if let ptr = ptr {
        num += 1
        free(UnsafeMutableRawPointer(mutating: ptr))
    }
}

I get the error

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

Not sure if it is possible, but it would be incredibly useful to be able to keep count of the number of times a pointer is destroyed


Solution

  • Referencing the instance variable num in the closure captures self and that is not possible in the callback which is a pure C function.

    Similarly as in How to use instance method as callback for function which takes only func or literal closure you have to use that a custom pointer (here: releaseRefCon) can be passed to the callback:

    let releaseCallback: CVPixelBufferReleaseBytesCallback = { releaseRefCon, ptr in
        let mySelf = Unmanaged<YourClass>.fromOpaque(releaseRefCon!).takeUnretainedValue()
        if let ptr = ptr {
            free(UnsafeMutableRawPointer(mutating: ptr))
            mySelf.num += 1
        }
    }
    
    let releaseRefCon = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
    let status = CVPixelBufferCreateWithBytes(nil, scaleWidth, scaleHeight,
                                              pixelFormat, destData,
                                              destBytesPerRow,
                                              releaseCallback, releaseRefCon,
                                              nil, &dstPixelBuffer)
    

    For the conversions from an instance pointer (here: self) to a void pointer and back to an instance pointer (here: mySelf) see How to cast self to UnsafeMutablePointer<Void> type in swift.