on MacOS 10.14.6, Swift and XCode 11.0, VLCKit 3.3.0, I try to create callbacks with @objc functions, within a class. But using #selector to point to my @objc func, the compiler generates an error
these are the 2 functions I declare within my class
class VLCStreamProcessor {
// ...
@objc func lock_frame(
opaque: UnsafeMutableRawPointer? ,
planes: UnsafeMutablePointer<UnsafeMutableRawPointer?>?)
-> UnsafeMutableRawPointer?
{ // ...
return UnsafeMutableRawPointer(user_data.pic)
}
@objc func unlock_frame(
opaque: UnsafeMutableRawPointer?,
picture: UnsafeMutableRawPointer?,
planes: UnsafePointer<UnsafeMutableRawPointer?>?)
{ // ...
}
then in an other function (myVLCProcessing), still within same class, I prepare my call backs
func myVLCProcessing()
{ // ...
libvlc_video_set_callbacks(
mplayerPtr, // type libvlc_media_player_t*
#selector( lock_frame(opaque:planes:) ), // type libvlc_video_lock_cb <- 1st error
#selector( unlock_frame(opaque:picture:planes: )), // type libvlc_video_unlock_cb <- 2nd error
0, // type libvlc_video_display_cb
opaque // type void*
)
// ...
}
there I get a compiler error, on the 2 lines with #selector : first :
Cannot convert value of type 'Selector' to expected argument type 'libvlc_video_lock_cb?' (aka 'Optional<@convention(c)(Optional<UnsafeMutableRawPointer>, Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>>) -> Optional<UnsafeMutableRawPointer>>')
second:
Cannot convert value of type 'Selector' to specified type 'libvlc_video_unlock_cb' (aka '@convention(c) (Optional<UnsafeMutableRawPointer>, Optional<UnsafeMutableRawPointer>, Optional<UnsafePointer<Optional<UnsafeMutableRawPointer>>>) -> ()')
from the libvlc (libvlc_media_player.h), the 2 C-functions are expected as :
typedef void *(*libvlc_video_lock_cb)(void *opaque, void **planes);
typedef void (*libvlc_video_unlock_cb)(void *opaque, void *picture,
void *const *planes);
any advice welcome.
Only global functions or closures (which capture no context) can be passed to the C function for the callback arguments. Similarly as in How to use instance method as callback for function which takes only func or literal closure you can “tunnel” self
(the pointer to the instance) to the callback functions by converting it to a void
pointer and back. The callback function can then call the instance method:
class VLCStreamProcessor {
func lock_frame(
planes: UnsafeMutablePointer<UnsafeMutableRawPointer?>?)
-> UnsafeMutableRawPointer?
{ // ...
}
func unlock_frame(
picture: UnsafeMutableRawPointer?,
planes: UnsafePointer<UnsafeMutableRawPointer?>?)
{ // ...
}
func myVLCProcessing() {
// ...
let opaque = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
libvlc_video_set_callbacks(mplayerPtr, { (opaque, planes) -> UnsafeMutableRawPointer? in
let mySelf = Unmanaged<VLCStreamProcessor>.fromOpaque(opaque!).takeUnretainedValue()
return mySelf.lock_frame(planes: planes)
}, { (opaque, picture, planes) in
let mySelf = Unmanaged<VLCStreamProcessor>.fromOpaque(opaque!).takeUnretainedValue()
mySelf.unlock_frame(picture: picture, planes: planes)
}, nil, opaque)
}
}
Here it is assumed that the VLCStreamProcessor
exists as long as the libvlc callbacks are set, otherwise the pointers have to be retained.