From 0aa1ab2a36ae7ec96310743b66ef88513c208718 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Sat, 28 Mar 2020 23:50:06 -0400 Subject: [PATCH 1/3] Initial work for arbitrary callbacks This relies on specific structure of interface{} being composed of two gpointer's. The code expects something along the lines of: ``` /* void cb_proxy(void* v, void* v2); */ import "C" //export cb_proxy func cb_proxy(v unsafe.Pointer, v2 unsafe.Pointer) { println("in cb_proxy") el := (*C.GstElement)(v) cb := (*gst.Element)(v2) mycall(el, cb) } func mycall(webrtc *C.GstElement, user_data *gst.Element) { } ... func main{ ... source.SetCallback("on-negotiation-needed", C.cb_proxy) ... } ``` --- element.go | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++- gst.c | 22 +++++++++++++++ gst.h | 5 ++++ 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/element.go b/element.go index a5ea2f1..6ba2e18 100644 --- a/element.go +++ b/element.go @@ -3,6 +3,7 @@ package gst /* #cgo pkg-config: gstreamer-1.0 gstreamer-app-1.0 #include "gst.h" +typedef void (*closure)(); */ import "C" @@ -14,6 +15,8 @@ import ( "runtime" "sync" "unsafe" + + "github.com/mattn/go-pointer" ) var ( @@ -33,10 +36,18 @@ const ( StatePlaying StateOptions = C.GST_STATE_PLAYING ) +// typedef struct ElementUserData { +// guint64 callbackId; +// gpointer callbackFunc; +// } ElementUserData; + type Element struct { + callbackID uint64 + callbackFunc interface{} + // Do not change the order of the above two elements + // It matches ElementUserData in gst.h on purpose GstElement *C.GstElement onPadAdded PadAddedCallback - callbackID uint64 } func (e *Element) Name() (name string) { @@ -294,6 +305,76 @@ func (e *Element) SetPadAddedCallback(callback PadAddedCallback) { C.X_g_signal_connect(e.GstElement, detailedSignal, C.guint64(callbackID)) } +func (e *Element) SetCallback(signal string, callback interface{}) { + e.callbackFunc = callback + + var callbackID uint64 + mutex.Lock() + for { + callbackID = rand.Uint64() + if callbackStore[callbackID] != nil { + continue + } + callbackStore[callbackID] = e + break + } + mutex.Unlock() + + e.callbackID = callbackID + + detailedSignal := (*C.gchar)(C.CString(signal)) + defer C.free(unsafe.Pointer(detailedSignal)) + + runtime.SetFinalizer(e, func(e *Element) { + e.cleanCallback() + }) + flags := 0 // TODO:, use GCOnnectFlags enum + notify := 0 // TODO: confirm null correctly used + + user_data_e := &Element{ + callbackID: callbackID, + callbackFunc: e.callbackFunc, + GstElement: e.GstElement, + onPadAdded: e.onPadAdded, + } + _ = user_data_e + + //vp := reflect.New(reflect.TypeOf(&[0]byte{})) + //vp.Elem().Set(reflect.ValueOf(callback)) + vp := reflect.ValueOf(callback) + _ = vp + + println("1") + fmt.Printf("callback: %v\n", callback) + fmt.Printf("callback: %v\n", callback.(unsafe.Pointer)) + fmt.Printf("callback: %v\n", unsafe.Pointer(callback.(unsafe.Pointer))) + fmt.Printf("callback: %d\n", (*[0]byte)(unsafe.Pointer(callback.(unsafe.Pointer)))) + fmt.Printf("callback: %p\n", C.closure(callback.(unsafe.Pointer))) + C.X_g_signal_connect_data_bak( + (C.gpointer)(unsafe.Pointer(e.GstElement)), + detailedSignal, + + //(*[0]byte)(unsafe.Pointer(callback)), + //(*[0]byte)(unsafe.Pointer(callback.(unsafe.Pointer))), + C.closure(callback.(unsafe.Pointer)), + //(callback.(unsafe.Pointer)), + //(*[0]byte)(unsafe.Pointer(vp.Pointer())), + //callback.(*[0]byte), + //(*[0]byte)(vp.Elem()), + //(vp.Interface()).(*[0]byte), + //vp.Interface().(*[0]byte), + //(vp.Elem()).(*[0]byte), + //(*[0]byte)(unsafe.Pointer(vp.Addr().Pointer())), + + (C.gpointer)(unsafe.Pointer(user_data_e)), + (*[0]byte)(pointer.Save(notify)), + (C.GConnectFlags)(flags), + + C.guint64(callbackID), + ) + println("2") +} + func ElementFactoryMake(factoryName string, name string) (e *Element, err error) { var pName *C.gchar diff --git a/gst.c b/gst.c index 4e70dc1..ec048b1 100644 --- a/gst.c +++ b/gst.c @@ -81,11 +81,33 @@ void X_g_signal_connect(GstElement* element, gchar* detailed_signal, guint64 cal g_signal_connect(element, detailed_signal, G_CALLBACK(cb_new_pad), d); } +void cb_func(GstElement *element, gpointer data) { + ElementUserData *d = data; + printf("[ GST ] cb_func invoking callback with user_data: %p\n",d->callbackFunc); + //void myfunc(GstElement* element,gpointer v); + ((void (*)(GstElement* element,gpointer v))(d->callbackFunc))(element,data); +} + void X_g_signal_connect_data(gpointer instance, const gchar *detailed_signal, void (*f)(GstElement*, GstBus*, GstMessage*, gpointer), gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags) { printf("[ GST ] g_signal_connect_data called\n"); g_signal_connect_data(instance, detailed_signal, G_CALLBACK(f), data, destroy_data, connect_flags); } +void X_g_signal_connect_data_bak(gpointer instance, const gchar *detailed_signal, void (*f)(GstElement*, GstBus*, GstMessage*, gpointer), gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags, guint64 callbackId) { + printf("[ GST ] g_signal_connect_data_bak called\n"); + + ElementUserData *d = calloc(1, sizeof(ElementUserData)); + //d->callbackId = callbackId; + + ElementUserData *e = data; + printf("[ GST ] X_g_signal_connect_data_bak callbackFunc: %p\n",e->callbackFunc); + printf("[ GST ] X_g_signal_connect_data_bak callbackFunc: %p\n",&(e->callbackFunc)); + d->callbackFunc = e->callbackFunc; + d->GstElement = instance; + + g_signal_connect_data(instance, detailed_signal, G_CALLBACK(cb_func), d, destroy_data, connect_flags); +} + GstElement *X_gst_bin_get_by_name(GstElement* element, const gchar* name) { GstElement *e = gst_bin_get_by_name(GST_BIN(element), name); if (e != NULL) { diff --git a/gst.h b/gst.h index 074c05d..2e29ada 100644 --- a/gst.h +++ b/gst.h @@ -9,7 +9,12 @@ typedef struct ElementUserData { guint64 callbackId; + gpointer interfaceItable; + gpointer callbackFunc; + GstElement *GstElement; + gpointer anything; } ElementUserData; +extern void X_g_signal_connect_data_bak(gpointer instance, const gchar *detailed_signal, void (*f)(GstElement*, GstBus*, GstMessage*, gpointer), gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags, guint64 callbackId); From ba21af6e6ec282855c108e9c9ba807b4e2ef3317 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Sun, 29 Mar 2020 02:06:43 -0400 Subject: [PATCH 2/3] Init arbitrary interface rewrite --- element.go | 127 ++--------------------------------------------------- gst.c | 44 ++++++------------- gst.h | 7 +-- 3 files changed, 18 insertions(+), 160 deletions(-) diff --git a/element.go b/element.go index 6ba2e18..970f280 100644 --- a/element.go +++ b/element.go @@ -10,22 +10,11 @@ import "C" import ( "errors" "fmt" - "math/rand" "reflect" "runtime" - "sync" "unsafe" - - "github.com/mattn/go-pointer" -) - -var ( - mutex sync.Mutex - callbackStore = map[uint64]*Element{} ) -type PadAddedCallback func(element *Element, pad *Pad) - type StateOptions int const ( @@ -42,12 +31,10 @@ const ( // } ElementUserData; type Element struct { - callbackID uint64 + GstElement *C.GstElement callbackFunc interface{} // Do not change the order of the above two elements // It matches ElementUserData in gst.h on purpose - GstElement *C.GstElement - onPadAdded PadAddedCallback } func (e *Element) Name() (name string) { @@ -246,133 +233,27 @@ func (e *Element) SetObject(name string, value interface{}) { } } -func (e *Element) cleanCallback() { - - if e.onPadAdded == nil { - return - } - - mutex.Lock() - defer mutex.Unlock() - - delete(callbackStore, e.callbackID) -} - -//export go_callback_new_pad -func go_callback_new_pad(CgstElement *C.GstElement, CgstPad *C.GstPad, callbackID C.guint64) { - - mutex.Lock() - element := callbackStore[uint64(callbackID)] - mutex.Unlock() - - if element == nil { - return - } - - callback := element.onPadAdded - - pad := &Pad{ - pad: CgstPad, - } - - callback(element, pad) -} - -func (e *Element) SetPadAddedCallback(callback PadAddedCallback) { - e.onPadAdded = callback - - var callbackID uint64 - mutex.Lock() - for { - callbackID = rand.Uint64() - if callbackStore[callbackID] != nil { - continue - } - callbackStore[callbackID] = e - break - } - mutex.Unlock() - - e.callbackID = callbackID - - detailedSignal := (*C.gchar)(C.CString("pad-added")) - defer C.free(unsafe.Pointer(detailedSignal)) - - runtime.SetFinalizer(e, func(e *Element) { - e.cleanCallback() - }) - - C.X_g_signal_connect(e.GstElement, detailedSignal, C.guint64(callbackID)) -} - func (e *Element) SetCallback(signal string, callback interface{}) { e.callbackFunc = callback - var callbackID uint64 - mutex.Lock() - for { - callbackID = rand.Uint64() - if callbackStore[callbackID] != nil { - continue - } - callbackStore[callbackID] = e - break - } - mutex.Unlock() - - e.callbackID = callbackID - detailedSignal := (*C.gchar)(C.CString(signal)) defer C.free(unsafe.Pointer(detailedSignal)) - - runtime.SetFinalizer(e, func(e *Element) { - e.cleanCallback() - }) flags := 0 // TODO:, use GCOnnectFlags enum notify := 0 // TODO: confirm null correctly used user_data_e := &Element{ - callbackID: callbackID, callbackFunc: e.callbackFunc, GstElement: e.GstElement, - onPadAdded: e.onPadAdded, } - _ = user_data_e - - //vp := reflect.New(reflect.TypeOf(&[0]byte{})) - //vp.Elem().Set(reflect.ValueOf(callback)) - vp := reflect.ValueOf(callback) - _ = vp - - println("1") - fmt.Printf("callback: %v\n", callback) - fmt.Printf("callback: %v\n", callback.(unsafe.Pointer)) - fmt.Printf("callback: %v\n", unsafe.Pointer(callback.(unsafe.Pointer))) - fmt.Printf("callback: %d\n", (*[0]byte)(unsafe.Pointer(callback.(unsafe.Pointer)))) - fmt.Printf("callback: %p\n", C.closure(callback.(unsafe.Pointer))) - C.X_g_signal_connect_data_bak( + + C.X_g_signal_connect_data( (C.gpointer)(unsafe.Pointer(e.GstElement)), detailedSignal, - - //(*[0]byte)(unsafe.Pointer(callback)), - //(*[0]byte)(unsafe.Pointer(callback.(unsafe.Pointer))), C.closure(callback.(unsafe.Pointer)), - //(callback.(unsafe.Pointer)), - //(*[0]byte)(unsafe.Pointer(vp.Pointer())), - //callback.(*[0]byte), - //(*[0]byte)(vp.Elem()), - //(vp.Interface()).(*[0]byte), - //vp.Interface().(*[0]byte), - //(vp.Elem()).(*[0]byte), - //(*[0]byte)(unsafe.Pointer(vp.Addr().Pointer())), - (C.gpointer)(unsafe.Pointer(user_data_e)), - (*[0]byte)(pointer.Save(notify)), + C.closure(unsafe.Pointer(¬ify)), (C.GConnectFlags)(flags), - - C.guint64(callbackID), ) - println("2") } func ElementFactoryMake(factoryName string, name string) (e *Element, err error) { diff --git a/gst.c b/gst.c index ec048b1..4191205 100644 --- a/gst.c +++ b/gst.c @@ -65,47 +65,29 @@ void X_gst_g_object_setv(GObject *object, guint n_properties, const gchar *names //g_object_setv(object, n_properties, names, value); } - -void cb_new_pad(GstElement *element, GstPad *pad, gpointer data) { - ElementUserData *d = (ElementUserData *)data; - go_callback_new_pad(element, pad, d->callbackId); +void cb_func(GstElement *element, gpointer data, gpointer data2) { + ElementUserData *d; + if(data2){ + d= data2; + printf("[ GST ] cb_func invoking callback arity:3"); + ((void (*)(GstElement* element,gpointer v, gpointer v2))(d->callbackFunc))(element,data,data2); + }else { + d= data; + printf("[ GST ] cb_func invoking callback arity:2"); + ((void (*)(GstElement* element,gpointer v))(d->callbackFunc))(element,data); + } } - void X_g_signal_connect(GstElement* element, gchar* detailed_signal, guint64 callbackId) { printf("[ GST ] g_signal_connect called with signal %s\n", detailed_signal); - ElementUserData *d = calloc(1, sizeof(ElementUserData)); - d->callbackId = callbackId; - - g_signal_connect(element, detailed_signal, G_CALLBACK(cb_new_pad), d); + g_signal_connect(element, detailed_signal, G_CALLBACK(cb_func), d); } -void cb_func(GstElement *element, gpointer data) { - ElementUserData *d = data; - printf("[ GST ] cb_func invoking callback with user_data: %p\n",d->callbackFunc); - //void myfunc(GstElement* element,gpointer v); - ((void (*)(GstElement* element,gpointer v))(d->callbackFunc))(element,data); -} void X_g_signal_connect_data(gpointer instance, const gchar *detailed_signal, void (*f)(GstElement*, GstBus*, GstMessage*, gpointer), gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags) { printf("[ GST ] g_signal_connect_data called\n"); - g_signal_connect_data(instance, detailed_signal, G_CALLBACK(f), data, destroy_data, connect_flags); -} - -void X_g_signal_connect_data_bak(gpointer instance, const gchar *detailed_signal, void (*f)(GstElement*, GstBus*, GstMessage*, gpointer), gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags, guint64 callbackId) { - printf("[ GST ] g_signal_connect_data_bak called\n"); - - ElementUserData *d = calloc(1, sizeof(ElementUserData)); - //d->callbackId = callbackId; - - ElementUserData *e = data; - printf("[ GST ] X_g_signal_connect_data_bak callbackFunc: %p\n",e->callbackFunc); - printf("[ GST ] X_g_signal_connect_data_bak callbackFunc: %p\n",&(e->callbackFunc)); - d->callbackFunc = e->callbackFunc; - d->GstElement = instance; - - g_signal_connect_data(instance, detailed_signal, G_CALLBACK(cb_func), d, destroy_data, connect_flags); + g_signal_connect_data(instance, detailed_signal, G_CALLBACK(cb_func), data, destroy_data, connect_flags); } GstElement *X_gst_bin_get_by_name(GstElement* element, const gchar* name) { diff --git a/gst.h b/gst.h index 2e29ada..c13c241 100644 --- a/gst.h +++ b/gst.h @@ -8,18 +8,14 @@ typedef struct ElementUserData { - guint64 callbackId; + GstElement *GstElement; gpointer interfaceItable; gpointer callbackFunc; - GstElement *GstElement; - gpointer anything; } ElementUserData; -extern void X_g_signal_connect_data_bak(gpointer instance, const gchar *detailed_signal, void (*f)(GstElement*, GstBus*, GstMessage*, gpointer), gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags, guint64 callbackId); -extern void go_callback_new_pad(GstElement *element,GstPad *pad, guint64 callbackId); extern void X_gst_shim_init(); @@ -34,7 +30,6 @@ extern void X_gst_g_object_set(GstElement* e, const gchar* p_name, const GValue* extern void X_gst_g_object_set_structure(GstElement *e, const gchar* p_name, const GstStructure *p_value); extern void X_gst_g_object_setv(GObject* object, guint n_properties, const gchar* names[], const GValue value[]); extern void X_g_signal_connect(GstElement* element, gchar* detailed_signal, guint64 callbackId); -extern void cb_new_pad(GstElement* element, GstPad* pad, gpointer data); extern gboolean cb_pad_event(GstPad *pad, GstObject *parent, GstEvent *event); extern GstElement *X_gst_bin_get_by_name(GstElement* element, const gchar* name); extern GstElementClass *X_GST_ELEMENT_GET_CLASS(GstElement *element); From 67e43adbe837b6b72a149af5bf88b07680d226b0 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Sun, 29 Mar 2020 02:37:48 -0400 Subject: [PATCH 3/3] remove superfluous comments --- element.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/element.go b/element.go index 970f280..f9a20b8 100644 --- a/element.go +++ b/element.go @@ -25,11 +25,6 @@ const ( StatePlaying StateOptions = C.GST_STATE_PLAYING ) -// typedef struct ElementUserData { -// guint64 callbackId; -// gpointer callbackFunc; -// } ElementUserData; - type Element struct { GstElement *C.GstElement callbackFunc interface{} @@ -238,7 +233,7 @@ func (e *Element) SetCallback(signal string, callback interface{}) { detailedSignal := (*C.gchar)(C.CString(signal)) defer C.free(unsafe.Pointer(detailedSignal)) - flags := 0 // TODO:, use GCOnnectFlags enum + flags := 0 // TODO: use GConnectFlags enum notify := 0 // TODO: confirm null correctly used user_data_e := &Element{