pull in upstream interface improvements and add a few more gstreamer interfaces

This commit is contained in:
Avi Zimmerman
2021-01-18 08:50:34 +02:00
parent 1427ab6b64
commit 546d620440
23 changed files with 969 additions and 292 deletions

View File

@@ -36,6 +36,7 @@ import (
"fmt"
"os"
"github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst"
)
@@ -51,7 +52,7 @@ func main() {
// Create a main loop. This is only required when utilizing signals via the bindings.
// In this example, the AddWatch on the pipeline bus requires iterating on the main loop.
mainLoop := gst.NewMainLoop(gst.DefaultMainContext(), false)
mainLoop := glib.NewMainLoop(glib.MainContextDefault(), false)
defer mainLoop.Unref()
// Build a pipeline string from the cli arguments

View File

@@ -47,7 +47,7 @@ type pluginConfig struct {
}
type elementConfig struct {
Name, Rank, Impl, Subclass string
Name, Rank, Impl, Subclass, Interfaces string
}
func buildCfgFromDir(dir string) *libraryConfig {
@@ -119,6 +119,9 @@ var pluginTmpl = template.Must(template.New("").Funcs(template.FuncMap{
"adjustedName": func(name string) string {
return strings.ToLower(strings.Replace(name, "-", "_", -1))
},
"splitInterfaces": func(ifacesString string) []string {
return strings.Split(ifacesString, ",")
},
"extendsFromBase": func(subclass string) bool {
if strings.HasPrefix(subclass, "base.") {
return true
@@ -163,6 +166,12 @@ var pluginMeta = &gst.PluginMetadata{
&{{ .Config.Element.Impl }}{},
// The base subclass this element extends
{{ .Config.Element.Subclass }},
{{- if .Config.Element.Interfaces }}
// The interfaces this element implements
{{- range $index, $interface := .Config.Element.Interfaces | splitInterfaces }}
{{ $interface }},
{{- end }}
{{- end }}
)
},
}

View File

@@ -60,7 +60,7 @@ func playbin(mainLoop *glib.MainLoop) error {
// Watch state change events
case gst.MessageStateChanged:
if _, newState := msg.ParseStateChanged(); newState == gst.StatePlaying {
bin := gst.BinFromElement(playbin)
bin := gst.ToGstBin(playbin)
// Generate a dot graph of the pipeline to GST_DEBUG_DUMP_DOT_DIR if defined
bin.DebugBinToDotFile(gst.DebugGraphShowAll, "PLAYING")
}

View File

@@ -0,0 +1,27 @@
//go:generate gst-plugin-gen
//
// +plugin:Name=boilerplate
// +plugin:Description=My plugin written in go
// +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-18
//
// +element:Name=myelement
// +element:Rank=gst.RankNone
// +element:Impl=myelement
// +element:Subclass=gst.ExtendsElement
//
package main
import "github.com/tinyzimmer/go-glib/glib"
func main() {}
type myelement struct{}
func (g *myelement) New() glib.GoObjectSubclass { return &myelement{} }
func (g *myelement) ClassInit(klass *glib.ObjectClass) {}

View File

@@ -0,0 +1,27 @@
//go:generate gst-plugin-gen
//
// +plugin:Name=gobin
// +plugin:Description=A bin element written in go
// +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-18
//
// +element:Name=gobin
// +element:Rank=gst.RankNone
// +element:Impl=gobin
// +element:Subclass=gst.ExtendsBin
//
package main
import "github.com/tinyzimmer/go-glib/glib"
func main() {}
type gobin struct{}
func (g *gobin) New() glib.GoObjectSubclass { return &gobin{} }
func (g *gobin) ClassInit(klass *glib.ObjectClass) {}

View File

@@ -29,6 +29,8 @@
// +element:Rank=gst.RankNone
// +element:Impl=fileSink
// +element:Subclass=base.ExtendsBaseSink
// +element:Interfaces=gst.InterfaceURIHandler
//
package main
import (
@@ -119,13 +121,6 @@ func (f *fileSink) New() glib.GoObjectSubclass {
}
}
// The TypeInit method should register any additional interfaces provided by the element.
// In this example we signal to the type system that we also implement the GstURIHandler interface.
func (f *fileSink) TypeInit(instance *glib.TypeInstance) {
CAT.Log(gst.LevelLog, "Adding URIHandler interface to type")
instance.AddInterface(gst.InterfaceURIHandler)
}
// The ClassInit method should specify the metadata for this element and add any pad templates
// and properties.
func (f *fileSink) ClassInit(klass *glib.ObjectClass) {

View File

@@ -29,6 +29,8 @@
// +element:Rank=gst.RankNone
// +element:Impl=fileSrc
// +element:Subclass=base.ExtendsBaseSrc
// +element:Interfaces=gst.InterfaceURIHandler
//
package main
import (
@@ -123,13 +125,6 @@ func (f *fileSrc) New() glib.GoObjectSubclass {
}
}
// The TypeInit method should register any additional interfaces provided by the element.
// In this example we signal to the type system that we also implement the GstURIHandler interface.
func (f *fileSrc) TypeInit(instance *glib.TypeInstance) {
CAT.Log(gst.LevelLog, "Adding URIHandler interface to type")
instance.AddInterface(gst.InterfaceURIHandler)
}
// The ClassInit method should specify the metadata for this element and add any pad templates
// and properties.
func (f *fileSrc) ClassInit(klass *glib.ObjectClass) {

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.7
github.com/tinyzimmer/go-glib v0.0.11
)

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.7 h1:09SIbhaL+E+5U/4qbZXiM7f6HEDvcxOBuEiSCkT9FNw=
github.com/tinyzimmer/go-glib v0.0.7/go.mod h1:zy2cs6eXSTtqqYrv9/UgYMDfr4pWKuYPSzwX87cBGX4=
github.com/tinyzimmer/go-glib v0.0.11 h1:+X15JtyglmBhiLu5KXHWxcxhypyc/CEqW+SIFmjZ110=
github.com/tinyzimmer/go-glib v0.0.11/go.mod h1:zy2cs6eXSTtqqYrv9/UgYMDfr4pWKuYPSzwX87cBGX4=

View File

@@ -19,12 +19,14 @@ inline GObjectClass * toGObjectClass (void *p) { return (G_
inline GstAllocator * toGstAllocator (void *p) { return (GST_ALLOCATOR_CAST(p)); }
inline GstBin * toGstBin (void *p) { return (GST_BIN(p)); }
inline GstBinClass * toGstBinClass (void *p) { return (GST_BIN_CLASS(p)); }
inline GstBufferList * toGstBufferList (void *p) { return (GST_BUFFER_LIST(p)); }
inline GstBufferPool * toGstBufferPool (void *p) { return (GST_BUFFER_POOL(p)); }
inline GstBuffer * toGstBuffer (void *p) { return (GST_BUFFER(p)); }
inline GstBus * toGstBus (void *p) { return (GST_BUS(p)); }
inline GstCapsFeatures * toGstCapsFeatures (void *p) { return (GST_CAPS_FEATURES(p)); }
inline GstCaps * toGstCaps (void *p) { return (GST_CAPS(p)); }
inline GstChildProxy * toGstChildProxy (void *p) { return (GST_CHILD_PROXY(p)); }
inline GstClock * toGstClock (void *p) { return (GST_CLOCK(p)); }
inline GstContext * toGstContext (void *p) { return (GST_CONTEXT_CAST(p)); }
inline GstDevice * toGstDevice (void *p) { return (GST_DEVICE_CAST(p)); }

View File

@@ -1,6 +1,73 @@
package gst
// #include "gst.go.h"
/*
#include "gst.go.h"
gboolean
binParentAddElement (GstBin * bin, GstElement * element)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(bin));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
return parent->add_element(bin, element);
}
void
binParentDeepElementAdded (GstBin * bin, GstBin * subbin, GstElement * element)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(bin));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
parent->deep_element_added(bin, subbin, element);
}
void
binParentDeepElementRemoved (GstBin * bin, GstBin * subbin, GstElement * element)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(element));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
parent->deep_element_removed(bin, subbin, element);
}
gboolean
binParentDoLatency (GstBin * bin)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(bin));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
return parent->do_latency(bin);
}
void
binParentElementAdded (GstBin * bin, GstElement * element)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(bin));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
parent->element_added(bin, element);
}
void
binParentElementRemoved (GstBin * bin, GstElement * element)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(bin));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
parent->element_removed(bin, element);
}
void
binParentHandleMessage (GstBin * bin, GstMessage * message)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(bin));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
parent->handle_message(bin, message);
}
gboolean
binParentRemoveElement (GstBin * bin, GstElement * element)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(bin));
GstBinClass * parent = toGstBinClass(g_type_class_peek_parent(this_class));
return parent->remove_element(bin, element);
}
*/
import "C"
import (
@@ -22,14 +89,18 @@ func NewBin(name string) *Bin {
return wrapBin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(bin))})
}
// BinFromElement wraps the given Element in a Bin reference. This only works for elements
// that implement their own Bin, such as playbin. If the provided element does not implement
// a Bin then nil is returned.
func BinFromElement(elem *Element) *Bin {
if C.toGstBin(elem.Unsafe()) == nil {
return nil
// ToGstBin wraps the given glib.Object, gst.Object, or gst.Element in a Bin instance. Only
// works for objects that implement their own Bin.
func ToGstBin(obj interface{}) *Bin {
switch obj := obj.(type) {
case *Object:
return &Bin{&Element{Object: obj}}
case *Element:
return &Bin{obj}
case *glib.Object:
return &Bin{&Element{Object: &Object{InitiallyUnowned: &glib.InitiallyUnowned{Object: obj}}}}
}
return &Bin{elem}
return nil
}
// Instance returns the underlying GstBin instance.
@@ -95,10 +166,10 @@ func (b *Bin) GetElementsSorted() ([]*Element, error) {
// element is found, it returns the element. You can cast this element to the given interface afterwards.
// If you want all elements that implement the interface, use GetAllByInterface. This function recurses
// into child bins.
func (b *Bin) GetByInterface(iface glib.Type) (*Element, error) {
elem := C.gst_bin_get_by_interface(b.Instance(), C.GType(iface))
func (b *Bin) GetByInterface(iface glib.Interface) (*Element, error) {
elem := C.gst_bin_get_by_interface(b.Instance(), C.GType(iface.Type()))
if elem == nil {
return nil, fmt.Errorf("Could not find any elements implementing %s", iface.Name())
return nil, fmt.Errorf("Could not find any elements implementing %s", iface.Type().Name())
}
return wrapElement(toGObject(unsafe.Pointer(elem))), nil
}
@@ -106,8 +177,8 @@ func (b *Bin) GetByInterface(iface glib.Type) (*Element, error) {
// GetAllByInterface looks for all elements inside the bin that implements the given interface. You can
// safely cast all returned elements to the given interface. The function recurses inside child bins.
// The function will return a series of Elements that should be unreffed after use.
func (b *Bin) GetAllByInterface(iface glib.Type) ([]*Element, error) {
iterator := C.gst_bin_iterate_all_by_interface(b.Instance(), C.GType(iface))
func (b *Bin) GetAllByInterface(iface glib.Interface) ([]*Element, error) {
iterator := C.gst_bin_iterate_all_by_interface(b.Instance(), C.GType(iface.Type()))
return iteratorToElementSlice(iterator)
}
@@ -123,7 +194,7 @@ func (b *Bin) GetAllByInterface(iface glib.Type) ([]*Element, error) {
// Add adds an element to the bin.
func (b *Bin) Add(elem *Element) error {
if ok := C.gst_bin_add((*C.GstBin)(b.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
return fmt.Errorf("Failed to add element to pipeline: %s", elem.Name())
return fmt.Errorf("Failed to add element to pipeline: %s", elem.GetName())
}
return nil
}
@@ -141,7 +212,7 @@ func (b *Bin) AddMany(elems ...*Element) error {
// Remove removes an element from the Bin.
func (b *Bin) Remove(elem *Element) error {
if ok := C.gst_bin_remove((*C.GstBin)(b.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
return fmt.Errorf("Failed to add element to pipeline: %s", elem.Name())
return fmt.Errorf("Failed to add element to pipeline: %s", elem.GetName())
}
return nil
}
@@ -257,3 +328,43 @@ func iteratorToElementSlice(iterator *C.GstIterator) ([]*Element, error) {
}
}
}
// ParentAddElement chains up to the parent AddElement handler.
func (b *Bin) ParentAddElement(element *Element) bool {
return gobool(C.binParentAddElement(b.Instance(), element.Instance()))
}
// ParentDeepElementAdded chains up to the parent DeepElementAdded handler.
func (b *Bin) ParentDeepElementAdded(subbin *Bin, element *Element) {
C.binParentDeepElementAdded(b.Instance(), subbin.Instance(), element.Instance())
}
// ParentDeepElementRemoved chains up to the parent DeepElementRemoved handler.
func (b *Bin) ParentDeepElementRemoved(subbin *Bin, element *Element) {
C.binParentDeepElementRemoved(b.Instance(), subbin.Instance(), element.Instance())
}
// ParentDoLatency chains up to the parent DoLatency handler.
func (b *Bin) ParentDoLatency() bool {
return gobool(C.binParentDoLatency(b.Instance()))
}
// ParentElementAdded chains up to the parent ElementAdded handler.
func (b *Bin) ParentElementAdded(element *Element) {
C.binParentElementAdded(b.Instance(), element.Instance())
}
// ParentElementRemoved chains up to the parent ElementRemoved handler.
func (b *Bin) ParentElementRemoved(element *Element) {
C.binParentElementRemoved(b.Instance(), element.Instance())
}
// ParentHandleMessage chains up to the parent HandleMessage handler.
func (b *Bin) ParentHandleMessage(message *Message) {
C.binParentHandleMessage(b.Instance(), message.Instance())
}
// ParentRemoveElement chains up to the parent RemoveElement handler.
func (b *Bin) ParentRemoveElement(element *Element) bool {
return gobool(C.binParentRemoveElement(b.Instance(), element.Instance()))
}

91
gst/gst_bin_exports.go Normal file
View File

@@ -0,0 +1,91 @@
package gst
/*
#include "gst.go.h"
*/
import "C"
import (
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
)
func cbWrapBin(bin *C.GstBin) *Bin {
return wrapBin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(bin))})
}
func cbWrapElement(elem *C.GstElement) *Element {
return wrapElement(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(elem))})
}
//export goGstBinAddElement
func goGstBinAddElement(bin *C.GstBin, element *C.GstElement) C.gboolean {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
AddElement(self *Bin, element *Element) bool
})
return gboolean(caller.AddElement(cbWrapBin(bin), cbWrapElement(element)))
}
//export goGstBinDeepElementAdded
func goGstBinDeepElementAdded(bin *C.GstBin, subbin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
DeepElementAdded(self *Bin, subbin *Bin, child *Element)
})
caller.DeepElementAdded(cbWrapBin(bin), cbWrapBin(subbin), cbWrapElement(child))
}
//export goGstBinDeepElementRemoved
func goGstBinDeepElementRemoved(bin *C.GstBin, subbin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
DeepElementRemoved(self *Bin, subbin *Bin, child *Element)
})
caller.DeepElementRemoved(cbWrapBin(bin), cbWrapBin(subbin), cbWrapElement(child))
}
//export goGstBinDoLatency
func goGstBinDoLatency(bin *C.GstBin) C.gboolean {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
DoLatency(self *Bin) bool
})
return gboolean(caller.DoLatency(cbWrapBin(bin)))
}
//export goGstBinElementAdded
func goGstBinElementAdded(bin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
ElementAdded(self *Bin, child *Element)
})
caller.ElementAdded(cbWrapBin(bin), cbWrapElement(child))
}
//export goGstBinElementRemoved
func goGstBinElementRemoved(bin *C.GstBin, child *C.GstElement) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
ElementRemoved(self *Bin, child *Element)
})
caller.ElementRemoved(cbWrapBin(bin), cbWrapElement(child))
}
//export goGstBinHandleMessage
func goGstBinHandleMessage(bin *C.GstBin, message *C.GstMessage) {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
HandleMessage(self *Bin, msg *Message)
})
caller.HandleMessage(cbWrapBin(bin), wrapMessage(message))
}
//export goGstBinRemoveElement
func goGstBinRemoveElement(bin *C.GstBin, element *C.GstElement) C.gboolean {
elem := glib.FromObjectUnsafePrivate(unsafe.Pointer(bin))
caller := elem.(interface {
RemoveElement(self *Bin, element *Element) bool
})
return gboolean(caller.RemoveElement(cbWrapBin(bin), cbWrapElement(element)))
}

