windows build issues - more plugin stuff

This commit is contained in:
Avi Zimmerman
2021-01-11 05:54:30 +02:00
parent 636cbf2ece
commit a9093dedf4
16 changed files with 395 additions and 69 deletions

View File

@@ -119,6 +119,12 @@ var pluginTmpl = template.Must(template.New("").Funcs(template.FuncMap{
"adjustedName": func(name string) string {
return strings.ToLower(strings.Replace(name, "-", "_", -1))
},
"extendsFromBase": func(subclass string) bool {
if strings.HasPrefix(subclass, "base.") {
return true
}
return false
},
}).Parse(`// !WARNING! THIS FILE WAS GENERATED BY GST-PLUGIN-GEN !WARNING! //
package main
@@ -128,7 +134,9 @@ import (
"unsafe"
"github.com/tinyzimmer/go-gst/gst"
{{- if (.Config.Element.Subclass | extendsFromBase) }}
"github.com/tinyzimmer/go-gst/gst/base"
{{- end }}
)
// The metadata for this plugin

View File

@@ -6,8 +6,8 @@ all: $(PLUGINS)
$(PLUGINS):
cd $@ && \
go generate && \
go build -o ../libgstgo$@.so -buildmode c-shared .
rm libgstgo$@.h
go build -o ../libgst$@.so -buildmode c-shared .
rm libgst$@.h
clean:
rm -f *.so *.h

View File

@@ -59,8 +59,8 @@ var CAT = gst.NewDebugCategory(
// This element only has a single property, the location of the file to write to.
// When getting and setting properties later on, you will reference them by their index in
// this list.
var properties = []*gst.ParameterSpec{
gst.NewStringParameter(
var properties = []*gst.ParamSpec{
gst.NewStringParam(
"location", // The name of the parameter
"File Location", // The long name for the parameter
"Location to write the file to", // A blurb about the parameter

View File

@@ -59,8 +59,8 @@ var CAT = gst.NewDebugCategory(
// This element only has a single property, the location of the file to read from.
// When getting and setting properties later on, you will reference them by their index in
// this list.
var properties = []*gst.ParameterSpec{
gst.NewStringParameter(
var properties = []*gst.ParamSpec{
gst.NewStringParam(
"location", // The name of the parameter
"File Location", // The long name for the parameter
"Location of the file to read from", // A blurb about the parameter

View File

@@ -0,0 +1,191 @@
// This is a GStreamer element implemented in Go that uses inbound data on a websocket
// connection as the source for the stream.
//
// In order to build the plugin for use by GStreamer, you can do the following:
//
// $ go generate
// $ go build -o libgstgofilesrc.so -buildmode c-shared .
//
//
//go:generate gst-plugin-gen
//
// +plugin:Name=websocketsrc
// +plugin:Description=GStreamer Websocket Source
// +plugin:Version=v0.0.1
// +plugin:License=gst.LicenseLGPL
// +plugin:Source=go-gst
// +plugin:Package=examples
// +plugin:Origin=https://github.com/tinyzimmer/go-gst
// +plugin:ReleaseDate=2021-01-10
//
// +element:Name=websocketsrc
// +element:Rank=gst.RankNone
// +element:Impl=websocketSrc
// +element:Subclass=gst.ExtendsElement
package main
import (
"fmt"
"net/http"
"github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst"
)
// Defaults //
var (
DefaultAddress string = "0.0.0.0"
DefaultPort int = 5000
DefaultRetrieveRemoteAddr bool = true
)
func main() {}
// CAT is the log category for the websocketsrc.
var CAT = gst.NewDebugCategory(
"websocketsrc",
gst.DebugColorNone,
"WebsocketSrc Element",
)
var properties = []*gst.ParamSpec{
gst.NewStringParam(
"address",
"Server Address",
"The address to bind the server to",
&DefaultAddress,
gst.ParameterReadWrite,
),
gst.NewIntParam(
"port",
"Server Port",
"The port to bind the server to",
1024, 65535,
DefaultPort,
gst.ParameterReadWrite,
),
gst.NewBoolParam(
"retrieve-remote-addr",
"Retrieve Remote Address",
"Include the remote client's address in the buffer metadata",
DefaultRetrieveRemoteAddr,
gst.ParameterReadWrite,
),
}
// Internals //
type state struct {
started bool
server *http.Server
needInitialEvents bool
needSegment bool
}
type settings struct {
address string
port int
retrieveRemoteAddr bool
}
func defaultSettings() *settings {
return &settings{
address: DefaultAddress,
port: DefaultPort,
retrieveRemoteAddr: DefaultRetrieveRemoteAddr,
}
}
// Element implementation //
type websocketSrc struct {
settings *settings
state *state
srcpad *gst.Pad
}
// // ObjectSubclass // //
func (w *websocketSrc) New() gst.GoElement {
return &websocketSrc{
settings: defaultSettings(),
state: &state{},
}
}
func (w *websocketSrc) TypeInit(instance *gst.TypeInstance) {}
func (w *websocketSrc) ClassInit(klass *gst.ElementClass) {
klass.SetMetadata(
"Websocket Src",
"Src/Websocket",
"Write stream from a connection over a websocket server",
"Avi Zimmerman <avi.zimmerman@gmail.com>",
)
klass.AddPadTemplate(gst.NewPadTemplate(
"src",
gst.PadDirectionSource,
gst.PadPresenceAlways,
gst.NewAnyCaps(),
))
klass.InstallProperties(properties)
}
// // Object // //
func (w *websocketSrc) SetProperty(self *gst.Object, id uint, value *glib.Value) {}
func (w *websocketSrc) GetProperty(self *gst.Object, id uint) *glib.Value { return nil }
func (w *websocketSrc) Constructed(self *gst.Object) {
w.srcpad = gst.ToElement(self).GetStaticPad("src")
w.srcpad.SetEventFunction(func(pad *gst.Pad, parent *gst.Object, event *gst.Event) bool {
var ret bool
self.Log(CAT, gst.LevelLog, fmt.Sprintf("Handling event: %s", event.Type()))
switch event.Type() {
case gst.EventTypeFlushStart:
// TODO
case gst.EventTypeFlushStop:
// TODO
case gst.EventTypeReconfigure:
ret = true
case gst.EventTypeLatency:
ret = true
default:
ret = false
}
if ret {
self.Log(CAT, gst.LevelLog, fmt.Sprintf("Handled event: %s", event.Type()))
} else {
self.Log(CAT, gst.LevelLog, fmt.Sprintf("Didn't handle event: %s", event.Type()))
}
return ret
})
w.srcpad.SetQueryFunction(func(pad *gst.Pad, parent *gst.Object, query *gst.Query) bool {
var ret bool
self.Log(CAT, gst.LevelLog, fmt.Sprintf("Handling query: %s", query.Type()))
switch query.Type() {
case gst.QueryLatency:
query.SetLatency(true, 0, gst.ClockTimeNone)
ret = true
case gst.QueryScheduling:
query.SetScheduling(gst.SchedulingFlagSequential, 1, -1, 0)
query.AddSchedulingMode(gst.PadModePush)
ret = true
case gst.QueryCaps:
query.SetCapsResult(query.ParseCaps())
ret = true
default:
ret = false
}
return ret
})
}

2
go.mod
View File

@@ -4,5 +4,5 @@ go 1.15
require (
github.com/mattn/go-pointer v0.0.1
github.com/tinyzimmer/go-glib v0.0.2
github.com/tinyzimmer/go-glib v0.0.3
)

4
go.sum
View File

@@ -1,4 +1,4 @@
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
github.com/tinyzimmer/go-glib v0.0.2 h1:hdvjwrhcS6WrMMeqfxsf3e7/lOhV8gbVyJ9/sN3LfyY=
github.com/tinyzimmer/go-glib v0.0.2/go.mod h1:D5rd0CvYn1p7TBhwlwnBXHSr4d8lwEY9JImPQ66S+Bs=
github.com/tinyzimmer/go-glib v0.0.3 h1:yPax+QpAcmm16Ye3RZOsBVR0UpMZ9JnglJCgrlBN+C8=
github.com/tinyzimmer/go-glib v0.0.3/go.mod h1:D5rd0CvYn1p7TBhwlwnBXHSr4d8lwEY9JImPQ66S+Bs=

View File

@@ -4,6 +4,7 @@ package gst
// there will be double linkage issues.
/*
#include <stdlib.h>
#include <gst/gst.h>
*/
import "C"
@@ -273,7 +274,7 @@ func goInstanceInit(obj *C.GTypeInstance, klass C.gpointer) {
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))))
C.memcpy(unsafe.Pointer(private), unsafe.Pointer(&ptr), C.gsize(unsafe.Sizeof(uintptr(0))))
}
//export goURIHdlrGetURIType

View File

@@ -848,6 +848,8 @@ const (
QueryBitrate QueryType = C.GST_QUERY_BITRATE // (51202) the bitrate query (since 1.16)
)
func (q QueryType) String() string { return C.GoString(C.gst_query_type_get_name(C.GstQueryType(q))) }
// QueryTypeFlags casts GstQueryTypeFlags
type QueryTypeFlags int

View File

@@ -39,7 +39,7 @@ func (o *ObjectClass) Instance() *C.GObjectClass { return o.ptr }
// InstallProperties will install the given ParameterSpecs to the object class.
// They will be IDed in the order they are provided.
func (o *ObjectClass) InstallProperties(params []*ParameterSpec) {
func (o *ObjectClass) InstallProperties(params []*ParamSpec) {
for idx, prop := range params {
C.g_object_class_install_property(
o.Instance(),

View File

@@ -10,112 +10,96 @@ import (
"github.com/tinyzimmer/go-glib/glib"
)
// ParameterSpec is a go representation of a C GParamSpec
type ParameterSpec struct{ paramSpec *C.GParamSpec }
// NewStringParameter returns a new ParameterSpec that will hold a string value.
func NewStringParameter(name, nick, blurb string, defaultValue *string, flags ParameterFlags) *ParameterSpec {
var cdefault *C.gchar
if defaultValue != nil {
cdefault = C.CString(*defaultValue)
}
paramSpec := C.g_param_spec_string(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
(*C.gchar)(cdefault),
C.GParamFlags(flags),
)
return &ParameterSpec{paramSpec: paramSpec}
}
// ParamSpec is a go representation of a C GParamSpec
type ParamSpec struct{ paramSpec *C.GParamSpec }
// Name returns the name of this parameter.
func (p *ParameterSpec) Name() string {
func (p *ParamSpec) Name() string {
return C.GoString(C.g_param_spec_get_name(p.paramSpec))
}
// Blurb returns the blurb for this parameter.
func (p *ParameterSpec) Blurb() string {
func (p *ParamSpec) Blurb() string {
return C.GoString(C.g_param_spec_get_blurb(p.paramSpec))
}
// Flags returns the flags for this parameter.
func (p *ParameterSpec) Flags() ParameterFlags {
func (p *ParamSpec) Flags() ParameterFlags {
return ParameterFlags(p.paramSpec.flags)
}
// ValueType returns the GType for the value inside this parameter.
func (p *ParameterSpec) ValueType() glib.Type {
func (p *ParamSpec) ValueType() glib.Type {
return glib.Type(p.paramSpec.value_type)
}
// OwnerType returns the Gtype for the owner of this parameter.
func (p *ParameterSpec) OwnerType() glib.Type {
func (p *ParamSpec) OwnerType() glib.Type {
return glib.Type(p.paramSpec.owner_type)
}
// Unref the underlying paramater spec.
func (p *ParameterSpec) Unref() { C.g_param_spec_unref(p.paramSpec) }
func (p *ParamSpec) Unref() { C.g_param_spec_unref(p.paramSpec) }
// UIntRange returns the range of the Uint stored in this parameter spec.
func (p *ParameterSpec) UIntRange() (uint, uint) {
func (p *ParamSpec) UIntRange() (uint, uint) {
paramUint := C.getParamUInt(p.paramSpec)
return uint(paramUint.minimum), uint(paramUint.maximum)
}
// IntRange returns the range of the Int stored in this parameter spec.
func (p *ParameterSpec) IntRange() (int, int) {
func (p *ParamSpec) IntRange() (int, int) {
paramUint := C.getParamInt(p.paramSpec)
return int(paramUint.minimum), int(paramUint.maximum)
}
// UInt64Range returns the range of the Uint64 stored in this parameter spec.
func (p *ParameterSpec) UInt64Range() (uint64, uint64) {
func (p *ParamSpec) UInt64Range() (uint64, uint64) {
paramUint := C.getParamUInt64(p.paramSpec)
return uint64(paramUint.minimum), uint64(paramUint.maximum)
}
// Int64Range returns the range of the Int64 stored in this parameter spec.
func (p *ParameterSpec) Int64Range() (int64, int64) {
func (p *ParamSpec) Int64Range() (int64, int64) {
paramUint := C.getParamInt64(p.paramSpec)
return int64(paramUint.minimum), int64(paramUint.maximum)
}
// FloatRange returns the range of the Float stored in this parameter spec.
func (p *ParameterSpec) FloatRange() (float64, float64) {
func (p *ParamSpec) FloatRange() (float64, float64) {
paramUint := C.getParamFloat(p.paramSpec)
return float64(paramUint.minimum), float64(paramUint.maximum)
}
// DoubleRange returns the range of the Double stored in this parameter spec.
func (p *ParameterSpec) DoubleRange() (float64, float64) {
func (p *ParamSpec) DoubleRange() (float64, float64) {
paramUint := C.getParamDouble(p.paramSpec)
return float64(paramUint.minimum), float64(paramUint.maximum)
}
// IsCaps returns true if this parameter contains a caps object.
func (p *ParameterSpec) IsCaps() bool { return gobool(C.isParamSpecTypeCaps(p.paramSpec)) }
func (p *ParamSpec) IsCaps() bool { return gobool(C.isParamSpecTypeCaps(p.paramSpec)) }
// IsEnum returns true if this parameter contains an enum.
func (p *ParameterSpec) IsEnum() bool { return gobool(C.isParamSpecEnum(p.paramSpec)) }
func (p *ParamSpec) IsEnum() bool { return gobool(C.isParamSpecEnum(p.paramSpec)) }
// IsFlags returns true if this paramater contains flags.
func (p *ParameterSpec) IsFlags() bool { return gobool(C.isParamSpecFlags(p.paramSpec)) }
func (p *ParamSpec) IsFlags() bool { return gobool(C.isParamSpecFlags(p.paramSpec)) }
// IsObject returns true if this parameter contains an object.
func (p *ParameterSpec) IsObject() bool { return gobool(C.isParamSpecObject(p.paramSpec)) }
func (p *ParamSpec) IsObject() bool { return gobool(C.isParamSpecObject(p.paramSpec)) }
// IsBoxed returns true if this parameter contains a boxed object.
func (p *ParameterSpec) IsBoxed() bool { return gobool(C.isParamSpecBoxed(p.paramSpec)) }
func (p *ParamSpec) IsBoxed() bool { return gobool(C.isParamSpecBoxed(p.paramSpec)) }
// IsPointer returns true if this paramater contains a pointer.
func (p *ParameterSpec) IsPointer() bool { return gobool(C.isParamSpecPointer(p.paramSpec)) }
func (p *ParamSpec) IsPointer() bool { return gobool(C.isParamSpecPointer(p.paramSpec)) }
// IsFraction returns true if this parameter contains a fraction.
func (p *ParameterSpec) IsFraction() bool { return gobool(C.isParamSpecFraction(p.paramSpec)) }
func (p *ParamSpec) IsFraction() bool { return gobool(C.isParamSpecFraction(p.paramSpec)) }
// IsGstArray returns true if this parameter contains a Gst array.
func (p *ParameterSpec) IsGstArray() bool { return gobool(C.isParamSpecGstArray(p.paramSpec)) }
func (p *ParamSpec) IsGstArray() bool { return gobool(C.isParamSpecGstArray(p.paramSpec)) }
// EnumValue is a go representation of a GEnumValue
type EnumValue struct {
@@ -124,7 +108,7 @@ type EnumValue struct {
}
// GetEnumValues returns the possible enum values for this parameter.
func (p *ParameterSpec) GetEnumValues() []*EnumValue {
func (p *ParamSpec) GetEnumValues() []*EnumValue {
var gsize C.guint
gEnumValues := C.getEnumValues(p.paramSpec, &gsize)
size := int(gsize)
@@ -146,7 +130,7 @@ type FlagsValue struct {
}
// GetFlagValues returns the possible flags for this parameter.
func (p *ParameterSpec) GetFlagValues() []*FlagsValue {
func (p *ParamSpec) GetFlagValues() []*FlagsValue {
var gSize C.guint
gFlags := C.getParamSpecFlags(p.paramSpec, &gSize)
size := int(gSize)

View File

@@ -0,0 +1,134 @@
package gst
// #include "gst.go.h"
import "C"
import "github.com/tinyzimmer/go-glib/glib"
// NewStringParam returns a new ParamSpec that will hold a string value.
func NewStringParam(name, nick, blurb string, defaultValue *string, flags ParameterFlags) *ParamSpec {
var cdefault *C.gchar
if defaultValue != nil {
cdefault = C.CString(*defaultValue)
}
paramSpec := C.g_param_spec_string(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
(*C.gchar)(cdefault),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// NewBoolParam creates a new ParamSpec that will hold a boolean value.
func NewBoolParam(name, nick, blurb string, defaultValue bool, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_boolean(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
gboolean(defaultValue),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// NewIntParam creates a new ParamSpec that will hold a signed integer value.
func NewIntParam(name, nick, blurb string, min, max, defaultValue int, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_int(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
C.gint(min),
C.gint(max),
C.gint(defaultValue),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// NewUintParam creates a new ParamSpec that will hold an unsigned integer value.
func NewUintParam(name, nick, blurb string, min, max, defaultValue uint, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_uint(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
C.guint(min),
C.guint(max),
C.guint(defaultValue),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// NewInt64Param creates a new ParamSpec that will hold a signed 64-bit integer value.
func NewInt64Param(name, nick, blurb string, min, max, defaultValue int64, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_int64(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
C.gint64(min),
C.gint64(max),
C.gint64(defaultValue),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// NewUint64Param creates a new ParamSpec that will hold an unsigned 64-bit integer value.
func NewUint64Param(name, nick, blurb string, min, max, defaultValue uint64, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_uint64(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
C.guint64(min),
C.guint64(max),
C.guint64(defaultValue),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// NewFloat32Param creates a new ParamSpec that will hold a 32-bit float value.
func NewFloat32Param(name, nick, blurb string, min, max, defaultValue float32, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_float(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
C.gfloat(min),
C.gfloat(max),
C.gfloat(defaultValue),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// NewFloat64Param creates a new ParamSpec that will hold a 64-bit float value.
func NewFloat64Param(name, nick, blurb string, min, max, defaultValue float64, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_double(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
C.gdouble(min),
C.gdouble(max),
C.gdouble(defaultValue),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}
// TypeCaps is the static Glib Type for a GstCaps.
var TypeCaps = glib.Type(C.gst_caps_get_type())
// NewBoxedParam creates a new ParamSpec containing a boxed type. Some helper type castings are included
// in these bindings.
func NewBoxedParam(name, nick, blurb string, boxedType glib.Type, flags ParameterFlags) *ParamSpec {
paramSpec := C.g_param_spec_boxed(
(*C.gchar)(C.CString(name)),
(*C.gchar)(C.CString(nick)),
(*C.gchar)(C.CString(blurb)),
C.GType(boxedType),
C.GParamFlags(flags),
)
return &ParamSpec{paramSpec: paramSpec}
}

View File

@@ -66,17 +66,17 @@ func (o *Object) Interfaces() []string {
// set in this object, or their defaults.
//
// Unref after usage.
func (o *Object) ListProperties() []*ParameterSpec {
func (o *Object) ListProperties() []*ParamSpec {
var size C.guint
props := C.g_object_class_list_properties((*C.GObjectClass)(o.Class()), &size)
if props == nil {
return nil
}
defer C.g_free((C.gpointer)(props))
out := make([]*ParameterSpec, 0)
out := make([]*ParamSpec, 0)
for _, prop := range (*[1 << 30]*C.GParamSpec)(unsafe.Pointer(props))[:size:size] {
C.g_param_spec_sink(prop) // steal the ref on the property
out = append(out, &ParameterSpec{
out = append(out, &ParamSpec{
paramSpec: prop,
})
}

View File

@@ -752,7 +752,7 @@ func (p *Pad) QueryPosition(format Format) (bool, int64) {
// RemoveProbe removes the probe with id from pad.
func (p *Pad) RemoveProbe(id uint64) {
C.gst_pad_remove_probe(p.Instance(), C.gulong(id))
C.gst_pad_remove_probe(p.Instance(), C.guint64(id))
}
// SendEvent sends the event to the pad. This function can be used by applications to send events in the pipeline.

View File

@@ -14,6 +14,9 @@ type Query struct {
ptr *C.GstQuery
}
// Type returns the type of the Query.
func (q *Query) Type() QueryType { return QueryType(q.ptr._type) }
// FromGstQueryUnsafe wraps the pointer to the given C GstQuery with the go type.
// This is meant for internal usage and is exported for visibility to other packages.
func FromGstQueryUnsafe(query unsafe.Pointer) *Query { return wrapQuery((*C.GstQuery)(query)) }

View File

@@ -15,8 +15,8 @@ import (
"reflect"
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
)
// GoElement is an interface to be implemented by GStreamer elements built using the
@@ -76,22 +76,25 @@ func gtypeForGoElement(name string, elem GoElement, extendable Extendable) C.GTy
ext: extendable,
}
ptr := gopointer.Save(classData)
typeInfo := C.GTypeInfo{
class_size: C.gushort(extendable.ClassSize()),
base_init: nil,
base_finalize: nil,
class_init: C.GClassInitFunc(C.cgoClassInit),
class_finalize: nil,
class_data: (C.gconstpointer)(ptr),
instance_size: C.gushort(extendable.InstanceSize()),
n_preallocs: 0,
instance_init: C.GInstanceInitFunc(C.cgoInstanceInit),
value_table: nil,
}
typeInfo := (*C.GTypeInfo)(C.malloc(C.sizeof_GTypeInfo))
defer C.free(unsafe.Pointer(typeInfo))
typeInfo.base_init = nil
typeInfo.base_finalize = nil
typeInfo.class_size = C.gushort(extendable.ClassSize())
typeInfo.class_finalize = nil
typeInfo.class_init = C.GClassInitFunc(C.cgoClassInit)
typeInfo.class_data = (C.gconstpointer)(ptr)
typeInfo.instance_size = C.gushort(extendable.InstanceSize())
typeInfo.n_preallocs = 0
typeInfo.instance_init = C.GInstanceInitFunc(C.cgoInstanceInit)
typeInfo.value_table = nil
gtype := C.g_type_register_static(
C.GType(extendable.Type()),
(*C.gchar)(C.CString(name)),
&typeInfo,
typeInfo,
C.GTypeFlags(0),
)
elem.TypeInit(&TypeInstance{gtype: gtype, gotype: elem})