1

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.

LLooggaann
  • 425
  • 1
  • 4
  • 16
  • You need to retain the value before passing it in. Check out the documentation of `Unmanaged` I’m busy now but I can write up an answer tomorrow. – Alexander Sep 04 '21 at 02:15
  • I seem to still be getting bad access crashes when using Unmanaged and passUnRetainedValue.. any thoughts? – LLooggaann Sep 22 '21 at 15:43
  • You need to `passRetained`. Think about it: when you create an `Unmanaged` value, the system needs to know whether you intend for this new `Unmanaged` value to be like a strong reference (in that you want the presence of the `Unmanaged` value to be enough to keep your target instance alive, even if other references expire), or an unowned reference (where you expect another strong ref to keep your instance alive, and you don't want to take ownership yourself). If you `passUnretained`, your `cString` instance will expire as soon as it gets released by ARC in the function where it was declared. – Alexander Sep 22 '21 at 16:02
  • You want `cString` to be retained, so that you can pass it to `VTDecompressionSessionDecodeFrame`, which will hold onto it and pass it to your call back, long after end end of the function that allocated `cString`. After that, it becomes your responsibility to release the instance, when appropriate. If the callback only gets called once, then you can use `takeRetainedValue()` to get the value of the string in a local variable. Once that local variable expires, your `cString` will be deallocated. – Alexander Sep 22 '21 at 16:03
  • On the input I'm using: `let nsString = NSString(string: "Test")` and `var ptr = Unmanaged.passRetained(nsString).toOpaque()` passing into `VTDecompressionSessionDecodeFrame` as `&ptr`. On the other side `if let sourceFrameRefCon = sourceFrameRefCon { let obj = Unmanaged.fromOpaque(sourceFrameRefCon).takeRetainedValue() print(obj) }` but i still get bad access on `fromOpaque`. – LLooggaann Sep 28 '21 at 23:58
  • Got it working by calling `VTDecompressionSessionDecodeFrame` with `ptr` rather than `&ptr` – LLooggaann Sep 29 '21 at 00:06

1 Answers1

1

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)
}
LLooggaann
  • 425
  • 1
  • 4
  • 16