106
gst/gst_bin_impl.go Normal file
View File

@@ -0,0 +1,106 @@
package gst
/*
#include "gst.go.h"
extern gboolean goGstBinAddElement (GstBin * bin, GstElement * element);
extern void goGstBinDeepElementAdded (GstBin * bin, GstBin * subbin, GstElement * child);
extern void goGstBinDeepElementRemoved (GstBin * bin, GstBin * subbin, GstElement * child);
extern gboolean goGstBinDoLatency (GstBin * bin);
extern void goGstBinElementAdded (GstBin * bin, GstElement * child);
extern void goGstBinElementRemoved (GstBin * bin, GstElement * child);
extern void goGstBinHandleMessage (GstBin * bin, GstMessage * message);
extern gboolean goGstBinRemoveElement (GstBin * bin, GstElement * element);
void setGstBinAddElement (GstBinClass * klass) { klass->add_element = goGstBinAddElement; };
void setGstBinDeepElementAdded (GstBinClass * klass) { klass->deep_element_added = goGstBinDeepElementAdded; };
void setGstBinDeepElementRemoved (GstBinClass * klass) { klass->deep_element_removed = goGstBinDeepElementRemoved; };
void setGstBinDoLatency (GstBinClass * klass) { klass->do_latency = goGstBinDoLatency; };
void setGstBinElementAdded (GstBinClass * klass) { klass->element_added = goGstBinElementAdded; };
void setGstBinElementRemoved (GstBinClass * klass) { klass->element_removed = goGstBinElementRemoved; };
void setGstBinHandleMessage (GstBinClass * klass) { klass->handle_message = goGstBinHandleMessage; };
void setGstBinRemoveElement (GstBinClass * klass) { klass->remove_element = goGstBinRemoveElement; };
*/
import "C"
import (
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
)
// ExtendsBin implements an Extendable object based on a GstBin.
var ExtendsBin glib.Extendable = &extendsBin{parent: ExtendsElement}
// BinImpl is the reference interface for Go elements extending a Bin. You only need to
// implement the methods that interest you.
type BinImpl interface {
AddElement(self *Bin, element *Element) bool
DeepElementAdded(self *Bin, subbin *Bin, child *Element)
DeepElementRemoved(self *Bin, subbin *Bin, child *Element)
DoLatency(self *Bin) bool
ElementAdded(self *Bin, child *Element)
ElementRemoved(self *Bin, child *Element)
HandleMessage(self *Bin, msg *Message)
RemoveElement(self *Bin, element *Element) bool
}
type extendsBin struct{ parent glib.Extendable }
func (e *extendsBin) Type() glib.Type { return glib.Type(C.gst_bin_get_type()) }
func (e *extendsBin) ClassSize() int64 { return int64(C.sizeof_GstBinClass) }
func (e *extendsBin) InstanceSize() int64 { return int64(C.sizeof_GstBin) }
func (e *extendsBin) InitClass(klass unsafe.Pointer, elem glib.GoObjectSubclass) {
e.parent.InitClass(klass, elem)
class := C.toGstBinClass(klass)
if _, ok := elem.(interface {
AddElement(self *Bin, element *Element) bool
}); ok {
C.setGstBinAddElement(class)
}
if _, ok := elem.(interface {
DeepElementAdded(self *Bin, subbin *Bin, child *Element)
}); ok {
C.setGstBinDeepElementAdded(class)
}
if _, ok := elem.(interface {
DeepElementRemoved(self *Bin, subbin *Bin, child *Element)
}); ok {
C.setGstBinDeepElementRemoved(class)
}
if _, ok := elem.(interface {
DoLatency(self *Bin) bool
}); ok {
C.setGstBinDoLatency(class)
}
if _, ok := elem.(interface {
ElementAdded(self *Bin, child *Element)
}); ok {
C.setGstBinElementAdded(class)
}
if _, ok := elem.(interface {
ElementRemoved(self *Bin, child *Element)
}); ok {
C.setGstBinElementRemoved(class)
}
if _, ok := elem.(interface {
HandleMessage(self *Bin, msg *Message)
}); ok {
C.setGstBinHandleMessage(class)
}
if _, ok := elem.(interface {
RemoveElement(self *Bin, element *Element) bool
}); ok {
C.setGstBinRemoveElement(class)
}
}

