iosswiftunsafe-pointersunsafemutablepointervideo-toolbox

EXC_BAD_ACCESS when trying to pass and read UnsafeMutableRawPointer through VTDecompressionSessionDecodeFrame


I think this is more a pointer question than a VideoToolbox session. I'm trying to do something similar to How to calculate FPS of Hardware Decode on iOS 8 exactly? and pass some metadata through VTDecompressionSessionDecodeFrame's sourceFrameRefCon so I can access it on the other side. In my case, I just want to pass a string.

Everything else with my decompression code works fine.

Here I pass a string through.

...

let string = "Test"
var cString = (string as NSString)

VTDecompressionSessionDecodeFrame(
     decompressionSession,
     sampleBuffer: sampleBuffer,
     flags: [
          ._EnableAsynchronousDecompression,
          ._EnableTemporalProcessing],
     frameRefcon: &cString,
     infoFlagsOut: &flagsOut)

And in my callback I attempt to print it:

callback = { (decompressionOutputRefCon: UnsafeMutableRawPointer?, sourceFrameRefCon: UnsafeMutableRawPointer?, status: OSStatus, infoFlags: VTDecodeInfoFlags, imageBuffer: CVBuffer?, presentationTimeStamp: CMTime, duration: CMTime) in
            
     if let sourceFrameRefCon = sourceFrameRefCon {
          let nsString = sourceFrameRefCon.load(as: NSString.self)
          let string = String(nsString)
          print(string)
     }
    ...

This actually works for a bit. I'll see Test printed in the console a dozen or so times, but then I'll get a EXC_BAD_ACCESS on the .load

I'm guessing there's a smarter way to pass these UnsafeMutableRawPointer's through.


Solution

  • Ended up getting this working by using the following:

    Input to VTDecompressionSessionDecodeFrame 's frameRefCon:

    let nsString = NSString(string: "Anything")
    let frameRefCon = Unmanaged.passRetained(nsString).toOpaque()
    

    Making sure to pass frameRefCon and not &frameRefCon

    On the output callback which has a param of sourceFrameRefCon: UnsafeMutableRawPointer?:

    if let sourceFrameRefCon = sourceFrameRefCon {
       let nsString = Unmanaged<NSString>.fromOpaque(sourceFrameRefCon).takeRetainedValue()
       print(nsString)
    }