mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-18 14:00:47 +08:00
340 lines
10 KiB
Go
340 lines
10 KiB
Go
package gst
|
|
|
|
// CGO exports have to be defined in a separate file from where they are used or else
|
|
// there will be double linkage issues.
|
|
|
|
/*
|
|
#include <gst/gst.h>
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"reflect"
|
|
"unsafe"
|
|
|
|
"github.com/gotk3/gotk3/glib"
|
|
gopointer "github.com/mattn/go-pointer"
|
|
)
|
|
|
|
//export goElementCallAsync
|
|
func goElementCallAsync(element *C.GstElement, userData C.gpointer) {
|
|
iface := gopointer.Restore(unsafe.Pointer(userData))
|
|
defer gopointer.Unref(unsafe.Pointer(userData))
|
|
f := iface.(func())
|
|
f()
|
|
}
|
|
|
|
//export goPadStickyEventForEachFunc
|
|
func goPadStickyEventForEachFunc(gpad *C.GstPad, event **C.GstEvent, userData C.gpointer) C.gboolean {
|
|
cbIface := gopointer.Restore(unsafe.Pointer(userData))
|
|
cbFunc := cbIface.(StickyEventsForEachFunc)
|
|
pad := wrapPad(toGObject(unsafe.Pointer(gpad)))
|
|
ev := wrapEvent(*event)
|
|
return gboolean(cbFunc(pad, ev))
|
|
}
|
|
|
|
//export goPadProbeFunc
|
|
func goPadProbeFunc(gstPad *C.GstPad, info *C.GstPadProbeInfo, userData C.gpointer) C.GstPadProbeReturn {
|
|
cbIface := gopointer.Restore(unsafe.Pointer(userData))
|
|
cbFunc := cbIface.(PadProbeCallback)
|
|
pad := wrapPad(toGObject(unsafe.Pointer(gstPad)))
|
|
return C.GstPadProbeReturn(cbFunc(pad, &PadProbeInfo{info}))
|
|
}
|
|
|
|
//export goPadForwardFunc
|
|
func goPadForwardFunc(gstPad *C.GstPad, userData C.gpointer) C.gboolean {
|
|
cbIface := gopointer.Restore(unsafe.Pointer(userData))
|
|
cbFunc := cbIface.(PadForwardFunc)
|
|
pad := wrapPad(toGObject(unsafe.Pointer(gstPad)))
|
|
return gboolean(cbFunc(pad))
|
|
}
|
|
|
|
//export goTagForEachFunc
|
|
func goTagForEachFunc(tagList *C.GstTagList, tag *C.gchar, userData C.gpointer) {
|
|
cbIface := gopointer.Restore(unsafe.Pointer(userData))
|
|
cbFunc := cbIface.(TagListForEachFunc)
|
|
cbFunc(wrapTagList(tagList), Tag(C.GoString(tag)))
|
|
}
|
|
|
|
//export goBufferListForEachCb
|
|
func goBufferListForEachCb(buf **C.GstBuffer, idx C.guint, userData C.gpointer) C.gboolean {
|
|
cbIface := gopointer.Restore(unsafe.Pointer(userData))
|
|
cbFunc := cbIface.(func(*Buffer, uint) bool)
|
|
return gboolean(cbFunc(wrapBuffer(*buf), uint(idx)))
|
|
}
|
|
|
|
//export goBufferMetaForEachCb
|
|
func goBufferMetaForEachCb(buf *C.GstBuffer, meta **C.GstMeta, userData C.gpointer) C.gboolean {
|
|
cbIface := gopointer.Restore(unsafe.Pointer(userData))
|
|
cbFunc := cbIface.(func(*Meta) bool)
|
|
return gboolean(cbFunc(wrapMeta(*meta)))
|
|
}
|
|
|
|
//export structForEachCb
|
|
func structForEachCb(fieldID C.GQuark, val *C.GValue, chPtr C.gpointer) C.gboolean {
|
|
ptr := gopointer.Restore(unsafe.Pointer(chPtr))
|
|
resCh := ptr.(chan interface{})
|
|
fieldName := C.GoString(C.g_quark_to_string(fieldID))
|
|
|
|
var resValue interface{}
|
|
|
|
gVal := glib.ValueFromNative(unsafe.Pointer(val))
|
|
if resValue, _ = gVal.GoValue(); resValue == nil {
|
|
// serialize the value if we can't do anything else with it
|
|
serialized := C.gst_value_serialize(val)
|
|
defer C.free(unsafe.Pointer(serialized))
|
|
resValue = C.GoString(serialized)
|
|
}
|
|
|
|
resCh <- fieldName
|
|
resCh <- resValue
|
|
return gboolean(true)
|
|
}
|
|
|
|
//export goBusSyncHandler
|
|
func goBusSyncHandler(bus *C.GstBus, cMsg *C.GstMessage, userData C.gpointer) C.GstBusSyncReply {
|
|
// wrap the message
|
|
msg := wrapMessage(cMsg)
|
|
|
|
// retrieve the ptr to the function
|
|
ptr := unsafe.Pointer(userData)
|
|
funcIface := gopointer.Restore(ptr)
|
|
busFunc, ok := funcIface.(BusSyncHandler)
|
|
|
|
if !ok {
|
|
gopointer.Unref(ptr)
|
|
return C.GstBusSyncReply(BusPass)
|
|
}
|
|
|
|
return C.GstBusSyncReply(busFunc(msg))
|
|
}
|
|
|
|
//export goBusFunc
|
|
func goBusFunc(bus *C.GstBus, cMsg *C.GstMessage, userData C.gpointer) C.gboolean {
|
|
// wrap the message
|
|
msg := wrapMessage(cMsg)
|
|
|
|
// retrieve the ptr to the function
|
|
ptr := unsafe.Pointer(userData)
|
|
funcIface := gopointer.Restore(ptr)
|
|
busFunc, ok := funcIface.(BusWatchFunc)
|
|
if !ok {
|
|
gopointer.Unref(ptr)
|
|
return gboolean(false)
|
|
}
|
|
|
|
// run the call back
|
|
if cont := busFunc(msg); !cont {
|
|
gopointer.Unref(ptr)
|
|
return gboolean(false)
|
|
}
|
|
|
|
return gboolean(true)
|
|
}
|
|
|
|
func getMetaInfoCbFuncs(meta *C.GstMeta) *MetaInfoCallbackFuncs {
|
|
gapi := glib.Type(meta.info.api)
|
|
gtype := glib.Type(meta.info._type)
|
|
typeCbs := registeredMetas[gapi]
|
|
if typeCbs == nil {
|
|
return nil
|
|
}
|
|
return typeCbs[gtype.Name()]
|
|
}
|
|
|
|
//export goMetaFreeFunc
|
|
func goMetaFreeFunc(meta *C.GstMeta, buf *C.GstBuffer) {
|
|
cbFuncs := getMetaInfoCbFuncs(meta)
|
|
if cbFuncs != nil && cbFuncs.FreeFunc != nil {
|
|
cbFuncs.FreeFunc(wrapBuffer(buf))
|
|
}
|
|
}
|
|
|
|
//export goMetaInitFunc
|
|
func goMetaInitFunc(meta *C.GstMeta, params C.gpointer, buf *C.GstBuffer) C.gboolean {
|
|
cbFuncs := getMetaInfoCbFuncs(meta)
|
|
if cbFuncs != nil && cbFuncs.InitFunc != nil {
|
|
paramsIface := gopointer.Restore(unsafe.Pointer(params))
|
|
defer gopointer.Unref(unsafe.Pointer(params))
|
|
return gboolean(cbFuncs.InitFunc(paramsIface, wrapBuffer(buf)))
|
|
}
|
|
return gboolean(true)
|
|
}
|
|
|
|
//export goMetaTransformFunc
|
|
func goMetaTransformFunc(transBuf *C.GstBuffer, meta *C.GstMeta, buffer *C.GstBuffer, mType C.GQuark, data C.gpointer) C.gboolean {
|
|
cbFuncs := getMetaInfoCbFuncs(meta)
|
|
if cbFuncs != nil && cbFuncs.TransformFunc != nil {
|
|
transformData := (*C.GstMetaTransformCopy)(unsafe.Pointer(data))
|
|
return gboolean(cbFuncs.TransformFunc(
|
|
wrapBuffer(transBuf),
|
|
wrapBuffer(buffer),
|
|
quarkToString(mType),
|
|
&MetaTransformCopy{
|
|
Region: gobool(transformData.region),
|
|
Offset: int64(transformData.offset),
|
|
Size: int64(transformData.size),
|
|
},
|
|
))
|
|
}
|
|
return gboolean(true)
|
|
}
|
|
|
|
//export goGDestroyNotifyFunc
|
|
func goGDestroyNotifyFunc(ptr C.gpointer) {
|
|
funcIface := gopointer.Restore(unsafe.Pointer(ptr))
|
|
defer gopointer.Unref(unsafe.Pointer(ptr))
|
|
f := funcIface.(func())
|
|
if f != nil {
|
|
f()
|
|
}
|
|
}
|
|
|
|
//export goGDestroyNotifyFuncNoRun
|
|
func goGDestroyNotifyFuncNoRun(ptr C.gpointer) {
|
|
gopointer.Unref(unsafe.Pointer(ptr))
|
|
}
|
|
|
|
//export goCapsMapFunc
|
|
func goCapsMapFunc(features *C.GstCapsFeatures, structure *C.GstStructure, userData C.gpointer) C.gboolean {
|
|
// retrieve the ptr to the function
|
|
ptr := unsafe.Pointer(userData)
|
|
funcIface := gopointer.Restore(ptr)
|
|
mapFunc, ok := funcIface.(CapsMapFunc)
|
|
|
|
if !ok {
|
|
gopointer.Unref(ptr)
|
|
return gboolean(false)
|
|
}
|
|
|
|
return gboolean(mapFunc(wrapCapsFeatures(features), wrapStructure(structure)))
|
|
}
|
|
|
|
//export goClockCb
|
|
func goClockCb(gclock *C.GstClock, clockTime C.GstClockTime, clockID C.GstClockID, userData C.gpointer) C.gboolean {
|
|
// retrieve the ptr to the function
|
|
ptr := unsafe.Pointer(userData)
|
|
funcIface := gopointer.Restore(ptr)
|
|
cb, ok := funcIface.(ClockCallback)
|
|
|
|
if !ok {
|
|
gopointer.Unref(ptr)
|
|
return gboolean(false)
|
|
}
|
|
|
|
clock := wrapClock(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gclock))})
|
|
return gboolean(cb(clock, ClockTime(clockTime)))
|
|
}
|
|
|
|
//export goPluginInit
|
|
func goPluginInit(plugin *C.GstPlugin, userData C.gpointer) C.gboolean {
|
|
ptr := unsafe.Pointer(userData)
|
|
defer gopointer.Unref(ptr)
|
|
funcIface := gopointer.Restore(ptr)
|
|
cb, ok := funcIface.(PluginInitFunc)
|
|
if !ok {
|
|
return gboolean(false)
|
|
}
|
|
return gboolean(cb(wrapPlugin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(plugin))})))
|
|
}
|
|
|
|
//export goGlobalPluginInit
|
|
func goGlobalPluginInit(plugin *C.GstPlugin) C.gboolean {
|
|
return gboolean(globalPluginInit(wrapPlugin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(plugin))})))
|
|
}
|
|
|
|
//export goClassInit
|
|
func goClassInit(klass C.gpointer, klassData C.gpointer) {
|
|
registerMutex.Lock()
|
|
defer registerMutex.Unlock()
|
|
|
|
ptr := unsafe.Pointer(klassData)
|
|
iface := gopointer.Restore(ptr)
|
|
defer gopointer.Unref(ptr)
|
|
|
|
data := iface.(*classData)
|
|
registeredClasses[klass] = data.elem
|
|
|
|
data.ext.InitClass(unsafe.Pointer(klass), data.elem)
|
|
|
|
C.g_type_class_add_private(klass, C.gsize(unsafe.Sizeof(uintptr(0))))
|
|
data.elem.ClassInit(wrapElementClass(klass))
|
|
}
|
|
|
|
//export goInstanceInit
|
|
func goInstanceInit(obj *C.GTypeInstance, klass C.gpointer) {
|
|
registerMutex.Lock()
|
|
defer registerMutex.Unlock()
|
|
|
|
elem := registeredClasses[klass].New()
|
|
registeredClasses[klass] = elem
|
|
|
|
ptr := gopointer.Save(elem)
|
|
private := C.g_type_instance_get_private(obj, registeredTypes[reflect.TypeOf(registeredClasses[klass]).String()])
|
|
C.memcpy(unsafe.Pointer(private), unsafe.Pointer(&ptr), C.gulong(unsafe.Sizeof(uintptr(0))))
|
|
}
|
|
|
|
//export goURIHdlrGetURIType
|
|
func goURIHdlrGetURIType(gtype C.GType) C.GstURIType {
|
|
return C.GstURIType(globalURIHdlr.GetURIType())
|
|
}
|
|
|
|
//export goURIHdlrGetProtocols
|
|
func goURIHdlrGetProtocols(gtype C.GType) **C.gchar {
|
|
protocols := globalURIHdlr.GetProtocols()
|
|
size := C.size_t(unsafe.Sizeof((*C.gchar)(nil)))
|
|
length := C.size_t(len(protocols))
|
|
arr := (**C.gchar)(C.malloc(length * size))
|
|
view := (*[1 << 30]*C.gchar)(unsafe.Pointer(arr))[0:len(protocols):len(protocols)]
|
|
for i, proto := range protocols {
|
|
view[i] = (*C.gchar)(C.CString(proto))
|
|
}
|
|
return arr
|
|
}
|
|
|
|
//export goURIHdlrGetURI
|
|
func goURIHdlrGetURI(hdlr *C.GstURIHandler) *C.gchar {
|
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(hdlr))
|
|
return (*C.gchar)(unsafe.Pointer(C.CString(iface.(URIHandler).GetURI())))
|
|
}
|
|
|
|
//export goURIHdlrSetURI
|
|
func goURIHdlrSetURI(hdlr *C.GstURIHandler, uri *C.gchar, gerr **C.GError) C.gboolean {
|
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(hdlr))
|
|
ok, err := iface.(URIHandler).SetURI(C.GoString(uri))
|
|
if err != nil {
|
|
C.g_set_error_literal(gerr, newQuarkFromString(string(DomainLibrary)), C.gint(LibraryErrorSettings), C.CString(err.Error()))
|
|
}
|
|
return gboolean(ok)
|
|
}
|
|
|
|
//export goObjectSetProperty
|
|
func goObjectSetProperty(obj *C.GObject, propID C.guint, val *C.GValue, param *C.GParamSpec) {
|
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(obj))
|
|
iface.SetProperty(wrapObject(toGObject(unsafe.Pointer(obj))), uint(propID-1), glib.ValueFromNative(unsafe.Pointer(val)))
|
|
}
|
|
|
|
//export goObjectGetProperty
|
|
func goObjectGetProperty(obj *C.GObject, propID C.guint, value *C.GValue, param *C.GParamSpec) {
|
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(obj))
|
|
val := iface.GetProperty(wrapObject(toGObject(unsafe.Pointer(obj))), uint(propID-1))
|
|
if val == nil {
|
|
return
|
|
}
|
|
C.g_value_copy((*C.GValue)(unsafe.Pointer(val.GValue)), value)
|
|
}
|
|
|
|
//export goObjectConstructed
|
|
func goObjectConstructed(obj *C.GObject) {
|
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(obj))
|
|
iface.Constructed(wrapObject(toGObject(unsafe.Pointer(obj))))
|
|
}
|
|
|
|
//export goObjectFinalize
|
|
func goObjectFinalize(obj *C.GObject, klass C.gpointer) {
|
|
registerMutex.Lock()
|
|
defer registerMutex.Unlock()
|
|
delete(registeredClasses, klass)
|
|
gopointer.Unref(privateFromObj(unsafe.Pointer(obj)))
|
|
}
|