222
gst/gst_child_proxy.go Normal file
View File

@@ -0,0 +1,222 @@
package gst
/*
#include "gst.go.h"
extern void goGstChildProxyChildAdded (GstChildProxy * parent, GObject * child, const gchar * name);
extern void goGstChildProxyChildRemoved (GstChildProxy * parent, GObject * child, const gchar * name);
extern GObject * goGstChildProxyGetChildByIndex (GstChildProxy * parent, guint idx);
extern GObject * goGstChildProxyGetChildByName (GstChildProxy * parent, const gchar * name);
extern guint goGstChildProxyGetChildrenCount (GstChildProxy * parent);
void setGstChildProxyChildAdded (gpointer iface) { ((GstChildProxyInterface*)iface)->child_added = goGstChildProxyChildAdded; }
void setGstChildProxyChildRemoved (gpointer iface) { ((GstChildProxyInterface*)iface)->child_removed = goGstChildProxyChildRemoved; }
void setGstChildProxyGetChildByIndex (gpointer iface) { ((GstChildProxyInterface*)iface)->get_child_by_index = goGstChildProxyGetChildByIndex; }
void setGstChildProxyGetChildByName (gpointer iface) { ((GstChildProxyInterface*)iface)->get_child_by_name = goGstChildProxyGetChildByName; }
void setGstChildProxyGetChildrenCount (gpointer iface) { ((GstChildProxyInterface*)iface)->get_children_count = goGstChildProxyGetChildrenCount; }
*/
import "C"
import (
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
)
// InterfaceChildProxy represents the GstChildProxy interface. Use this when querying bins
// for elements that implement GstChildProxy, or when signaling that a GoObjectSubclass
// provides this interface.
var InterfaceChildProxy glib.Interface = &interfaceChildProxy{}
type interfaceChildProxy struct{ glib.Interface }
func (i *interfaceChildProxy) Type() glib.Type { return glib.Type(C.GST_TYPE_CHILD_PROXY) }
func (i *interfaceChildProxy) InitFunc() glib.InterfaceInitFunc {
return func(instance *glib.TypeInstance) {
goobj := instance.GoType
if _, ok := goobj.(interface {
ChildAdded(self *ChildProxy, child *glib.Object, name string)
}); ok {
C.setGstChildProxyChildAdded((C.gpointer)(instance.GTypeInstance))
}
if _, ok := goobj.(interface {
ChildRemoved(self *ChildProxy, child *glib.Object, name string)
}); ok {
C.setGstChildProxyChildRemoved((C.gpointer)(instance.GTypeInstance))
}
if _, ok := goobj.(interface {
GetChildByIndex(self *ChildProxy, idx uint) *glib.Object
}); ok {
C.setGstChildProxyGetChildByIndex((C.gpointer)(instance.GTypeInstance))
}
if _, ok := goobj.(interface {
GetChildByName(self *ChildProxy, name string) *glib.Object
}); ok {
C.setGstChildProxyGetChildByName((C.gpointer)(instance.GTypeInstance))
}
if _, ok := goobj.(interface {
GetChildrenCount(self *ChildProxy) uint
}); ok {
C.setGstChildProxyGetChildrenCount((C.gpointer)(instance.GTypeInstance))
}
}
}
// ChildProxyImpl is the reference implementation for a ChildProxy implemented by a Go object.
type ChildProxyImpl interface {
ChildAdded(self *ChildProxy, child *glib.Object, name string)
ChildRemoved(self *ChildProxy, child *glib.Object, name string)
GetChildByIndex(self *ChildProxy, idx uint) *glib.Object
GetChildByName(self *ChildProxy, name string) *glib.Object
GetChildrenCount(self *ChildProxy) uint
}
// ChildProxy is an interface that abstracts handling of property sets for
// elements with children. They all have multiple GstPad or some kind of voice
// objects. Another use case are container elements like GstBin. The element
// implementing the interface acts as a parent for those child objects.
//
// Property names are written as "child-name::property-name". The whole naming
// scheme is recursive. Thus "child1::child2::property" is valid too, if "child1"
// and "child2" implement the GstChildProxy interface.
type ChildProxy struct{ ptr *C.GstChildProxy }
// ToChildProxy returns a ChildProxy for the given element. If the element does not implement
// a ChildProxy it returns nil.
func ToChildProxy(elem *Element) *ChildProxy {
if proxy := C.toGstChildProxy(elem.Unsafe()); proxy != nil {
return &ChildProxy{proxy}
}
return nil
}
// Instance returns the underlying GstChildProxy instance.
func (c *ChildProxy) Instance() *C.GstChildProxy {
return C.toGstChildProxy(unsafe.Pointer(c.ptr))
}
// ChildAdded emits the "child-added" signal.
func (c *ChildProxy) ChildAdded(child *glib.Object, name string) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
C.gst_child_proxy_child_added(
c.Instance(),
(*C.GObject)(child.Unsafe()),
(*C.gchar)(unsafe.Pointer(cname)),
)
}
// ChildRemoved emits the "child-removed" signal.
func (c *ChildProxy) ChildRemoved(child *glib.Object, name string) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
C.gst_child_proxy_child_removed(
c.Instance(),
(*C.GObject)(child.Unsafe()),
(*C.gchar)(unsafe.Pointer(cname)),
)
}
// Get gets properties of the parent object and its children. This is a direct alias to looping
// over GetProperty and returning the results in the order of the arguments. If any of the results
// returns nil from an allocation error, nil is returned for the entire slice.
func (c *ChildProxy) Get(names ...string) []*glib.Value {
out := make([]*glib.Value, len(names))
for i, name := range names {
val := c.GetProperty(name)
if val == nil {
return nil
}
out[i] = val
}
return out
}
// GetChildByIndex fetches a child by its number. This function can return nil if the object is not
// found. Unref after usage.
func (c *ChildProxy) GetChildByIndex(idx uint) *glib.Object {
gobj := C.gst_child_proxy_get_child_by_index(c.Instance(), C.guint(idx))
if gobj == nil {
return nil
}
return &glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gobj))}
}
// GetChildByName fetches a child by name. The virtual method's default implementation uses Object
// together with Object.GetName. If the interface is to be used with GObjects, this method needs
// to be overridden.
//
// This function can return nil if the object is not found. Unref after usage.
func (c *ChildProxy) GetChildByName(name string) *glib.Object {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
gobj := C.gst_child_proxy_get_child_by_name(c.Instance(), (*C.gchar)(unsafe.Pointer(cname)))
if gobj == nil {
return nil
}
return &glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gobj))}
}
// GetChildrenCount returns the number of child objects the parent contains.
func (c *ChildProxy) GetChildrenCount() uint {
return uint(C.gst_child_proxy_get_children_count(c.Instance()))
}
// GetProperty gets a single property using the ChildProxy mechanism. The bindings
// take care of freeing the value when it leaves the user's scope. This function
// can return nil if a failure happens trying to allocate GValues.
func (c *ChildProxy) GetProperty(name string) *glib.Value {
value, err := glib.ValueAlloc()
if err != nil {
return nil
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
C.gst_child_proxy_get_property(c.Instance(), (*C.gchar)(unsafe.Pointer(cname)), (*C.GValue)(unsafe.Pointer(value.GValue)))
return value
}
// Lookup looks up which object and and parameter would be affected by the given name.
// If ok is false, the targets could not be found and this function returned nil.
// Unref target after usage.
func (c *ChildProxy) Lookup(name string) (ok bool, target *glib.Object, param *glib.ParamSpec) {
var gtarget *C.GObject
var gspec *C.GParamSpec
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
ok = gobool(C.gst_child_proxy_lookup(
c.Instance(),
(*C.gchar)(unsafe.Pointer(cname)),
&gtarget, &gspec,
))
if !ok {
return
}
target = &glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gtarget))}
param = glib.ToParamSpec(unsafe.Pointer(gspec))
return
}
// Set takes a map of names to values and applies them using the ChildProxy mechanism.
func (c *ChildProxy) Set(values map[string]*glib.Value) {
for name, value := range values {
c.SetProperty(name, value)
}
}
// SetProperty sets a single property using the ChildProxy mechanism.
func (c *ChildProxy) SetProperty(name string, value *glib.Value) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
C.gst_child_proxy_set_property(
c.Instance(),
(*C.gchar)(unsafe.Pointer(cname)),
(*C.GValue)(unsafe.Pointer(value.GValue)),
)
}

