mirror of
https://github.com/go-gst/go-gst.git
synced 2025-09-26 20:11:18 +08:00
200 lines
5.4 KiB
Go
200 lines
5.4 KiB
Go
package gst
|
|
|
|
/*
|
|
#include "gst.go.h"
|
|
|
|
extern gboolean structForEachCb (GQuark field_id, GValue * value, gpointer user_data);
|
|
|
|
gboolean structureForEach (GQuark field_id, GValue * value, gpointer user_data)
|
|
{
|
|
return structForEachCb(field_id, value, user_data);
|
|
}
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"github.com/go-gst/go-glib/glib"
|
|
gopointer "github.com/mattn/go-pointer"
|
|
)
|
|
|
|
// Structure is a go implementation of a C GstStructure.
|
|
type Structure struct {
|
|
ptr unsafe.Pointer
|
|
gType glib.Type
|
|
}
|
|
|
|
// NewStructure returns a new empty structure with the given name.
|
|
func NewStructure(name string) *Structure {
|
|
cName := C.CString(name)
|
|
defer C.free(unsafe.Pointer(cName))
|
|
structure := C.gst_structure_new_empty(cName)
|
|
return wrapStructure(structure)
|
|
}
|
|
|
|
// NewStructureFromString builds a new GstStructure from the given string.
|
|
func NewStructureFromString(stStr string) *Structure {
|
|
cStr := C.CString(stStr)
|
|
defer C.free(unsafe.Pointer(cStr))
|
|
structure := C.gst_structure_from_string(cStr, nil)
|
|
if structure == nil {
|
|
return nil
|
|
}
|
|
return wrapStructure(structure)
|
|
}
|
|
|
|
// MarshalStructure will convert the given go struct into a GstStructure. Currently nested
|
|
// structs are not supported.
|
|
func MarshalStructure(data interface{}) *Structure {
|
|
typeOf := reflect.TypeOf(data)
|
|
valsOf := reflect.ValueOf(data)
|
|
st := NewStructure(typeOf.Name())
|
|
for i := 0; i < valsOf.NumField(); i++ {
|
|
gval := valsOf.Field(i).Interface()
|
|
fieldName := typeOf.Field(i).Name
|
|
if err := st.SetValue(fieldName, gval); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to set %v for %s", gval, fieldName)
|
|
}
|
|
}
|
|
return st
|
|
}
|
|
|
|
// FromGstStructureUnsafe wraps the given unsafe.Pointer in a Structure. This is meant for internal usage
|
|
// and is exported for visibility to other packages.
|
|
func FromGstStructureUnsafe(st unsafe.Pointer) *Structure {
|
|
return wrapStructure((*C.GstStructure)(st))
|
|
}
|
|
|
|
// UnmarshalInto will unmarshal this structure into the given pointer. The object
|
|
// reflected by the pointer must be non-nil.
|
|
func (s *Structure) UnmarshalInto(data interface{}) error {
|
|
rv := reflect.ValueOf(data)
|
|
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
|
return errors.New("Data is invalid (nil or non-pointer)")
|
|
}
|
|
|
|
val := reflect.ValueOf(data).Elem()
|
|
nVal := rv.Elem()
|
|
for i := 0; i < val.NumField(); i++ {
|
|
nvField := nVal.Field(i)
|
|
fieldName := val.Type().Field(i).Name
|
|
val, err := s.GetValue(fieldName)
|
|
if err == nil {
|
|
nvField.Set(reflect.ValueOf(val))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Instance returns the native GstStructure instance.
|
|
func (s *Structure) Instance() *C.GstStructure { return C.toGstStructure(s.ptr) }
|
|
|
|
// Free frees the memory for the underlying GstStructure.
|
|
func (s *Structure) Free() { C.gst_structure_free(s.Instance()) }
|
|
|
|
// String implement a stringer on a GstStructure.
|
|
func (s *Structure) String() string {
|
|
str := C.gst_structure_to_string(s.Instance())
|
|
defer C.g_free((C.gpointer)(str))
|
|
return C.GoString(str)
|
|
}
|
|
|
|
// Name returns the name of this structure.
|
|
func (s *Structure) Name() string {
|
|
return C.GoString(C.gst_structure_get_name(s.Instance()))
|
|
}
|
|
|
|
// Size returns the number of fields inside this structure.
|
|
func (s *Structure) Size() int {
|
|
return int(C.gst_structure_n_fields(s.Instance()))
|
|
}
|
|
|
|
// SetValue sets the data at key to the given value.
|
|
func (s *Structure) SetValue(key string, value interface{}) error {
|
|
gVal, err := glib.GValue(value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cKey := C.CString(key)
|
|
defer C.free(unsafe.Pointer(cKey))
|
|
C.gst_structure_set_value(s.Instance(), cKey, (*C.GValue)(unsafe.Pointer(gVal.GValue)))
|
|
return nil
|
|
}
|
|
|
|
// GetValue retrieves the value at key.
|
|
func (s *Structure) GetValue(key string) (interface{}, error) {
|
|
cKey := C.CString(key)
|
|
defer C.free(unsafe.Pointer(cKey))
|
|
gVal := C.gst_structure_get_value(s.Instance(), cKey)
|
|
if gVal == nil {
|
|
return nil, fmt.Errorf("No value exists at %s", key)
|
|
}
|
|
return glib.ValueFromNative(unsafe.Pointer(gVal)).GoValue()
|
|
}
|
|
|
|
// RemoveValue removes the value at the given key. If the key does not exist,
|
|
// the structure is unchanged.
|
|
func (s *Structure) RemoveValue(key string) {
|
|
cKey := C.CString(key)
|
|
defer C.free(unsafe.Pointer(cKey))
|
|
C.gst_structure_remove_field(s.Instance(), cKey)
|
|
}
|
|
|
|
// Values returns a map of all the values inside this structure. If values cannot be
|
|
// converted to an equivalent go type, they are serialized to a string.
|
|
func (s *Structure) Values() map[string]interface{} {
|
|
out := make(map[string]interface{})
|
|
resCh := make(chan interface{})
|
|
chPtr := gopointer.Save(resCh)
|
|
defer gopointer.Unref(chPtr)
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := 0; i < s.Size(); i++ {
|
|
nameIface := <-resCh
|
|
valIface := <-resCh
|
|
fieldName := nameIface.(string)
|
|
out[fieldName] = valIface
|
|
}
|
|
}()
|
|
|
|
C.gst_structure_foreach(s.Instance(), C.GstStructureForeachFunc(C.structureForEach), (C.gpointer)(unsafe.Pointer(chPtr)))
|
|
wg.Wait()
|
|
|
|
return out
|
|
}
|
|
|
|
// TypeStructure is the glib.Type for a Structure.
|
|
var TypeStructure = glib.Type(C.gst_structure_get_type())
|
|
|
|
var _ glib.ValueTransformer = &Structure{}
|
|
|
|
// ToGValue implements a glib.ValueTransformer
|
|
func (s *Structure) ToGValue() (*glib.Value, error) {
|
|
val, err := glib.ValueInit(TypeStructure)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
C.gst_value_set_structure(
|
|
(*C.GValue)(unsafe.Pointer(val.GValue)),
|
|
s.Instance(),
|
|
)
|
|
return val, nil
|
|
}
|
|
|
|
func wrapStructure(st *C.GstStructure) *Structure {
|
|
return &Structure{
|
|
ptr: unsafe.Pointer(st),
|
|
gType: glib.Type(st._type),
|
|
}
|
|
}
|