View File

@@ -0,0 +1,74 @@
package gst
/*
#include "gst.go.h"
*/
import "C"
import (
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
)
func wrapParent(parent *C.GstChildProxy) *ChildProxy { return &ChildProxy{ptr: parent} }
//export goGstChildProxyChildAdded
func goGstChildProxyChildAdded(parent *C.GstChildProxy, child *C.GObject, name *C.gchar) {
iface := glib.FromObjectUnsafePrivate(unsafe.Pointer(parent))
caller := iface.(interface {
ChildAdded(self *ChildProxy, child *glib.Object, name string)
})
caller.ChildAdded(
wrapParent(parent),
&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(child))},
C.GoString(name),
)
}
//export goGstChildProxyChildRemoved
func goGstChildProxyChildRemoved(parent *C.GstChildProxy, child *C.GObject, name *C.gchar) {
iface := glib.FromObjectUnsafePrivate(unsafe.Pointer(parent))
caller := iface.(interface {
ChildRemoved(self *ChildProxy, child *glib.Object, name string)
})
caller.ChildRemoved(
wrapParent(parent),
&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(child))},
C.GoString(name),
)
}
//export goGstChildProxyGetChildByIndex
func goGstChildProxyGetChildByIndex(parent *C.GstChildProxy, idx C.guint) *C.GObject {
iface := glib.FromObjectUnsafePrivate(unsafe.Pointer(parent))
caller := iface.(interface {
GetChildByIndex(self *ChildProxy, idx uint) *glib.Object
})
obj := caller.GetChildByIndex(wrapParent(parent), uint(idx))
if obj == nil {
return nil
}
return (*C.GObject)(unsafe.Pointer(obj.GObject))
}
//export goGstChildProxyGetChildByName
func goGstChildProxyGetChildByName(parent *C.GstChildProxy, name *C.gchar) *C.GObject {
iface := glib.FromObjectUnsafePrivate(unsafe.Pointer(parent))
caller := iface.(interface {
GetChildByName(self *ChildProxy, name string) *glib.Object
})
obj := caller.GetChildByName(wrapParent(parent), C.GoString(name))
if obj == nil {
return nil
}
return (*C.GObject)(unsafe.Pointer(obj.GObject))
}
//export goGstChildProxyGetChildrenCount
func goGstChildProxyGetChildrenCount(parent *C.GstChildProxy) C.guint {
iface := glib.FromObjectUnsafePrivate(unsafe.Pointer(parent))
caller := iface.(interface {
GetChildrenCount(self *ChildProxy) uint
})
return C.guint(caller.GetChildrenCount(wrapParent(parent)))
}

View File

@@ -70,7 +70,7 @@ func (d *Device) HasClasses(classes []string) bool {
// while in the PLAYING state.
func (d *Device) ReconfigureElement(elem *Element) error {
if ok := gobool(C.gst_device_reconfigure_element(d.Instance(), elem.Instance())); !ok {
return fmt.Errorf("Failed to reconfigure element %s", elem.Name())
return fmt.Errorf("Failed to reconfigure element %s", elem.GetName())
}
return nil
}

View File

@@ -29,40 +29,6 @@ GstStateChangeReturn elementParentChangeState (GstElement * element, GstStateCha
return parent->change_state(element, transition);
}
extern GstStateChangeReturn goGstElementClassChangeState (GstElement * element, GstStateChange change);
extern GstStateChangeReturn goGstElementClassGetState (GstElement * element, GstState * state, GstState * pending, GstClockTime timeout);
extern void goGstElementClassNoMorePads (GstElement * element);
extern void goGstElementClassPadAdded (GstElement * element, GstPad * pad);
extern void goGstElementClassPadRemoved (GstElement * element, GstPad * pad);
extern gboolean goGstElementClassPostMessage (GstElement * element, GstMessage * msg);
extern GstClock * goGstElementClassProvideClock (GstElement * element);
extern gboolean goGstElementClassQuery (GstElement * element, GstQuery * query);
extern void goGstElementClassReleasePad (GstElement * element, GstPad * pad);
extern GstPad * goGstElementClassRequestNewPad (GstElement * element, GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
extern gboolean goGstElementClassSendEvent (GstElement * element, GstEvent * event);
extern void goGstElementClassSetBus (GstElement * element, GstBus * bus);
extern gboolean goGstElementClassSetClock (GstElement * element, GstClock * clock);
extern void goGstElementClassSetContext (GstElement * element, GstContext * ctx);
extern GstStateChangeReturn goGstElementClassSetState (GstElement * element, GstState state);
extern void goGstElementClassStateChanged (GstElement * element, GstState old, GstState new, GstState pending);
void setGstElementClassChangeState (GstElementClass * klass) { klass->change_state = goGstElementClassChangeState; }
void setGstElementClassGetState (GstElementClass * klass) { klass->get_state = goGstElementClassGetState; }
void setGstElementClassNoMorePads (GstElementClass * klass) { klass->no_more_pads = goGstElementClassNoMorePads; }
void setGstElementClassPadAdded (GstElementClass * klass) { klass->pad_added = goGstElementClassPadAdded; }
void setGstElementClassPadRemoved (GstElementClass * klass) { klass->pad_removed = goGstElementClassPadRemoved; }
void setGstElementClassPostMessage (GstElementClass * klass) { klass->post_message = goGstElementClassPostMessage; }
void setGstElementClassProvideClock (GstElementClass * klass) { klass->provide_clock = goGstElementClassProvideClock; }
void setGstElementClassQuery (GstElementClass * klass) { klass->query = goGstElementClassQuery; }
void setGstElementClassReleasePad (GstElementClass * klass) { klass->release_pad = goGstElementClassReleasePad; }
void setGstElementClassRequestNewPad (GstElementClass * klass) { klass->request_new_pad = goGstElementClassRequestNewPad; }
void setGstElementClassSendEvent (GstElementClass * klass) { klass->send_event = goGstElementClassSendEvent; }
void setGstElementClassSetBus (GstElementClass * klass) { klass->set_bus = goGstElementClassSetBus; }
void setGstElementClassSetClock (GstElementClass * klass) { klass->set_clock = goGstElementClassSetClock; }
void setGstElementClassSetContext (GstElementClass * klass) { klass->set_context = goGstElementClassSetContext; }
void setGstElementClassSetState (GstElementClass * klass) { klass->set_state = goGstElementClassSetState; }
void setGstElementClassStateChanged (GstElementClass * klass) { klass->state_changed = goGstElementClassStateChanged; }
*/
import "C"
@@ -70,7 +36,6 @@ import (
"fmt"
"path"
"runtime"
"time"
"unsafe"
gopointer "github.com/mattn/go-pointer"
@@ -117,12 +82,12 @@ const (
// RegisterElement creates a new elementfactory capable of instantiating objects of the given GoElement
// and adds the factory to the plugin. A higher rank means more importance when autoplugging.
func RegisterElement(plugin *Plugin, name string, rank Rank, elem glib.GoObjectSubclass, extends glib.Extendable) bool {
func RegisterElement(plugin *Plugin, name string, rank Rank, elem glib.GoObjectSubclass, extends glib.Extendable, interfaces ...glib.Interface) bool {
return gobool(C.gst_element_register(
plugin.Instance(),
C.CString(name),
C.guint(rank),
C.GType(glib.RegisterGoType(name, elem, extends)),
C.GType(glib.RegisterGoType(name, elem, extends, interfaces...)),
))
}
@@ -340,7 +305,7 @@ func (e *Element) IsURIHandler() bool {
// Link wraps gst_element_link and links this element to the given one.
func (e *Element) Link(elem *Element) error {
if ok := C.gst_element_link((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
return fmt.Errorf("Failed to link %s to %s", e.Name(), elem.Name())
return fmt.Errorf("Failed to link %s to %s", e.GetName(), elem.GetName())
}
return nil
}
@@ -349,7 +314,7 @@ func (e *Element) Link(elem *Element) error {
// using the provided sink caps.
func (e *Element) LinkFiltered(elem *Element, caps *Caps) error {
if ok := C.gst_element_link_filtered((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance()), (*C.GstCaps)(caps.Instance())); !gobool(ok) {
return fmt.Errorf("Failed to link %s to %s with provider caps", e.Name(), elem.Name())
return fmt.Errorf("Failed to link %s to %s with provided caps", e.GetName(), elem.GetName())
}
return nil
}
@@ -459,152 +424,3 @@ func (e *Element) URIHandler() URIHandler {
}
return &gstURIHandler{ptr: e.Instance()}
}
// ExtendsElement signifies a GoElement that extends a GstElement.
var ExtendsElement glib.Extendable = &extendElement{parent: glib.ExtendsObject}
// ElementImpl is an interface containing go quivalents of the virtual methods that can be
// overridden by a plugin extending an Element.
type ElementImpl interface {
// ChangeState is called by SetState to perform an incremental state change.
ChangeState(*Element, StateChange) StateChangeReturn
// GetState should return the states of the element
GetState(self *Element, timeout time.Duration) (ret StateChangeReturn, current, pending State)
// NoMorePads is called when there are no more pads on the element.
NoMorePads(*Element)
// PadAdded is called to add a pad to the element.
PadAdded(*Element, *Pad)
// PadRemoved is called to remove a pad from the element.
PadRemoved(*Element, *Pad)
// PostMessage is called when a message is posted to the element. Call Element.ParentPostMessage
// to have it posted on the bus after processing.
PostMessage(*Element, *Message) bool
// ProvideClock is called to retrieve the clock provided by the element.
ProvideClock(*Element) *Clock
// Query is called to perform a query on the element.
Query(*Element, *Query) bool
// ReleasePad is called when a request pad is to be released.
ReleasePad(*Element, *Pad)
// RequestNewPad is called when a new pad is requested from the element.
RequestNewPad(self *Element, templ *PadTemplate, name string, caps *Caps) *Pad
// SendEvent is called to send an event to the element.
SendEvent(*Element, *Event) bool
// SetBus is called to set the Bus on the element.
SetBus(*Element, *Bus)
// SetClock is called to set the clock on the element.
SetClock(*Element, *Clock) bool
// SetContext is called to set the Context on the element.
SetContext(*Element, *Context)
// SetState is called to set a new state on the element.
SetState(*Element, State) StateChangeReturn
// StateChanged is called immediately after a new state was set.
StateChanged(self *Element, old, new, pending State)
}
type extendElement struct{ parent glib.Extendable }
func (e *extendElement) Type() glib.Type { return glib.Type(C.gst_element_get_type()) }
func (e *extendElement) ClassSize() int64 { return int64(C.sizeof_GstElementClass) }
func (e *extendElement) InstanceSize() int64 { return int64(C.sizeof_GstElement) }
func (e *extendElement) InitClass(klass unsafe.Pointer, elem glib.GoObjectSubclass) {
e.parent.InitClass(klass, elem)
elemClass := C.toGstElementClass(klass)
if _, ok := elem.(interface {
ChangeState(*Element, StateChange) StateChangeReturn
}); ok {
C.setGstElementClassChangeState(elemClass)
}
if _, ok := elem.(interface {
GetState(self *Element, timeout time.Duration) (ret StateChangeReturn, current, pending State)
}); ok {
C.setGstElementClassGetState(elemClass)
}
if _, ok := elem.(interface {
NoMorePads(*Element)
}); ok {
C.setGstElementClassNoMorePads(elemClass)
}
if _, ok := elem.(interface {
PadAdded(*Element, *Pad)
}); ok {
C.setGstElementClassPadAdded(elemClass)
}
if _, ok := elem.(interface {
PadRemoved(*Element, *Pad)
}); ok {
C.setGstElementClassPadRemoved(elemClass)
}
if _, ok := elem.(interface {
PostMessage(*Element, *Message) bool
}); ok {
C.setGstElementClassPostMessage(elemClass)
}
if _, ok := elem.(interface {
ProvideClock(*Element) *Clock
}); ok {
C.setGstElementClassProvideClock(elemClass)
}
if _, ok := elem.(interface {
Query(*Element, *Query) bool
}); ok {
C.setGstElementClassQuery(elemClass)
}
if _, ok := elem.(interface {
ReleasePad(*Element, *Pad)
}); ok {
C.setGstElementClassReleasePad(elemClass)
}
if _, ok := elem.(interface {
RequestNewPad(self *Element, templ *PadTemplate, name string, caps *Caps) *Pad
}); ok {
C.setGstElementClassRequestNewPad(elemClass)
}
if _, ok := elem.(interface {
SendEvent(*Element, *Event) bool
}); ok {
C.setGstElementClassSendEvent(elemClass)
}
if _, ok := elem.(interface {
SetBus(*Element, *Bus)
}); ok {
C.setGstElementClassSetBus(elemClass)
}
if _, ok := elem.(interface {
SetClock(*Element, *Clock) bool
}); ok {
C.setGstElementClassSetClock(elemClass)
}
if _, ok := elem.(interface {
SetContext(*Element, *Context)
}); ok {
C.setGstElementClassSetContext(elemClass)
}
if _, ok := elem.(interface {
SetState(*Element, State) StateChangeReturn
}); ok {
C.setGstElementClassSetState(elemClass)
}
if _, ok := elem.(interface {
StateChanged(self *Element, old, new, pending State)
}); ok {
C.setGstElementClassStateChanged(elemClass)
}
}

View File

@@ -14,11 +14,23 @@ import (
// This is meant for internal usage and is exported for visibility to other packages.
func FromGstElementUnsafe(elem unsafe.Pointer) *Element { return wrapElement(toGObject(elem)) }
// NewElement is a generic wrapper around `gst_element_factory_make`.
func NewElement(name string) (*Element, error) {
elemName := C.CString(name)
// NewElement creates a new element using the factory of the given name.
func NewElement(factory string) (*Element, error) {
return NewElementWithName(factory, "")
}
// NewElementWithName creates a new element and sets it's name to the given value.
func NewElementWithName(factory string, name string) (*Element, error) {
elemName := C.CString(factory)
defer C.free(unsafe.Pointer(elemName))
elem := C.gst_element_factory_make((*C.gchar)(elemName), nil)
var elem *C.GstElement
if name == "" {
elem = C.gst_element_factory_make((*C.gchar)(elemName), nil)
} else {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
elem = C.gst_element_factory_make((*C.gchar)(elemName), (*C.gchar)(cname))
}
if elem == nil {
return nil, fmt.Errorf("Could not create element: %s", name)
}

196
gst/gst_element_impl.go Normal file
View File

@@ -0,0 +1,196 @@
package gst
/*
#include "gst.go.h"
extern GstStateChangeReturn goGstElementClassChangeState (GstElement * element, GstStateChange change);
extern GstStateChangeReturn goGstElementClassGetState (GstElement * element, GstState * state, GstState * pending, GstClockTime timeout);
extern void goGstElementClassNoMorePads (GstElement * element);
extern void goGstElementClassPadAdded (GstElement * element, GstPad * pad);
extern void goGstElementClassPadRemoved (GstElement * element, GstPad * pad);
extern gboolean goGstElementClassPostMessage (GstElement * element, GstMessage * msg);
extern GstClock * goGstElementClassProvideClock (GstElement * element);
extern gboolean goGstElementClassQuery (GstElement * element, GstQuery * query);
extern void goGstElementClassReleasePad (GstElement * element, GstPad * pad);
extern GstPad * goGstElementClassRequestNewPad (GstElement * element, GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
extern gboolean goGstElementClassSendEvent (GstElement * element, GstEvent * event);
extern void goGstElementClassSetBus (GstElement * element, GstBus * bus);
extern gboolean goGstElementClassSetClock (GstElement * element, GstClock * clock);
extern void goGstElementClassSetContext (GstElement * element, GstContext * ctx);
extern GstStateChangeReturn goGstElementClassSetState (GstElement * element, GstState state);
extern void goGstElementClassStateChanged (GstElement * element, GstState old, GstState new, GstState pending);
void setGstElementClassChangeState (GstElementClass * klass) { klass->change_state = goGstElementClassChangeState; }
void setGstElementClassGetState (GstElementClass * klass) { klass->get_state = goGstElementClassGetState; }
void setGstElementClassNoMorePads (GstElementClass * klass) { klass->no_more_pads = goGstElementClassNoMorePads; }
void setGstElementClassPadAdded (GstElementClass * klass) { klass->pad_added = goGstElementClassPadAdded; }
void setGstElementClassPadRemoved (GstElementClass * klass) { klass->pad_removed = goGstElementClassPadRemoved; }
void setGstElementClassPostMessage (GstElementClass * klass) { klass->post_message = goGstElementClassPostMessage; }
void setGstElementClassProvideClock (GstElementClass * klass) { klass->provide_clock = goGstElementClassProvideClock; }
void setGstElementClassQuery (GstElementClass * klass) { klass->query = goGstElementClassQuery; }
void setGstElementClassReleasePad (GstElementClass * klass) { klass->release_pad = goGstElementClassReleasePad; }
void setGstElementClassRequestNewPad (GstElementClass * klass) { klass->request_new_pad = goGstElementClassRequestNewPad; }
void setGstElementClassSendEvent (GstElementClass * klass) { klass->send_event = goGstElementClassSendEvent; }
void setGstElementClassSetBus (GstElementClass * klass) { klass->set_bus = goGstElementClassSetBus; }
void setGstElementClassSetClock (GstElementClass * klass) { klass->set_clock = goGstElementClassSetClock; }
void setGstElementClassSetContext (GstElementClass * klass) { klass->set_context = goGstElementClassSetContext; }
void setGstElementClassSetState (GstElementClass * klass) { klass->set_state = goGstElementClassSetState; }
void setGstElementClassStateChanged (GstElementClass * klass) { klass->state_changed = goGstElementClassStateChanged; }
*/
import "C"
import (
"time"
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
)
// ExtendsElement implements an Extendable object based on a GstElement.
var ExtendsElement glib.Extendable = &extendElement{parent: glib.ExtendsObject}
// ElementImpl is an interface containing go equivalents of the virtual methods that can be
// overridden by a plugin extending an Element.
type ElementImpl interface {
// ChangeState is called by SetState to perform an incremental state change.
ChangeState(*Element, StateChange) StateChangeReturn
// GetState should return the states of the element
GetState(self *Element, timeout time.Duration) (ret StateChangeReturn, current, pending State)
// NoMorePads is called when there are no more pads on the element.
NoMorePads(*Element)
// PadAdded is called to add a pad to the element.
PadAdded(*Element, *Pad)
// PadRemoved is called to remove a pad from the element.
PadRemoved(*Element, *Pad)
// PostMessage is called when a message is posted to the element. Call Element.ParentPostMessage
// to have it posted on the bus after processing.
PostMessage(*Element, *Message) bool
// ProvideClock is called to retrieve the clock provided by the element.
ProvideClock(*Element) *Clock
// Query is called to perform a query on the element.
Query(*Element, *Query) bool
// ReleasePad is called when a request pad is to be released.
ReleasePad(*Element, *Pad)
// RequestNewPad is called when a new pad is requested from the element.
RequestNewPad(self *Element, templ *PadTemplate, name string, caps *Caps) *Pad
// SendEvent is called to send an event to the element.
SendEvent(*Element, *Event) bool
// SetBus is called to set the Bus on the element.
SetBus(*Element, *Bus)
// SetClock is called to set the clock on the element.
SetClock(*Element, *Clock) bool
// SetContext is called to set the Context on the element.
SetContext(*Element, *Context)
// SetState is called to set a new state on the element.
SetState(*Element, State) StateChangeReturn
// StateChanged is called immediately after a new state was set.
StateChanged(self *Element, old, new, pending State)
}
type extendElement struct{ parent glib.Extendable }
func (e *extendElement) Type() glib.Type { return glib.Type(C.gst_element_get_type()) }
func (e *extendElement) ClassSize() int64 { return int64(C.sizeof_GstElementClass) }
func (e *extendElement) InstanceSize() int64 { return int64(C.sizeof_GstElement) }
func (e *extendElement) InitClass(klass unsafe.Pointer, elem glib.GoObjectSubclass) {
e.parent.InitClass(klass, elem)
elemClass := C.toGstElementClass(klass)
if _, ok := elem.(interface {
ChangeState(*Element, StateChange) StateChangeReturn
}); ok {
C.setGstElementClassChangeState(elemClass)
}
if _, ok := elem.(interface {
GetState(self *Element, timeout time.Duration) (ret StateChangeReturn, current, pending State)
}); ok {
C.setGstElementClassGetState(elemClass)
}
if _, ok := elem.(interface {
NoMorePads(*Element)
}); ok {
C.setGstElementClassNoMorePads(elemClass)
}
if _, ok := elem.(interface {
PadAdded(*Element, *Pad)
}); ok {
C.setGstElementClassPadAdded(elemClass)
}
if _, ok := elem.(interface {
PadRemoved(*Element, *Pad)
}); ok {
C.setGstElementClassPadRemoved(elemClass)
}
if _, ok := elem.(interface {
PostMessage(*Element, *Message) bool
}); ok {
C.setGstElementClassPostMessage(elemClass)
}
if _, ok := elem.(interface {
ProvideClock(*Element) *Clock
}); ok {
C.setGstElementClassProvideClock(elemClass)
}
if _, ok := elem.(interface {
Query(*Element, *Query) bool
}); ok {
C.setGstElementClassQuery(elemClass)
}
if _, ok := elem.(interface {
ReleasePad(*Element, *Pad)
}); ok {
C.setGstElementClassReleasePad(elemClass)
}
if _, ok := elem.(interface {
RequestNewPad(self *Element, templ *PadTemplate, name string, caps *Caps) *Pad
}); ok {
C.setGstElementClassRequestNewPad(elemClass)
}
if _, ok := elem.(interface {
SendEvent(*Element, *Event) bool
}); ok {
C.setGstElementClassSendEvent(elemClass)
}
if _, ok := elem.(interface {
SetBus(*Element, *Bus)
}); ok {
C.setGstElementClassSetBus(elemClass)
}
if _, ok := elem.(interface {
SetClock(*Element, *Clock) bool
}); ok {
C.setGstElementClassSetClock(elemClass)
}
if _, ok := elem.(interface {
SetContext(*Element, *Context)
}); ok {
C.setGstElementClassSetContext(elemClass)
}
if _, ok := elem.(interface {
SetState(*Element, State) StateChangeReturn
}); ok {
C.setGstElementClassSetState(elemClass)
}
if _, ok := elem.(interface {
StateChanged(self *Element, old, new, pending State)
}); ok {
C.setGstElementClassStateChanged(elemClass)
}
}

View File

@@ -72,11 +72,11 @@ func (m *Message) String() string {
case MessageStructureChange:
chgType, elem, busy := m.ParseStructureChange()
msg += fmt.Sprintf("Structure change of type %s from %s. (in progress: %v)", chgType.String(), elem.Name(), busy)
msg += fmt.Sprintf("Structure change of type %s from %s. (in progress: %v)", chgType.String(), elem.GetName(), busy)
case MessageStreamStatus:
statusType, elem := m.ParseStreamStatus()
msg += fmt.Sprintf("Stream status from %s: %s", elem.Name(), statusType.String())
msg += fmt.Sprintf("Stream status from %s: %s", elem.GetName(), statusType.String())
case MessageApplication:
msg += "Message posted by the application, possibly via an application-specific element."
@@ -165,7 +165,7 @@ func (m *Message) String() string {
if obj != nil && propVal != nil {
goval, err := propVal.GoValue()
if err != nil {
msg += fmt.Sprintf("Object %s had property '%s' changed to %+v", obj.Name(), propName, goval)
msg += fmt.Sprintf("Object %s had property '%s' changed to %+v", obj.GetName(), propName, goval)
}
}

View File

@@ -4,6 +4,7 @@ package gst
import "C"
import (
"time"
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
@@ -14,70 +15,36 @@ type Object struct{ *glib.InitiallyUnowned }
// FromGstObjectUnsafe returns an Object wrapping the given pointer. It meant for internal
// usage and exported for visibility to other packages.
func FromGstObjectUnsafe(ptr unsafe.Pointer) *Object {
return wrapObject(toGObject(ptr))
}
// Unsafe returns the unsafe pointer to the underlying object. This method is primarily
// for internal usage and is exposed for visibility in other packages.
func (o *Object) Unsafe() unsafe.Pointer {
if o == nil || o.GObject == nil {
return nil
}
return unsafe.Pointer(o.GObject)
}
func FromGstObjectUnsafe(ptr unsafe.Pointer) *Object { return wrapObject(toGObject(ptr)) }
// Instance returns the native C GstObject.
func (o *Object) Instance() *C.GstObject { return C.toGstObject(o.Unsafe()) }
// BaseObject returns this object for embedding structs.
// BaseObject is a convenience method for retrieving this object from embedded structs.
func (o *Object) BaseObject() *Object { return o }
// GstObject is an alias to Instance on the underlying GstObject of any extending struct.
func (o *Object) GstObject() *C.GstObject { return C.toGstObject(o.Unsafe()) }
// Class returns the GObjectClass of this instance.
func (o *Object) Class() *C.GObjectClass { return C.getGObjectClass(o.Unsafe()) }
// GObject returns the underlying GObject instance.
func (o *Object) GObject() *glib.Object { return o.InitiallyUnowned.Object }
// Name returns the name of this object.
func (o *Object) Name() string {
// GetName returns the name of this object.
func (o *Object) GetName() string {
cName := C.gst_object_get_name((*C.GstObject)(o.Instance()))
defer C.free(unsafe.Pointer(cName))
return C.GoString(cName)
}
// Interfaces returns the interfaces associated with this object.
func (o *Object) Interfaces() []string {
var size C.guint
ifaces := C.g_type_interfaces(C.gsize(o.TypeFromInstance()), &size)
if int(size) == 0 {
// GetValue retrieves the value for the given controlled property at the given timestamp.
func (o *Object) GetValue(property string, timestamp time.Duration) *glib.Value {
cprop := C.CString(property)
defer C.free(unsafe.Pointer(cprop))
gval := C.gst_object_get_value(o.Instance(), (*C.gchar)(cprop), C.GstClockTime(timestamp.Nanoseconds()))
if gval == nil {
return nil
}
defer C.g_free((C.gpointer)(ifaces))
out := make([]string, int(size))
for _, t := range (*[1 << 30]int)(unsafe.Pointer(ifaces))[:size:size] {
out = append(out, glib.Type(t).Name())
}
return out
}
// ListProperties returns a list of the properties associated with this object.
// The default values assumed in the parameter spec reflect the values currently
// set in this object, or their defaults.
//
// Unref after usage.
func (o *Object) ListProperties() []*glib.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([]*glib.ParamSpec, 0)
for _, prop := range (*[1 << 30]*C.GParamSpec)(unsafe.Pointer(props))[:size:size] {
out = append(out, glib.ToParamSpec(unsafe.Pointer(prop)))
}
return out
return glib.ValueFromNative(unsafe.Pointer(gval))
}
// Log logs a message to the given category from this object using the currently registered
@@ -85,3 +52,25 @@ func (o *Object) ListProperties() []*glib.ParamSpec {
func (o *Object) Log(cat *DebugCategory, level DebugLevel, message string) {
cat.logDepth(level, message, 2, (*C.GObject)(o.Unsafe()))
}
// Clear will will clear all references to this object. If the reference is already null
// the the function does nothing. Otherwise the reference count is decreased and the pointer
// set to null.
func (o *Object) Clear() {
if ptr := o.Unsafe(); ptr != nil {
C.gst_clear_object((**C.GstObject)(unsafe.Pointer(&ptr)))
}
}
// Ref increments the reference count on object. This function does not take the lock on object
// because it relies on atomic refcounting. For convenience the same object is returned.
func (o *Object) Ref() *Object {
C.gst_object_ref((C.gpointer)(o.Unsafe()))
return o
}
// Unref decrements the reference count on object. If reference count hits zero, destroy object.
// This function does not take the lock on object as it relies on atomic refcounting.
func (o *Object) Unref() {
C.gst_object_unref((C.gpointer)(o.Unsafe()))
}

View File

@@ -9,8 +9,15 @@ import (
)
// InterfaceTagSetter represents the GstTagsetter interface GType. Use this when querying bins
// for elements that implement a TagSetter.
var InterfaceTagSetter = glib.Type(C.GST_TYPE_TAG_SETTER)
// for elements that implement a TagSetter. Extending this interface is not yet implemented.
var InterfaceTagSetter glib.Interface = &interfaceTagSetter{}
type interfaceTagSetter struct{}
func (i *interfaceTagSetter) Type() glib.Type { return glib.Type(C.GST_TYPE_TAG_SETTER) }
func (i *interfaceTagSetter) InitFunc() glib.InterfaceInitFunc {
return func(instance *glib.TypeInstance) {}
}
// TagSetter is an interface that elements can implement to provide Tag writing capabilities.
type TagSetter interface {

View File

@@ -27,21 +27,18 @@ import (
)
// InterfaceURIHandler represents the GstURIHandler interface GType. Use this when querying bins
// for elements that implement a URIHandler, or when signaling that a GoElement provides this
// interface.
// for elements that implement a URIHandler, or when signaling that a GoObjectSubclass provides this
// interface. Note that the way this interface is implemented, it can only be used once per plugin.
var InterfaceURIHandler glib.Interface = &interfaceURIHandler{}
type interfaceURIHandler struct {
glib.Interface
}
type interfaceURIHandler struct{ glib.Interface }
func (i *interfaceURIHandler) Type() glib.Type {
return glib.Type(C.GST_TYPE_URI_HANDLER)
}
func (i *interfaceURIHandler) InitFunc(t *glib.TypeInstance) unsafe.Pointer {
globalURIHdlr = t.GoType.(URIHandler)
return unsafe.Pointer(C.uriHandlerInit)
func (i *interfaceURIHandler) Type() glib.Type { return glib.Type(C.GST_TYPE_URI_HANDLER) }
func (i *interfaceURIHandler) InitFunc() glib.InterfaceInitFunc {
return func(instance *glib.TypeInstance) {
globalURIHdlr = instance.GoType.(URIHandler)
C.uriHandlerInit((C.gpointer)(instance.GTypeInstance), nil)
}
}
// URIHandler represents an interface that elements can implement to provide URI handling