major cleanup

This commit is contained in:
Avi Zimmerman
2021-01-08 16:06:52 +02:00
parent cbf6279abc
commit ca1cdb00e7
54 changed files with 720 additions and 305 deletions

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@ _bin/
.devcontainer/ .devcontainer/
_rust/ _rust/
*.DS_Store* *.DS_Store*
*.supp

View File

@@ -8,7 +8,7 @@
// functionality to implement these plugins. The example in this code produces an element // functionality to implement these plugins. The example in this code produces an element
// that can read from a file on the local system. // that can read from a file on the local system.
// //
// In order to build the plugin for use by GStreamer, you may do the following: // In order to build the plugin for use by GStreamer, you can do the following:
// //
// $ go build -o libgstgofilesrc.so -buildmode c-shared . // $ go build -o libgstgofilesrc.so -buildmode c-shared .
// //
@@ -21,14 +21,15 @@ import (
"io" "io"
"os" "os"
"strings" "strings"
"syscall"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst" "github.com/tinyzimmer/go-gst/gst"
"github.com/tinyzimmer/go-gst/gst/base" "github.com/tinyzimmer/go-gst/gst/base"
) )
// CAT is the log category for the gofilesrc // CAT is the log category for the gofilesrc. It is safe to define GStreamer objects as globals
// without calling gst.Init, since in the context of a loaded plugin all initialization has
// already been taken care of by the loading application.
var CAT = gst.NewDebugCategory( var CAT = gst.NewDebugCategory(
"gofilesrc", "gofilesrc",
gst.DebugColorNone, gst.DebugColorNone,
@@ -77,6 +78,11 @@ type fileSrc struct {
state *state state *state
} }
func (f *fileSrc) PostMessage(self *gst.Element, msg *gst.Message) bool {
fmt.Println("Received message on the pipeline", msg)
return self.ParentPostMessage(msg)
}
// Private methods only used internally by the plugin // Private methods only used internally by the plugin
// setLocation is a simple method to check the validity of a provided file path and set the // setLocation is a simple method to check the validity of a provided file path and set the
@@ -97,7 +103,7 @@ func (f *fileSrc) setLocation(path string) error {
// gst.GoElement implementation. Here we simply create a new fileSrc with zeroed settings // gst.GoElement implementation. Here we simply create a new fileSrc with zeroed settings
// and state objects. // and state objects.
func (f *fileSrc) New() gst.GoElement { func (f *fileSrc) New() gst.GoElement {
CAT.Log(gst.LevelDebug, "Initializing new fileSrc object") CAT.Log(gst.LevelLog, "Initializing new fileSrc object")
return &fileSrc{ return &fileSrc{
settings: &settings{}, settings: &settings{},
state: &state{}, state: &state{},
@@ -107,29 +113,27 @@ func (f *fileSrc) New() gst.GoElement {
// The TypeInit method should register any additional interfaces provided by the element. // 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. // In this example we signal to the type system that we also implement the GstURIHandler interface.
func (f *fileSrc) TypeInit(instance *gst.TypeInstance) { func (f *fileSrc) TypeInit(instance *gst.TypeInstance) {
CAT.Log(gst.LevelDebug, "Adding URIHandler interface to type") CAT.Log(gst.LevelLog, "Adding URIHandler interface to type")
instance.AddInterface(gst.InterfaceURIHandler) instance.AddInterface(gst.InterfaceURIHandler)
} }
// The ClassInit method should specify the metadata for this element and add any pad templates // The ClassInit method should specify the metadata for this element and add any pad templates
// and properties. // and properties.
func (f *fileSrc) ClassInit(klass *gst.ElementClass) { func (f *fileSrc) ClassInit(klass *gst.ElementClass) {
CAT.Log(gst.LevelDebug, "Initializing gofilesrc class") CAT.Log(gst.LevelLog, "Initializing gofilesrc class")
klass.SetMetadata( klass.SetMetadata(
"File Source", "File Source",
"Source/File", "Source/File",
"Read stream from a file", "Read stream from a file",
"Avi Zimmerman <avi.zimmerman@gmail.com>", "Avi Zimmerman <avi.zimmerman@gmail.com>",
) )
caps := gst.NewAnyCaps() CAT.Log(gst.LevelLog, "Adding src pad template and properties to class")
srcPadTemplate := gst.NewPadTemplate( klass.AddPadTemplate(gst.NewPadTemplate(
"src", "src",
gst.PadDirectionSource, gst.PadDirectionSource,
gst.PadPresenceAlways, gst.PadPresenceAlways,
caps, gst.NewAnyCaps(),
) ))
CAT.Log(gst.LevelDebug, "Adding src pad template and properties to class")
klass.AddPadTemplate(srcPadTemplate)
klass.InstallProperties(properties) klass.InstallProperties(properties)
} }
@@ -189,7 +193,7 @@ func (f *fileSrc) GetProperty(self *gst.Object, id uint) *glib.Value {
// during the initialization process can be performed here. In this example, we set the format on our // during the initialization process can be performed here. In this example, we set the format on our
// underlying GstBaseSrc to bytes. // underlying GstBaseSrc to bytes.
func (f *fileSrc) Constructed(self *gst.Object) { func (f *fileSrc) Constructed(self *gst.Object) {
self.Log(CAT, gst.LevelDebug, "Setting format of GstBaseSrc to bytes") self.Log(CAT, gst.LevelLog, "Setting format of GstBaseSrc to bytes")
base.ToGstBaseSrc(self).SetFormat(gst.FormatBytes) base.ToGstBaseSrc(self).SetFormat(gst.FormatBytes)
} }
@@ -211,7 +215,7 @@ func (f *fileSrc) GetSize(self *base.GstBaseSrc) (bool, int64) {
// and any error encountered in the process is posted to the pipeline. // and any error encountered in the process is posted to the pipeline.
func (f *fileSrc) Start(self *base.GstBaseSrc) bool { func (f *fileSrc) Start(self *base.GstBaseSrc) bool {
if f.state.started { if f.state.started {
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorSettings, "FileSrc is already started", "") self.ErrorMessage(gst.DomainResource, gst.ResourceErrorSettings, "GoFileSrc is already started", "")
return false return false
} }
@@ -240,7 +244,7 @@ func (f *fileSrc) Start(self *base.GstBaseSrc) bool {
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("file stat - name: %s size: %d mode: %v modtime: %v", stat.Name(), stat.Size(), stat.Mode(), stat.ModTime())) self.Log(CAT, gst.LevelDebug, fmt.Sprintf("file stat - name: %s size: %d mode: %v modtime: %v", stat.Name(), stat.Size(), stat.Mode(), stat.ModTime()))
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Opening file %s for reading", f.settings.location)) self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Opening file %s for reading", f.settings.location))
f.state.file, err = os.OpenFile(f.settings.location, syscall.O_RDONLY, 0444) f.state.file, err = os.Open(f.settings.location)
if err != nil { if err != nil {
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorOpenRead, self.ErrorMessage(gst.DomainResource, gst.ResourceErrorOpenRead,
fmt.Sprintf("Could not open file %s for reading", f.settings.location), err.Error()) fmt.Sprintf("Could not open file %s for reading", f.settings.location), err.Error())
@@ -285,7 +289,7 @@ func (f *fileSrc) Fill(self *base.GstBaseSrc, offset uint64, size uint, buffer *
return gst.FlowError return gst.FlowError
} }
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Request to fill buffer from offset %v with size %v", offset, size)) self.Log(CAT, gst.LevelLog, fmt.Sprintf("Request to fill buffer from offset %v with size %v", offset, size))
if f.state.position != offset { if f.state.position != offset {
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Seeking to new position at offset %v from previous position at offset %v", offset, f.state.position)) self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Seeking to new position at offset %v from previous position at offset %v", offset, f.state.position))
@@ -297,18 +301,6 @@ func (f *fileSrc) Fill(self *base.GstBaseSrc, offset uint64, size uint, buffer *
f.state.position = offset f.state.position = offset
} }
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Reading %v bytes from file at offset %v", size, f.state.position))
out := make([]byte, int(size))
if _, err := f.state.file.Read(out); err != nil && err != io.EOF {
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorRead,
fmt.Sprintf("Failed to read %d bytes from file at %d", size, offset), err.Error())
return gst.FlowError
}
f.state.position = f.state.position + uint64(size)
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Incremented current position to %v", f.state.position))
self.Log(CAT, gst.LevelDebug, fmt.Sprintf("Writing data from file to buffer"))
bufmap := buffer.Map(gst.MapWrite) bufmap := buffer.Map(gst.MapWrite)
if bufmap == nil { if bufmap == nil {
self.ErrorMessage(gst.DomainLibrary, gst.LibraryErrorFailed, "Failed to map buffer", "") self.ErrorMessage(gst.DomainLibrary, gst.LibraryErrorFailed, "Failed to map buffer", "")
@@ -316,9 +308,17 @@ func (f *fileSrc) Fill(self *base.GstBaseSrc, offset uint64, size uint, buffer *
} }
defer buffer.Unmap() defer buffer.Unmap()
bufmap.WriteData(out) self.Log(CAT, gst.LevelLog, fmt.Sprintf("Reading %v bytes from offset %v in file into buffer at %v", size, f.state.position, bufmap.Data()))
if _, err := io.CopyN(bufmap.Writer(), f.state.file, int64(size)); err != nil {
self.ErrorMessage(gst.DomainResource, gst.ResourceErrorRead,
fmt.Sprintf("Failed to read %d bytes from file at %d into buffer", size, offset), err.Error())
return gst.FlowError
}
buffer.SetSize(int64(size)) buffer.SetSize(int64(size))
f.state.position = f.state.position + uint64(size)
self.Log(CAT, gst.LevelLog, fmt.Sprintf("Incremented current position to %v", f.state.position))
return gst.FlowOK return gst.FlowOK
} }

2
go.mod
View File

@@ -3,6 +3,6 @@ module github.com/tinyzimmer/go-gst
go 1.15 go 1.15
require ( require (
github.com/gotk3/gotk3 v0.4.0
github.com/mattn/go-pointer v0.0.1 github.com/mattn/go-pointer v0.0.1
github.com/tinyzimmer/go-glib v0.0.2
) )

7
go.sum
View File

@@ -1,5 +1,6 @@
github.com/gotk3/gotk3 v0.4.0 h1:TIuhyQitGeRTxOQIV3AJlYtEWWJpC74JHwAIsxlH8MU=
github.com/gotk3/gotk3 v0.4.0/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo=
github.com/gotk3/gotk3 v0.5.2 h1:jbSFvUNMfo3ImM6BWBAkNUxY5piqP3eTc1YFbYy9ecU=
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= 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/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
github.com/tinyzimmer/go-glib v0.0.1 h1:pfsr7EbP23/cZPGlEpsmwtQXjdzYj0S+WhUgOALdsQI=
github.com/tinyzimmer/go-glib v0.0.1/go.mod h1:D5rd0CvYn1p7TBhwlwnBXHSr4d8lwEY9JImPQ66S+Bs=
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=

View File

@@ -87,11 +87,13 @@ func (a *Source) GetCurrentLevelBytes() uint64 {
return uint64(C.gst_app_src_get_current_level_bytes(a.Instance())) return uint64(C.gst_app_src_get_current_level_bytes(a.Instance()))
} }
var gstClockTimeNone C.GstClockTime = 0xffffffffffffffff
// GetDuration gets the duration of the stream in nanoseconds. A negative value means that the duration is not known. // GetDuration gets the duration of the stream in nanoseconds. A negative value means that the duration is not known.
func (a *Source) GetDuration() time.Duration { func (a *Source) GetDuration() time.Duration {
dur := C.gst_app_src_get_duration(a.Instance()) dur := C.gst_app_src_get_duration(a.Instance())
if gst.ClockTime(dur) == gst.ClockTimeNone { if dur == gstClockTimeNone {
return time.Duration(-1) return gst.ClockTimeNone
} }
return time.Duration(uint64(dur)) * time.Nanosecond return time.Duration(uint64(dur)) * time.Nanosecond
} }

View File

@@ -50,7 +50,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst" "github.com/tinyzimmer/go-gst/gst"
) )

View File

@@ -8,7 +8,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
func toGObject(data unsafe.Pointer) *glib.Object { func toGObject(data unsafe.Pointer) *glib.Object {
@@ -99,7 +99,7 @@ func streamSliceToGlist(streams []*Stream) *C.GList {
for _, stream := range streams { for _, stream := range streams {
wrapped = wrapped.Append(uintptr(stream.Unsafe())) wrapped = wrapped.Append(uintptr(stream.Unsafe()))
} }
return (*C.GList)(unsafe.Pointer(wrapped.Native())) return &glist
} }
func glistToStreamSlice(glist *C.GList) []*Stream { func glistToStreamSlice(glist *C.GList) []*Stream {

View File

@@ -10,10 +10,11 @@ import "C"
import ( import (
"reflect" "reflect"
"time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
) )
//export goElementCallAsync //export goElementCallAsync
@@ -223,7 +224,7 @@ func goClockCb(gclock *C.GstClock, clockTime C.GstClockTime, clockID C.GstClockI
} }
clock := wrapClock(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gclock))}) clock := wrapClock(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gclock))})
return gboolean(cb(clock, ClockTime(clockTime))) return gboolean(cb(clock, time.Duration(clockTime)))
} }
//export goPluginInit //export goPluginInit

View File

@@ -3,7 +3,10 @@ package gst
// #include "gst.go.h" // #include "gst.go.h"
import "C" import "C"
import "unsafe" import (
"time"
"unsafe"
)
// Version represents information about the current GST version. // Version represents information about the current GST version.
type Version int type Version int
@@ -47,20 +50,20 @@ func (g GFraction) Num() int { return g.num }
// Denom returns the fraction's denominator. // Denom returns the fraction's denominator.
func (g GFraction) Denom() int { return g.denom } func (g GFraction) Denom() int { return g.denom }
// ClockTime is a go representation of a GstClockTime. Most of the time these are casted
// to time.Duration objects. It represents a time value in nanoseconds.
type ClockTime uint64
// ClockTimeDiff is a datatype to hold a time difference, measured in nanoseconds. // ClockTimeDiff is a datatype to hold a time difference, measured in nanoseconds.
type ClockTimeDiff int64 type ClockTimeDiff int64
const ( // ClockTimeNone means infinite timeout or an empty value
// ClockFormat is the string used when formatting clock strings var ClockTimeNone time.Duration = time.Duration(-1)
ClockFormat string = "u:%02u:%02u.%09u"
// BufferOffsetNone is a var for no-offset return results.
var BufferOffsetNone time.Duration = time.Duration(-1)
var (
// ClockTimeNone means infinite timeout (unsigned representation of -1) or an otherwise unknown value. // ClockTimeNone means infinite timeout (unsigned representation of -1) or an otherwise unknown value.
ClockTimeNone ClockTime = 0xffffffffffffffff gstClockTimeNone C.GstClockTime = 0xffffffffffffffff
// BufferOffsetNone is a constant for no-offset return results. // // BufferOffsetNone is a constant for no-offset return results.
BufferOffsetNone ClockTime = 0xffffffffffffffff // gstBufferOffsetNone C.GstClockTime = 0xffffffffffffffff
) )
// ClockEntryType wraps GstClockEntryType // ClockEntryType wraps GstClockEntryType
@@ -562,6 +565,32 @@ const (
SeekTypeEnd SeekType = C.GST_SEEK_TYPE_END SeekTypeEnd SeekType = C.GST_SEEK_TYPE_END
) )
// StateChange is the different state changes an element goes through. StateNull ⇒ StatePlaying is called
// an upwards state change and StatePlaying ⇒ StateNull a downwards state change.
//
// See https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c#GstStateChange
// for more information on the responsibiltiies of elements during each transition.
type StateChange int
// StateChange castings
const (
StateChangeNullToReady StateChange = C.GST_STATE_CHANGE_NULL_TO_READY
StateChangeReadyToPaused StateChange = C.GST_STATE_CHANGE_READY_TO_PAUSED
StateChangePausedToPlaying StateChange = C.GST_STATE_CHANGE_PAUSED_TO_PLAYING
StateChangePlayingToPaused StateChange = C.GST_STATE_CHANGE_PLAYING_TO_PAUSED
StateChangePausedToReady StateChange = C.GST_STATE_CHANGE_PAUSED_TO_READY
StateChangeReadyToNull StateChange = C.GST_STATE_CHANGE_READY_TO_NULL
StateChangeNullToNull StateChange = C.GST_STATE_CHANGE_NULL_TO_NULL
StateChangeReadyToReady StateChange = C.GST_STATE_CHANGE_READY_TO_READY
StateChangePausedToPaused StateChange = C.GST_STATE_CHANGE_PAUSED_TO_PAUSED
StateChangePlayingToPlaying StateChange = C.GST_STATE_CHANGE_PLAYING_TO_PLAYING
)
// String returns the string representation of a StateChange
func (s StateChange) String() string {
return C.GoString(C.gst_state_change_get_name(C.GstStateChange(s)))
}
// StateChangeReturn is a representation of GstStateChangeReturn. // StateChangeReturn is a representation of GstStateChangeReturn.
type StateChangeReturn int type StateChangeReturn int
@@ -573,6 +602,10 @@ const (
StateChangeNoPreroll StateChangeReturn = C.GST_STATE_CHANGE_NO_PREROLL StateChangeNoPreroll StateChangeReturn = C.GST_STATE_CHANGE_NO_PREROLL
) )
func (s StateChangeReturn) String() string {
return C.GoString(C.gst_element_state_change_return_get_name(C.GstStateChangeReturn(s)))
}
// ElementFlags casts C GstElementFlags to a go type // ElementFlags casts C GstElementFlags to a go type
type ElementFlags int type ElementFlags int

View File

@@ -32,10 +32,10 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// GoObject is an interface that abstracts on the GObject. In most cases at least SetProperty and GetProperty // GoObject is an interface that abstracts on the GObject. In almost all cases at least SetProperty and GetProperty
// should be implemented by elements built from the go bindings. // should be implemented by elements built from the go bindings.
type GoObject interface { type GoObject interface {
// SetProperty should set the value of the property with the given id. ID is the index+1 of the parameter // SetProperty should set the value of the property with the given id. ID is the index+1 of the parameter
@@ -48,7 +48,8 @@ type GoObject interface {
Constructed(*Object) Constructed(*Object)
} }
// ExtendsObject signifies a GoElement that extends a GObject. // ExtendsObject signifies a GoElement that extends a GObject. It is the base Extendable
// that all other implementations derive from.
var ExtendsObject Extendable = &extendObject{} var ExtendsObject Extendable = &extendObject{}
type extendObject struct{} type extendObject struct{}

View File

@@ -22,7 +22,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// ObjectClass is a loose binding around the glib GObjectClass. // ObjectClass is a loose binding around the glib GObjectClass.

View File

@@ -7,7 +7,7 @@ import (
"strings" "strings"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// ParameterSpec is a go representation of a C GParamSpec // ParameterSpec is a go representation of a C GParamSpec

View File

@@ -6,7 +6,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// AllocationParams wraps the GstAllocationParams. // AllocationParams wraps the GstAllocationParams.

View File

@@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Bin is a go wrapper arounds a GstBin. // Bin is a go wrapper arounds a GstBin.

View File

@@ -26,8 +26,8 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
) )
// GetMaxBufferMemory returns the maximum amount of memory a buffer can hold. // GetMaxBufferMemory returns the maximum amount of memory a buffer can hold.
@@ -161,42 +161,42 @@ func (b *Buffer) Bytes() []byte {
// presented to the user. // presented to the user.
func (b *Buffer) PresentationTimestamp() time.Duration { func (b *Buffer) PresentationTimestamp() time.Duration {
pts := b.Instance().pts pts := b.Instance().pts
if ClockTime(pts) == ClockTimeNone { if pts == gstClockTimeNone {
return time.Duration(-1) return ClockTimeNone
} }
return guint64ToDuration(pts) return time.Duration(pts)
} }
// SetPresentationTimestamp sets the presentation timestamp on the buffer. // SetPresentationTimestamp sets the presentation timestamp on the buffer.
func (b *Buffer) SetPresentationTimestamp(dur time.Duration) { func (b *Buffer) SetPresentationTimestamp(dur time.Duration) {
ins := b.Instance() ins := b.Instance()
ins.pts = C.GstClockTime(durationToClockTime(dur)) ins.pts = C.GstClockTime(dur.Nanoseconds())
} }
// DecodingTimestamp returns the decoding timestamp of the buffer, or a negative duration if not known // DecodingTimestamp returns the decoding timestamp of the buffer, or a negative duration if not known
// or relevant. This value contains the timestamp when the media should be processed. // or relevant. This value contains the timestamp when the media should be processed.
func (b *Buffer) DecodingTimestamp() time.Duration { func (b *Buffer) DecodingTimestamp() time.Duration {
dts := b.Instance().dts dts := b.Instance().dts
if ClockTime(dts) == ClockTimeNone { if dts == gstClockTimeNone {
return time.Duration(-1) return ClockTimeNone
} }
return guint64ToDuration(dts) return time.Duration(dts)
} }
// Duration returns the length of the data inside this buffer, or a negative duration if not known // Duration returns the length of the data inside this buffer, or a negative duration if not known
// or relevant. // or relevant.
func (b *Buffer) Duration() time.Duration { func (b *Buffer) Duration() time.Duration {
dur := b.Instance().duration dur := b.Instance().duration
if ClockTime(dur) == ClockTimeNone { if dur == gstClockTimeNone {
return time.Duration(-1) return ClockTimeNone
} }
return guint64ToDuration(dur) return time.Duration(dur)
} }
// SetDuration sets the duration on the buffer. // SetDuration sets the duration on the buffer.
func (b *Buffer) SetDuration(dur time.Duration) { func (b *Buffer) SetDuration(dur time.Duration) {
ins := b.Instance() ins := b.Instance()
ins.duration = C.GstClockTime(durationToClockTime(dur)) ins.duration = C.GstClockTime(dur.Nanoseconds())
} }
// Offset returns a media specific offset for the buffer data. For video frames, this is the frame // Offset returns a media specific offset for the buffer data. For video frames, this is the frame
@@ -292,8 +292,8 @@ func (b *Buffer) AddReferenceTimestampMeta(ref *Caps, timestamp, duration time.D
return &ReferenceTimestampMeta{ return &ReferenceTimestampMeta{
Parent: wrapMeta(&meta.parent), Parent: wrapMeta(&meta.parent),
Reference: wrapCaps(meta.reference), Reference: wrapCaps(meta.reference),
Timestamp: clockTimeToDuration(ClockTime(meta.timestamp)), Timestamp: time.Duration(meta.timestamp),
Duration: clockTimeToDuration(ClockTime(meta.duration)), Duration: time.Duration(meta.duration),
} }
} }
@@ -472,8 +472,8 @@ func (b *Buffer) GetReferenceTimestampMeta(caps *Caps) *ReferenceTimestampMeta {
return &ReferenceTimestampMeta{ return &ReferenceTimestampMeta{
Parent: wrapMeta(&meta.parent), Parent: wrapMeta(&meta.parent),
Reference: wrapCaps(meta.reference), Reference: wrapCaps(meta.reference),
Timestamp: clockTimeToDuration(ClockTime(meta.timestamp)), Timestamp: time.Duration(meta.timestamp),
Duration: clockTimeToDuration(ClockTime(meta.duration)), Duration: time.Duration(meta.duration),
} }
} }

View File

@@ -7,7 +7,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// BufferPool is a go wrapper around a GstBufferPool. // BufferPool is a go wrapper around a GstBufferPool.

View File

@@ -28,8 +28,8 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
) )
// Bus is a Go wrapper around a GstBus. It provides convenience methods for // Bus is a Go wrapper around a GstBus. It provides convenience methods for
@@ -283,7 +283,7 @@ func (b *Bus) Peek() *Message {
// For 0 timeouts use gst_bus_pop_filtered instead of this function; for other short timeouts use TimedPopFiltered; // For 0 timeouts use gst_bus_pop_filtered instead of this function; for other short timeouts use TimedPopFiltered;
// everything else is better handled by setting up an asynchronous bus watch and doing things from there. // everything else is better handled by setting up an asynchronous bus watch and doing things from there.
func (b *Bus) Poll(msgTypes MessageType, timeout time.Duration) *Message { func (b *Bus) Poll(msgTypes MessageType, timeout time.Duration) *Message {
cTime := C.GstClockTime(durationToClockTime(timeout)) cTime := C.GstClockTime(timeout.Nanoseconds())
mType := C.GstMessageType(msgTypes) mType := C.GstMessageType(msgTypes)
msg := C.gst_bus_poll(b.Instance(), mType, cTime) msg := C.gst_bus_poll(b.Instance(), mType, cTime)
if msg == nil { if msg == nil {
@@ -364,10 +364,10 @@ func (b *Bus) SetSyncHandler(f BusSyncHandler) {
// If timeout is 0, this function behaves like Pop. If timeout is < 0, this function will block forever until a message was posted on the bus. // If timeout is 0, this function behaves like Pop. If timeout is < 0, this function will block forever until a message was posted on the bus.
func (b *Bus) TimedPop(dur time.Duration) *Message { func (b *Bus) TimedPop(dur time.Duration) *Message {
var cTime C.GstClockTime var cTime C.GstClockTime
if dur.Nanoseconds() < 0 { if dur == ClockTimeNone {
cTime = C.GstClockTime(ClockTimeNone) cTime = C.GstClockTime(gstClockTimeNone)
} else { } else {
cTime = C.GstClockTime(durationToClockTime(dur)) cTime = C.GstClockTime(dur.Nanoseconds())
} }
msg := C.gst_bus_timed_pop(b.Instance(), cTime) msg := C.gst_bus_timed_pop(b.Instance(), cTime)
if msg == nil { if msg == nil {
@@ -383,10 +383,10 @@ func (b *Bus) TimedPop(dur time.Duration) *Message {
// was posted on the bus. // was posted on the bus.
func (b *Bus) TimedPopFiltered(dur time.Duration, msgTypes MessageType) *Message { func (b *Bus) TimedPopFiltered(dur time.Duration, msgTypes MessageType) *Message {
var cTime C.GstClockTime var cTime C.GstClockTime
if dur.Nanoseconds() < 0 { if dur == ClockTimeNone {
cTime = C.GstClockTime(ClockTimeNone) cTime = C.GstClockTime(gstClockTimeNone)
} else { } else {
cTime = C.GstClockTime(durationToClockTime(dur)) cTime = C.GstClockTime(dur.Nanoseconds())
} }
msg := C.gst_bus_timed_pop_filtered(b.Instance(), cTime, C.GstMessageType(msgTypes)) msg := C.gst_bus_timed_pop_filtered(b.Instance(), cTime, C.GstMessageType(msgTypes))
if msg == nil { if msg == nil {

View File

@@ -17,8 +17,8 @@ import (
"fmt" "fmt"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
) )
// Caps is a go wrapper around GstCaps. // Caps is a go wrapper around GstCaps.
@@ -406,7 +406,7 @@ func (c *Caps) SetValue(field string, val interface{}) {
C.gst_caps_set_value( C.gst_caps_set_value(
c.Instance(), c.Instance(),
(*C.gchar)(unsafe.Pointer(C.CString(field))), (*C.gchar)(unsafe.Pointer(C.CString(field))),
(*C.GValue)(gVal.Native()), (*C.GValue)(unsafe.Pointer(gVal.GValue)),
) )
} }

View File

@@ -23,12 +23,12 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
) )
// ClockCallback is the prototype of a clock callback function. // ClockCallback is the prototype of a clock callback function.
type ClockCallback func(clock *Clock, clockTime ClockTime) bool type ClockCallback func(clock *Clock, clockTime time.Duration) bool
// ClockID is a go wrapper around a GstClockID. // ClockID is a go wrapper around a GstClockID.
type ClockID struct { type ClockID struct {
@@ -45,8 +45,8 @@ func (c *ClockID) GetClock() *Clock {
} }
// GetTime returns the time for this ClockID // GetTime returns the time for this ClockID
func (c *ClockID) GetTime() ClockTime { func (c *ClockID) GetTime() time.Duration {
return ClockTime(C.gst_clock_id_get_time(c.Instance())) return time.Duration(C.gst_clock_id_get_time(c.Instance()))
} }
// Unschedule cancels an outstanding request with id. This can either be an outstanding async notification or a pending sync notification. // Unschedule cancels an outstanding request with id. This can either be an outstanding async notification or a pending sync notification.
@@ -88,8 +88,8 @@ func (c *ClockID) Wait() (ret ClockReturn, jitter ClockTimeDiff) {
// //
// id := clock.NewSingleShotID(gst.ClockTime(1000000000)) // 1 second // id := clock.NewSingleShotID(gst.ClockTime(1000000000)) // 1 second
// //
// id.WaitAsync(func(clock *gst.Clock, clockTime gst.ClockTime) bool { // id.WaitAsync(func(clock *gst.Clock, clockTime time.Duration) bool {
// fmt.Println("Single shot triggered at", clockTime) // fmt.Println("Single shot triggered at", clockTime.Nanoseconds())
// pipeline.SetState(gst.StateNull) // pipeline.SetState(gst.StateNull)
// return true // return true
// }) // })
@@ -130,7 +130,7 @@ func (c *Clock) Instance() *C.GstClock { return C.toGstClock(c.Unsafe()) }
// //
// If this functions returns TRUE, the float will contain the correlation coefficient of the interpolation. A value of 1.0 means // If this functions returns TRUE, the float will contain the correlation coefficient of the interpolation. A value of 1.0 means
// a perfect regression was performed. This value can be used to control the sampling frequency of the master and slave clocks. // a perfect regression was performed. This value can be used to control the sampling frequency of the master and slave clocks.
func (c *Clock) AddObservation(slaveTime, masterTime ClockTime) (bool, float64) { func (c *Clock) AddObservation(slaveTime, masterTime time.Duration) (bool, float64) {
var out C.gdouble var out C.gdouble
ok := gobool(C.gst_clock_add_observation( ok := gobool(C.gst_clock_add_observation(
c.Instance(), c.Instance(),
@@ -145,7 +145,7 @@ func (c *Clock) AddObservation(slaveTime, masterTime ClockTime) (bool, float64)
// result of the master clock estimation, without updating the internal calibration. // result of the master clock estimation, without updating the internal calibration.
// //
// The caller can then take the results and call SetCalibration with the values, or some modified version of them. // The caller can then take the results and call SetCalibration with the values, or some modified version of them.
func (c *Clock) AddObservationUnapplied(slaveTime, masterTime ClockTime) (ok bool, rSquared float64, internalTime, externalTime, rateNum, rateDenom ClockTime) { func (c *Clock) AddObservationUnapplied(slaveTime, masterTime time.Duration) (ok bool, rSquared float64, internalTime, externalTime, rateNum, rateDenom time.Duration) {
var ginternal, gexternal, grateNum, grateDenom C.GstClockTime var ginternal, gexternal, grateNum, grateDenom C.GstClockTime
var grSquared C.gdouble var grSquared C.gdouble
ok = gobool(C.gst_clock_add_observation_unapplied( ok = gobool(C.gst_clock_add_observation_unapplied(
@@ -154,7 +154,7 @@ func (c *Clock) AddObservationUnapplied(slaveTime, masterTime ClockTime) (ok boo
C.GstClockTime(masterTime), C.GstClockTime(masterTime),
&grSquared, &ginternal, &gexternal, &grateNum, &grateDenom, &grSquared, &ginternal, &gexternal, &grateNum, &grateDenom,
)) ))
return ok, float64(grSquared), ClockTime(ginternal), ClockTime(gexternal), ClockTime(grateNum), ClockTime(grateDenom) return ok, float64(grSquared), time.Duration(ginternal), time.Duration(gexternal), time.Duration(grateNum), time.Duration(grateDenom)
} }
// AdjustUnlocked converts the given internal clock time to the external time, adjusting for the rate and reference time set with // AdjustUnlocked converts the given internal clock time to the external time, adjusting for the rate and reference time set with
@@ -162,8 +162,8 @@ func (c *Clock) AddObservationUnapplied(slaveTime, masterTime ClockTime) (ok boo
// held and is mainly used by clock subclasses. // held and is mainly used by clock subclasses.
// //
// This function is the reverse of UnadjustUnlocked. // This function is the reverse of UnadjustUnlocked.
func (c *Clock) AdjustUnlocked(internal ClockTime) ClockTime { func (c *Clock) AdjustUnlocked(internal time.Duration) time.Duration {
return ClockTime(C.gst_clock_adjust_unlocked(c.Instance(), C.GstClockTime(internal))) return time.Duration(C.gst_clock_adjust_unlocked(c.Instance(), C.GstClockTime(internal)))
} }
// AdjustWithCalibration converts the given internal_target clock time to the external time, using the passed calibration parameters. // AdjustWithCalibration converts the given internal_target clock time to the external time, using the passed calibration parameters.
@@ -171,8 +171,8 @@ func (c *Clock) AdjustUnlocked(internal ClockTime) ClockTime {
// doesn't ensure a monotonically increasing result as AdjustUnlocked does. // doesn't ensure a monotonically increasing result as AdjustUnlocked does.
// //
// See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstclock.html#gst_clock_adjust_with_calibration // See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstclock.html#gst_clock_adjust_with_calibration
func (c *Clock) AdjustWithCalibration(internalTarget, cinternal, cexternal, cnum, cdenom ClockTime) ClockTime { func (c *Clock) AdjustWithCalibration(internalTarget, cinternal, cexternal, cnum, cdenom time.Duration) time.Duration {
return ClockTime(C.gst_clock_adjust_with_calibration( return time.Duration(C.gst_clock_adjust_with_calibration(
c.Instance(), c.Instance(),
C.GstClockTime(internalTarget), C.GstClockTime(internalTarget),
C.GstClockTime(cinternal), C.GstClockTime(cinternal),
@@ -183,48 +183,30 @@ func (c *Clock) AdjustWithCalibration(internalTarget, cinternal, cexternal, cnum
} }
// GetCalibration gets the internal rate and reference time of clock. See gst_clock_set_calibration for more information. // GetCalibration gets the internal rate and reference time of clock. See gst_clock_set_calibration for more information.
func (c *Clock) GetCalibration() (internal, external, rateNum, rateDenom ClockTime) { func (c *Clock) GetCalibration() (internal, external, rateNum, rateDenom time.Duration) {
var ginternal, gexternal, grateNum, grateDenom C.GstClockTime var ginternal, gexternal, grateNum, grateDenom C.GstClockTime
C.gst_clock_get_calibration(c.Instance(), &ginternal, &gexternal, &grateNum, &grateDenom) C.gst_clock_get_calibration(c.Instance(), &ginternal, &gexternal, &grateNum, &grateDenom)
return ClockTime(ginternal), ClockTime(gexternal), ClockTime(grateNum), ClockTime(grateDenom) return time.Duration(ginternal), time.Duration(gexternal), time.Duration(grateNum), time.Duration(grateDenom)
} }
// GetTime gets the current time of the given clock in nanoseconds or ClockTimeNone if invalid. // GetTime gets the current time of the given clock in nanoseconds or -1 if invalid.
// The time is always monotonically increasing and adjusted according to the current offset and rate. // The time is always monotonically increasing and adjusted according to the current offset and rate.
func (c *Clock) GetTime() ClockTime { func (c *Clock) GetTime() time.Duration {
res := C.gst_clock_get_time(c.Instance()) res := C.gst_clock_get_time(c.Instance())
if ClockTime(res) == ClockTimeNone { if res == C.GST_CLOCK_TIME_NONE {
return ClockTimeNone return ClockTimeNone
} }
return ClockTime(res) return time.Duration(res)
} }
// GetInternalTime gets the current internal time of the given clock in nanoseconds // GetInternalTime gets the current internal time of the given clock in nanoseconds
// or ClockTimeNone if invalid. The time is returned unadjusted for the offset and the rate. // or ClockTimeNone if invalid. The time is returned unadjusted for the offset and the rate.
func (c *Clock) GetInternalTime() ClockTime { func (c *Clock) GetInternalTime() time.Duration {
res := C.gst_clock_get_internal_time(c.Instance()) res := C.gst_clock_get_internal_time(c.Instance())
if ClockTime(res) == ClockTimeNone { if res == C.GST_CLOCK_TIME_NONE {
return ClockTimeNone return ClockTimeNone
} }
return ClockTime(res) return time.Duration(res)
}
// GetDuration returns the time.Duration equivalent of this clock time.
func (c *Clock) GetDuration() time.Duration {
tm := c.GetTime()
if tm == ClockTimeNone {
return time.Duration(-1)
}
return clockTimeToDuration(tm)
}
// GetInternalDuration returns the time.Duration equivalent of this clock's internal time.
func (c *Clock) GetInternalDuration() time.Duration {
tm := c.GetInternalTime()
if tm == ClockTimeNone {
return time.Duration(-1)
}
return clockTimeToDuration(tm)
} }
// GetMaster returns the master clock that this clock is slaved to or nil when the clock // GetMaster returns the master clock that this clock is slaved to or nil when the clock
@@ -239,17 +221,21 @@ func (c *Clock) GetMaster() *Clock {
// GetResolution gets the accuracy of the clock. The accuracy of the clock is the granularity // GetResolution gets the accuracy of the clock. The accuracy of the clock is the granularity
// of the values returned by GetTime. // of the values returned by GetTime.
func (c *Clock) GetResolution() ClockTime { return ClockTime(C.gst_clock_get_resolution(c.Instance())) } func (c *Clock) GetResolution() time.Duration {
return time.Duration(C.gst_clock_get_resolution(c.Instance()))
}
// GetTimeout gets the amount of time that master and slave clocks are sampled. // GetTimeout gets the amount of time that master and slave clocks are sampled.
func (c *Clock) GetTimeout() ClockTime { return ClockTime(C.gst_clock_get_timeout(c.Instance())) } func (c *Clock) GetTimeout() time.Duration {
return time.Duration(C.gst_clock_get_timeout(c.Instance()))
}
// IsSynced returns true if the clock is synced. // IsSynced returns true if the clock is synced.
func (c *Clock) IsSynced() bool { return gobool(C.gst_clock_is_synced(c.Instance())) } func (c *Clock) IsSynced() bool { return gobool(C.gst_clock_is_synced(c.Instance())) }
// NewPeriodicID gets an ID from clock to trigger a periodic notification. The periodic notifications // NewPeriodicID gets an ID from clock to trigger a periodic notification. The periodic notifications
// will start at time start_time and will then be fired with the given interval. ID should be unreffed after usage. // will start at time start_time and will then be fired with the given interval. ID should be unreffed after usage.
func (c *Clock) NewPeriodicID(startTime, interval ClockTime) *ClockID { func (c *Clock) NewPeriodicID(startTime, interval time.Duration) *ClockID {
id := C.gst_clock_new_periodic_id( id := C.gst_clock_new_periodic_id(
c.Instance(), c.Instance(),
C.GstClockTime(startTime), C.GstClockTime(startTime),
@@ -260,7 +246,7 @@ func (c *Clock) NewPeriodicID(startTime, interval ClockTime) *ClockID {
// NewSingleShotID gets a ClockID from the clock to trigger a single shot notification at the requested time. // NewSingleShotID gets a ClockID from the clock to trigger a single shot notification at the requested time.
// The single shot id should be unreffed after usage. // The single shot id should be unreffed after usage.
func (c *Clock) NewSingleShotID(at ClockTime) *ClockID { func (c *Clock) NewSingleShotID(at time.Duration) *ClockID {
id := C.gst_clock_new_single_shot_id( id := C.gst_clock_new_single_shot_id(
c.Instance(), c.Instance(),
C.GstClockTime(at), C.GstClockTime(at),
@@ -270,7 +256,7 @@ func (c *Clock) NewSingleShotID(at ClockTime) *ClockID {
// PeriodicIDReinit reinitializes the provided periodic id to the provided start time and interval. Does not // PeriodicIDReinit reinitializes the provided periodic id to the provided start time and interval. Does not
/// modify the reference count. /// modify the reference count.
func (c *Clock) PeriodicIDReinit(clockID *ClockID, startTime, interval ClockTime) bool { func (c *Clock) PeriodicIDReinit(clockID *ClockID, startTime, interval time.Duration) bool {
return gobool(C.gst_clock_periodic_id_reinit( return gobool(C.gst_clock_periodic_id_reinit(
c.Instance(), c.Instance(),
clockID.Instance(), clockID.Instance(),
@@ -281,7 +267,7 @@ func (c *Clock) PeriodicIDReinit(clockID *ClockID, startTime, interval ClockTime
// SetCalibration adjusts the rate and time of clock. // SetCalibration adjusts the rate and time of clock.
// See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstclock.html#gst_clock_set_calibration. // See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstclock.html#gst_clock_set_calibration.
func (c *Clock) SetCalibration(internal, external, rateNum, rateDenom ClockTime) { func (c *Clock) SetCalibration(internal, external, rateNum, rateDenom time.Duration) {
C.gst_clock_set_calibration( C.gst_clock_set_calibration(
c.Instance(), c.Instance(),
C.GstClockTime(internal), C.GstClockTime(internal),
@@ -305,8 +291,8 @@ func (c *Clock) SetMaster(master *Clock) bool {
// SetResolution sets the accuracy of the clock. Some clocks have the possibility to operate with different accuracy // SetResolution sets the accuracy of the clock. Some clocks have the possibility to operate with different accuracy
// at the expense of more resource usage. There is normally no need to change the default resolution of a clock. // at the expense of more resource usage. There is normally no need to change the default resolution of a clock.
// The resolution of a clock can only be changed if the clock has the ClockFlagCanSetResolution flag set. // The resolution of a clock can only be changed if the clock has the ClockFlagCanSetResolution flag set.
func (c *Clock) SetResolution(resolution ClockTime) ClockTime { func (c *Clock) SetResolution(resolution time.Duration) time.Duration {
return ClockTime(C.gst_clock_set_resolution(c.Instance(), C.GstClockTime(resolution))) return time.Duration(C.gst_clock_set_resolution(c.Instance(), C.GstClockTime(resolution)))
} }
// SetSynced sets clock to synced and emits the GstClock::synced signal, and wakes up any thread waiting in WaitForSync. // SetSynced sets clock to synced and emits the GstClock::synced signal, and wakes up any thread waiting in WaitForSync.
@@ -316,12 +302,12 @@ func (c *Clock) SetResolution(resolution ClockTime) ClockTime {
func (c *Clock) SetSynced(synced bool) { C.gst_clock_set_synced(c.Instance(), gboolean(synced)) } func (c *Clock) SetSynced(synced bool) { C.gst_clock_set_synced(c.Instance(), gboolean(synced)) }
// SetTimeout sets the amount of time, in nanoseconds, to sample master and slave clocks // SetTimeout sets the amount of time, in nanoseconds, to sample master and slave clocks
func (c *Clock) SetTimeout(timeout ClockTime) { func (c *Clock) SetTimeout(timeout time.Duration) {
C.gst_clock_set_timeout(c.Instance(), C.GstClockTime(timeout)) C.gst_clock_set_timeout(c.Instance(), C.GstClockTime(timeout))
} }
// SingleShotIDReinit reinitializes the provided single shot id to the provided time. Does not modify the reference count. // SingleShotIDReinit reinitializes the provided single shot id to the provided time. Does not modify the reference count.
func (c *Clock) SingleShotIDReinit(clockID *ClockID, at ClockTime) bool { func (c *Clock) SingleShotIDReinit(clockID *ClockID, at time.Duration) bool {
return gobool(C.gst_clock_single_shot_id_reinit(c.Instance(), clockID.Instance(), C.GstClockTime(at))) return gobool(C.gst_clock_single_shot_id_reinit(c.Instance(), clockID.Instance(), C.GstClockTime(at)))
} }
@@ -329,14 +315,14 @@ func (c *Clock) SingleShotIDReinit(clockID *ClockID, at ClockTime) bool {
// set with SetCalibration. This function should be called with the clock's OBJECT_LOCK held and is mainly used by clock subclasses. // set with SetCalibration. This function should be called with the clock's OBJECT_LOCK held and is mainly used by clock subclasses.
// //
// This function is the reverse of AdjustUnlocked. // This function is the reverse of AdjustUnlocked.
func (c *Clock) UnadjustUnlocked(external ClockTime) ClockTime { func (c *Clock) UnadjustUnlocked(external time.Duration) time.Duration {
return ClockTime(C.gst_clock_unadjust_unlocked(c.Instance(), C.GstClockTime(external))) return time.Duration(C.gst_clock_unadjust_unlocked(c.Instance(), C.GstClockTime(external)))
} }
// UnadjustWithCalibration converts the given external_target clock time to the internal time, using the passed calibration parameters. // UnadjustWithCalibration converts the given external_target clock time to the internal time, using the passed calibration parameters.
// This function performs the same calculation as UnadjustUnlocked when called using the current calibration parameters. // This function performs the same calculation as UnadjustUnlocked when called using the current calibration parameters.
func (c *Clock) UnadjustWithCalibration(externalTarget, cinternal, cexternal, cnum, cdenom ClockTime) ClockTime { func (c *Clock) UnadjustWithCalibration(externalTarget, cinternal, cexternal, cnum, cdenom time.Duration) time.Duration {
return ClockTime(C.gst_clock_unadjust_with_calibration( return time.Duration(C.gst_clock_unadjust_with_calibration(
c.Instance(), c.Instance(),
C.GstClockTime(externalTarget), C.GstClockTime(externalTarget),
C.GstClockTime(cinternal), C.GstClockTime(cinternal),
@@ -352,12 +338,12 @@ func (c *Clock) UnadjustWithCalibration(externalTarget, cinternal, cexternal, cn
// For asynchronous waiting, the GstClock::synced signal can be used. // For asynchronous waiting, the GstClock::synced signal can be used.
// //
// This returns immediately with TRUE if ClockFlagNeedsStartupSync is not set on the clock, or if the clock is already synced. // This returns immediately with TRUE if ClockFlagNeedsStartupSync is not set on the clock, or if the clock is already synced.
func (c *Clock) WaitForSync(timeout ClockTime) bool { func (c *Clock) WaitForSync(timeout time.Duration) bool {
return gobool(C.gst_clock_wait_for_sync(c.Instance(), C.GstClockTime(timeout))) return gobool(C.gst_clock_wait_for_sync(c.Instance(), C.GstClockTime(timeout)))
} }
// String returns the string representation of this clock value. // String returns the string representation of this clock value.
func (c *Clock) String() string { return c.GetDuration().String() } func (c *Clock) String() string { return c.GetTime().String() }
// InternalString returns the string representation of this clock's internal value. // InternalString returns the string representation of this clock's internal value.
func (c *Clock) InternalString() string { return c.GetInternalDuration().String() } func (c *Clock) InternalString() string { return c.GetInternalTime().String() }

View File

@@ -8,7 +8,7 @@ import (
"strings" "strings"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Device is a Go representation of a GstDevice. // Device is a Go representation of a GstDevice.

View File

@@ -16,6 +16,46 @@ void cgoElementCallAsync (GstElement * element, gpointer user_data)
goElementCallAsync(element, user_data); goElementCallAsync(element, user_data);
} }
gboolean elementParentPostMessage (GstElement * element, GstMessage * message) {
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(element));
GstElementClass * parent = toGstElementClass(g_type_class_peek_parent(this_class));
return parent->post_message(element, message);
}
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 "C"
@@ -23,9 +63,10 @@ import (
"fmt" "fmt"
"path" "path"
"runtime" "runtime"
"time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
) )
@@ -119,6 +160,11 @@ func (e *Element) CallAsync(f func()) {
) )
} }
// ChangeState performs the given transition on this element.
func (e *Element) ChangeState(transition StateChange) StateChangeReturn {
return StateChangeReturn(C.gst_element_change_state(e.Instance(), C.GstStateChange(transition)))
}
// Connect connects to the given signal on this element, and applies f as the callback. The callback must // Connect connects to the given signal on this element, and applies f as the callback. The callback must
// match the signature of the expected callback from the documentation. However, instead of specifying C types // match the signature of the expected callback from the documentation. However, instead of specifying C types
// for arguments specify the go-gst equivalent (e.g. *gst.Element for almost all GstElement derivitives). // for arguments specify the go-gst equivalent (e.g. *gst.Element for almost all GstElement derivitives).
@@ -291,6 +337,12 @@ func (e *Element) LinkFiltered(elem *Element, caps *Caps) error {
return nil return nil
} }
// ParentPostMessage can be used when extending an element. During a PostMessage, use this method
// to have the message posted on the bus after processing.
func (e *Element) ParentPostMessage(msg *Message) bool {
return gobool(C.elementParentPostMessage(e.Instance(), msg.Instance()))
}
// Query performs a query on the given element. // Query performs a query on the given element.
// //
// For elements that don't implement a query handler, this function forwards the query to a random srcpad or // For elements that don't implement a query handler, this function forwards the query to a random srcpad or
@@ -388,6 +440,44 @@ func (e *Element) URIHandler() URIHandler {
// ExtendsElement signifies a GoElement that extends a GstElement. // ExtendsElement signifies a GoElement that extends a GstElement.
var ExtendsElement Extendable = &extendElement{parent: ExtendsObject} var ExtendsElement Extendable = &extendElement{parent: 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 Extendable } type extendElement struct{ parent Extendable }
func (e *extendElement) Type() glib.Type { return glib.Type(C.gst_element_get_type()) } func (e *extendElement) Type() glib.Type { return glib.Type(C.gst_element_get_type()) }
@@ -396,4 +486,102 @@ func (e *extendElement) InstanceSize() int64 { return int64(C.sizeof_GstElement)
func (e *extendElement) InitClass(klass unsafe.Pointer, elem GoElement) { func (e *extendElement) InitClass(klass unsafe.Pointer, elem GoElement) {
e.parent.InitClass(klass, elem) 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)
}
} }

160
gst/gst_element_exports.go Normal file
View File

@@ -0,0 +1,160 @@
package gst
/*
#include "gst.go.h"
*/
import "C"
import (
"time"
"unsafe"
)
//export goGstElementClassChangeState
func goGstElementClassChangeState(elem *C.GstElement, change C.GstStateChange) C.GstStateChangeReturn {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
ChangeState(*Element, StateChange) StateChangeReturn
})
return C.GstStateChangeReturn(iface.ChangeState(wrapCbElem(elem), StateChange(change)))
}
//export goGstElementClassGetState
func goGstElementClassGetState(elem *C.GstElement, state, pending *C.GstState, timeout C.GstClockTime) C.GstStateChangeReturn {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
GetState(*Element, time.Duration) (ret StateChangeReturn, current, pending State)
})
ret, cur, pend := iface.GetState(wrapCbElem(elem), time.Duration(timeout)*time.Nanosecond)
if ret == StateChangeFailure {
return C.GstStateChangeReturn(ret)
}
*state = C.GstState(cur)
*pending = C.GstState(pend)
return C.GstStateChangeReturn(ret)
}
//export goGstElementClassNoMorePads
func goGstElementClassNoMorePads(elem *C.GstElement) {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
NoMorePads(*Element)
})
iface.NoMorePads(wrapCbElem(elem))
}
//export goGstElementClassPadAdded
func goGstElementClassPadAdded(elem *C.GstElement, pad *C.GstPad) {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
PadAdded(*Element, *Pad)
})
iface.PadAdded(wrapCbElem(elem), wrapPad(toGObject(unsafe.Pointer(pad))))
}
//export goGstElementClassPadRemoved
func goGstElementClassPadRemoved(elem *C.GstElement, pad *C.GstPad) {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
PadRemoved(*Element, *Pad)
})
iface.PadRemoved(wrapCbElem(elem), wrapPad(toGObject(unsafe.Pointer(pad))))
}
//export goGstElementClassPostMessage
func goGstElementClassPostMessage(elem *C.GstElement, msg *C.GstMessage) C.gboolean {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
PostMessage(*Element, *Message) bool
})
return gboolean(iface.PostMessage(wrapCbElem(elem), wrapMessage(msg)))
}
//export goGstElementClassProvideClock
func goGstElementClassProvideClock(elem *C.GstElement) *C.GstClock {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
ProvideClock(*Element) *Clock
})
clock := iface.ProvideClock(wrapCbElem(elem))
if clock == nil {
return nil
}
return clock.Instance()
}
//export goGstElementClassQuery
func goGstElementClassQuery(elem *C.GstElement, query *C.GstQuery) C.gboolean {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
Query(*Element, *Query) bool
})
return gboolean(iface.Query(wrapCbElem(elem), wrapQuery(query)))
}
//export goGstElementClassReleasePad
func goGstElementClassReleasePad(elem *C.GstElement, pad *C.GstPad) {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
ReleasePad(*Element, *Pad)
})
iface.ReleasePad(wrapCbElem(elem), wrapPad(toGObject(unsafe.Pointer(pad))))
}
//export goGstElementClassRequestNewPad
func goGstElementClassRequestNewPad(elem *C.GstElement, templ *C.GstPadTemplate, name *C.gchar, caps *C.GstCaps) *C.GstPad {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
RequestNewPad(self *Element, templ *PadTemplate, name string, caps *Caps) *Pad
})
pad := iface.RequestNewPad(
wrapCbElem(elem),
wrapPadTemplate(toGObject(unsafe.Pointer(templ))),
C.GoString(name),
wrapCaps(caps),
)
if pad == nil {
return nil
}
return pad.Instance()
}
//export goGstElementClassSendEvent
func goGstElementClassSendEvent(elem *C.GstElement, event *C.GstEvent) C.gboolean {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
SendEvent(*Element, *Event) bool
})
return gboolean(iface.SendEvent(wrapCbElem(elem), wrapEvent(event)))
}
//export goGstElementClassSetBus
func goGstElementClassSetBus(elem *C.GstElement, bus *C.GstBus) {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
SetBus(*Element, *Bus)
})
iface.SetBus(wrapCbElem(elem), wrapBus(toGObject(unsafe.Pointer(bus))))
}
//export goGstElementClassSetClock
func goGstElementClassSetClock(elem *C.GstElement, clock *C.GstClock) C.gboolean {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
SetClock(*Element, *Clock) bool
})
return gboolean(iface.SetClock(wrapCbElem(elem), wrapClock(toGObject(unsafe.Pointer(clock)))))
}
//export goGstElementClassSetContext
func goGstElementClassSetContext(elem *C.GstElement, ctx *C.GstContext) {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
SetContext(*Element, *Context)
})
iface.SetContext(wrapCbElem(elem), wrapContext(ctx))
}
//export goGstElementClassSetState
func goGstElementClassSetState(elem *C.GstElement, state C.GstState) C.GstStateChangeReturn {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
SetState(*Element, State) StateChangeReturn
})
return C.GstStateChangeReturn(iface.SetState(wrapCbElem(elem), State(state)))
}
//export goGstElementClassStateChanged
func goGstElementClassStateChanged(elem *C.GstElement, old, new, pending C.GstState) {
iface := FromObjectUnsafePrivate(unsafe.Pointer(elem)).(interface {
StateChanged(self *Element, old, new, pending State)
})
iface.StateChanged(wrapCbElem(elem), State(old), State(new), State(pending))
}
func wrapCbElem(elem *C.GstElement) *Element { return wrapElement(toGObject(unsafe.Pointer(elem))) }

View File

@@ -7,7 +7,7 @@ import (
"fmt" "fmt"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// FromGstElementUnsafe wraps the pointer to the given C GstElement with the go type. // FromGstElementUnsafe wraps the pointer to the given C GstElement with the go type.

View File

@@ -7,7 +7,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Event is a go wrapper around a GstEvent. // Event is a go wrapper around a GstEvent.
@@ -108,7 +108,7 @@ func (e *Event) ParseFlushStop() (resetTime bool) {
func (e *Event) ParseGap() (timestamp, duration time.Duration) { func (e *Event) ParseGap() (timestamp, duration time.Duration) {
var ts, dur C.GstClockTime var ts, dur C.GstClockTime
C.gst_event_parse_gap(e.Instance(), &ts, &dur) C.gst_event_parse_gap(e.Instance(), &ts, &dur)
return clockTimeToDuration(ClockTime(ts)), clockTimeToDuration(ClockTime(dur)) return time.Duration(ts), time.Duration(dur)
} }
// ParseGapFlags retrieves the gap flags that may have been set on a gap event with SetGapFlags. // ParseGapFlags retrieves the gap flags that may have been set on a gap event with SetGapFlags.
@@ -135,7 +135,7 @@ func (e *Event) ParseGroupID() (ok bool, gid uint) {
func (e *Event) ParseLatency() time.Duration { func (e *Event) ParseLatency() time.Duration {
var out C.GstClockTime var out C.GstClockTime
C.gst_event_parse_latency(e.Instance(), &out) C.gst_event_parse_latency(e.Instance(), &out)
return clockTimeToDuration(ClockTime(out)) return time.Duration(out)
} }
// ParseProtection parses an event containing protection system specific information and stores the results in // ParseProtection parses an event containing protection system specific information and stores the results in
@@ -168,7 +168,7 @@ func (e *Event) ParseQOS() (qTtype QOSType, proportion float64, diff ClockTimeDi
e.Instance(), e.Instance(),
&gtype, &gprop, &gdiff, &gts, &gtype, &gprop, &gdiff, &gts,
) )
return QOSType(gtype), float64(gprop), ClockTimeDiff(gdiff), clockTimeToDuration(ClockTime(gts)) return QOSType(gtype), float64(gprop), ClockTimeDiff(gdiff), time.Duration(gts)
} }
// ParseSeek parses a seek event. // ParseSeek parses a seek event.
@@ -187,7 +187,7 @@ func (e *Event) ParseSeek() (rate float64, format Format, flags SeekFlags, start
func (e *Event) ParseSeekTrickModeInterval() (interval time.Duration) { func (e *Event) ParseSeekTrickModeInterval() (interval time.Duration) {
var out C.GstClockTime var out C.GstClockTime
C.gst_event_parse_seek_trickmode_interval(e.Instance(), &out) C.gst_event_parse_seek_trickmode_interval(e.Instance(), &out)
return clockTimeToDuration(ClockTime(out)) return time.Duration(out)
} }
// ParseSegment parses a segment event and stores the result in the given segment location. segment remains valid // ParseSegment parses a segment event and stores the result in the given segment location. segment remains valid
@@ -324,7 +324,7 @@ func (e *Event) SetRunningTimeOffset(offset int64) {
// SetSeekTrickModeInterval sets a trickmode interval on a (writable) seek event. Elements that support TRICKMODE_KEY_UNITS // SetSeekTrickModeInterval sets a trickmode interval on a (writable) seek event. Elements that support TRICKMODE_KEY_UNITS
// seeks SHOULD use this as the minimal interval between each frame they may output. // seeks SHOULD use this as the minimal interval between each frame they may output.
func (e *Event) SetSeekTrickModeInterval(interval time.Duration) { func (e *Event) SetSeekTrickModeInterval(interval time.Duration) {
C.gst_event_set_seek_trickmode_interval(e.Instance(), C.GstClockTime(durationToClockTime(interval))) C.gst_event_set_seek_trickmode_interval(e.Instance(), C.GstClockTime(interval.Nanoseconds()))
} }
// SetSeqnum sets the sequence number of a event. // SetSeqnum sets the sequence number of a event.

View File

@@ -67,8 +67,8 @@ func NewFlushStopEvent(resetTime bool) *Event {
// especially for sparse streams such as subtitle streams. // especially for sparse streams such as subtitle streams.
func NewGapEvent(timestamp, duration time.Duration) *Event { func NewGapEvent(timestamp, duration time.Duration) *Event {
return wrapEvent(C.gst_event_new_gap( return wrapEvent(C.gst_event_new_gap(
C.GstClockTime(durationToClockTime(timestamp)), C.GstClockTime(timestamp.Nanoseconds()),
C.GstClockTime(durationToClockTime(duration)), C.GstClockTime(duration.Nanoseconds()),
)) ))
} }
@@ -105,7 +105,7 @@ func NewGapEvent(timestamp, duration time.Duration) *Event {
// The latency is mostly used in live sinks and is always expressed in the time format. // The latency is mostly used in live sinks and is always expressed in the time format.
func NewLatencyEvent(latency time.Duration) *Event { func NewLatencyEvent(latency time.Duration) *Event {
return wrapEvent(C.gst_event_new_latency( return wrapEvent(C.gst_event_new_latency(
C.GstClockTime(durationToClockTime(latency)), C.GstClockTime(latency.Nanoseconds()),
)) ))
} }
@@ -168,7 +168,7 @@ func NewQOSEvent(qType QOSType, proportion float64, diff ClockTimeDiff, timestam
C.GstQOSType(qType), C.GstQOSType(qType),
C.gdouble(proportion), C.gdouble(proportion),
C.GstClockTimeDiff(diff), C.GstClockTimeDiff(diff),
C.GstClockTime(durationToClockTime(timestamp)), C.GstClockTime(timestamp.Nanoseconds()),
)) ))
} }

View File

@@ -4,6 +4,10 @@ package gst
import "C" import "C"
import "unsafe" import "unsafe"
// CAT is the global DebugCategory used for logging from the bindings. It is okay to use
// it from applications, but plugins should use their own.
var CAT *DebugCategory
// Init is a wrapper around gst_init() and must be called before any // Init is a wrapper around gst_init() and must be called before any
// other gstreamer calls and is used to initialize everything necessary. // other gstreamer calls and is used to initialize everything necessary.
// In addition to setting up gstreamer for usage, a pointer to a slice of // In addition to setting up gstreamer for usage, a pointer to a slice of
@@ -11,6 +15,10 @@ import "unsafe"
// args will be modified to remove any flags that were handled. // args will be modified to remove any flags that were handled.
// Alternatively, nil may be passed in to not perform any command line // Alternatively, nil may be passed in to not perform any command line
// parsing. // parsing.
//
// The bindings will also set up their own internal DebugCategory for logging
// than can be invoked from applications or plugins as well. However, for
// plugins it is generally better to initialize your own DebugCategory.
func Init(args *[]string) { func Init(args *[]string) {
if args != nil { if args != nil {
argc := C.int(len(*args)) argc := C.int(len(*args))
@@ -29,4 +37,5 @@ func Init(args *[]string) {
} else { } else {
C.gst_init(nil, nil) C.gst_init(nil, nil)
} }
CAT = NewDebugCategory("GST_GO", DebugColorNone, "GStreamer Go Bindings")
} }

View File

@@ -2,11 +2,17 @@ package gst
/* /*
#include "gst.go.h" #include "gst.go.h"
void memcpy_offset (void * dest, guint offset, const void * src, size_t n) { memcpy(dest + offset, src, n); }
*/ */
import "C" import "C"
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors"
"io"
"unsafe" "unsafe"
) )
@@ -20,11 +26,45 @@ func (m *MapInfo) Instance() *C.GstMapInfo {
return m.ptr return m.ptr
} }
// Reader returns a Reader for the contents of this map's memory.
func (m *MapInfo) Reader() io.Reader {
return bytes.NewReader(m.Bytes())
}
type mapInfoWriter struct {
mapInfo *MapInfo
wsize int
}
func (m *mapInfoWriter) Write(p []byte) (int, error) {
if m.wsize+len(p) > int(m.mapInfo.Size()) {
return 0, errors.New("Attempt to write more data than allocated to MapInfo")
}
m.mapInfo.WriteAt(m.wsize, p)
m.wsize += len(p)
return len(p), nil
}
// Writer returns a writer that will copy the contents passed to Write directly to the
// map's memory sequentially. An error will be returned if an attempt is made to write
// more data than the map can hold.
func (m *MapInfo) Writer() io.Writer {
return &mapInfoWriter{
mapInfo: m,
wsize: 0,
}
}
// WriteData writes the given sequence directly to the map's memory. // WriteData writes the given sequence directly to the map's memory.
func (m *MapInfo) WriteData(data []byte) { func (m *MapInfo) WriteData(data []byte) {
C.memcpy(unsafe.Pointer(m.ptr.data), unsafe.Pointer(&data[0]), C.gsize(len(data))) C.memcpy(unsafe.Pointer(m.ptr.data), unsafe.Pointer(&data[0]), C.gsize(len(data)))
} }
// WriteAt writes the given data sequence directly to the map's memory at the given offset.
func (m *MapInfo) WriteAt(offset int, data []byte) {
C.memcpy_offset(unsafe.Pointer(m.ptr.data), C.guint(offset), unsafe.Pointer(&data[0]), C.gsize(len(data)))
}
// Memory returns the underlying memory object. // Memory returns the underlying memory object.
func (m *MapInfo) Memory() *Memory { func (m *MapInfo) Memory() *Memory {
return wrapMemory(m.ptr.memory) return wrapMemory(m.ptr.memory)

View File

@@ -8,7 +8,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Memory is a go representation of GstMemory. This object is implemented in a read-only fashion // Memory is a go representation of GstMemory. This object is implemented in a read-only fashion

View File

@@ -8,7 +8,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Message is a Go wrapper around a GstMessage. It provides convenience methods for // Message is a Go wrapper around a GstMessage. It provides convenience methods for
@@ -170,7 +170,7 @@ func (m *Message) ParseStreamStatus() (StreamStatusType, *Element) {
func (m *Message) ParseAsyncDone() time.Duration { func (m *Message) ParseAsyncDone() time.Duration {
var clockTime C.GstClockTime var clockTime C.GstClockTime
C.gst_message_parse_async_done((*C.GstMessage)(m.Instance()), &clockTime) C.gst_message_parse_async_done((*C.GstMessage)(m.Instance()), &clockTime)
return clockTimeToDuration(ClockTime(clockTime)) return time.Duration(clockTime)
} }
// BufferingStats represents the buffering stats as retrieved from a GST_MESSAGE_TYPE_BUFFERING. // BufferingStats represents the buffering stats as retrieved from a GST_MESSAGE_TYPE_BUFFERING.
@@ -339,7 +339,7 @@ type QoSValues struct {
// The stream time of the buffer that generated the message // The stream time of the buffer that generated the message
StreamTime time.Duration StreamTime time.Duration
// The timestamps of the buffer that generated the message // The timestamps of the buffer that generated the message
Timestamp ClockTime Timestamp time.Duration
// The duration of the buffer that generated the message // The duration of the buffer that generated the message
Duration time.Duration Duration time.Duration
} }
@@ -356,10 +356,10 @@ func (m *Message) ParseQoS() *QoSValues {
) )
return &QoSValues{ return &QoSValues{
Live: gobool(live), Live: gobool(live),
RunningTime: guint64ToDuration(runningTime), RunningTime: time.Duration(runningTime),
StreamTime: guint64ToDuration(streamTime), StreamTime: time.Duration(streamTime),
Timestamp: ClockTime(timestamp), Timestamp: time.Duration(timestamp),
Duration: guint64ToDuration(duration), Duration: time.Duration(duration),
} }
} }
@@ -385,7 +385,7 @@ func (m *Message) ParseProgress() (progressType ProgressType, code, text string)
func (m *Message) ParseResetTime() time.Duration { func (m *Message) ParseResetTime() time.Duration {
var clockTime C.GstClockTime var clockTime C.GstClockTime
C.gst_message_parse_reset_time((*C.GstMessage)(m.Instance()), &clockTime) C.gst_message_parse_reset_time((*C.GstMessage)(m.Instance()), &clockTime)
return clockTimeToDuration(ClockTime(clockTime)) return time.Duration(clockTime)
} }
// ParseDeviceAdded parses a device-added message. The device-added message is // ParseDeviceAdded parses a device-added message. The device-added message is

View File

@@ -6,7 +6,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
func getMessageSourceObj(src interface{}) *C.GstObject { func getMessageSourceObj(src interface{}) *C.GstObject {
@@ -41,9 +41,9 @@ func NewAsyncDoneMessage(src interface{}, runningTime time.Duration) *Message {
} }
var cTime C.GstClockTime var cTime C.GstClockTime
if runningTime.Nanoseconds() < 0 { if runningTime.Nanoseconds() < 0 {
cTime = C.GstClockTime(ClockTimeNone) cTime = C.GstClockTime(gstClockTimeNone)
} else { } else {
cTime = C.GstClockTime(durationToClockTime(runningTime)) cTime = C.GstClockTime(runningTime.Nanoseconds())
} }
return wrapMessage(C.gst_message_new_async_done( return wrapMessage(C.gst_message_new_async_done(
srcObj, srcObj,
@@ -312,7 +312,7 @@ func NewPropertyNotifyMessage(src interface{}, propName string, val interface{})
return wrapMessage(C.gst_message_new_property_notify( return wrapMessage(C.gst_message_new_property_notify(
srcObj, srcObj,
cName, cName,
(*C.GValue)(gVal.Native()), (*C.GValue)(unsafe.Pointer(gVal.GValue)),
)) ))
} }
@@ -332,10 +332,10 @@ func NewQoSMessage(src interface{}, live bool, runningTime, streamTime, timestam
return wrapMessage(C.gst_message_new_qos( return wrapMessage(C.gst_message_new_qos(
srcObj, srcObj,
gboolean(live), gboolean(live),
C.guint64(durationToClockTime(runningTime)), C.guint64((runningTime.Nanoseconds())),
C.guint64(durationToClockTime(streamTime)), C.guint64((streamTime.Nanoseconds())),
C.guint64(durationToClockTime(timestamp)), C.guint64((timestamp.Nanoseconds())),
C.guint64(durationToClockTime(duration)), C.guint64((duration.Nanoseconds())),
)) ))
} }
@@ -410,7 +410,7 @@ func NewResetTimeMessage(src interface{}, runningTime time.Duration) *Message {
if srcObj == nil { if srcObj == nil {
return nil return nil
} }
return wrapMessage(C.gst_message_new_reset_time(srcObj, C.GstClockTime(durationToClockTime(runningTime)))) return wrapMessage(C.gst_message_new_reset_time(srcObj, C.GstClockTime(runningTime.Nanoseconds())))
} }
// NewSegmentDoneMessage creates a new segment done message. This message is posted by elements that finish playback of a segment as a result of a // NewSegmentDoneMessage creates a new segment done message. This message is posted by elements that finish playback of a segment as a result of a
@@ -479,7 +479,7 @@ func NewStepDoneMessage(src interface{}, format Format, amount uint64, rate floa
C.gdouble(rate), C.gdouble(rate),
gboolean(flush), gboolean(flush),
gboolean(intermediate), gboolean(intermediate),
C.guint64(durationToClockTime(duration)), C.guint64(duration.Nanoseconds()),
gboolean(eos), gboolean(eos),
)) ))
} }

View File

@@ -27,7 +27,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Meta is a go representation of GstMeta. // Meta is a go representation of GstMeta.

View File

@@ -6,7 +6,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// MiniObject is an opaque struct meant to form the base of gstreamer // MiniObject is an opaque struct meant to form the base of gstreamer

View File

@@ -6,7 +6,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Object is a go representation of a GstObject. // Object is a go representation of a GstObject.

View File

@@ -35,7 +35,7 @@ import (
"errors" "errors"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
) )

View File

@@ -5,7 +5,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// PadTemplate is a go representation of a GstPadTemplate // PadTemplate is a go representation of a GstPadTemplate

View File

@@ -9,7 +9,7 @@ import (
"strings" "strings"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Pipeline is a go implementation of a GstPipeline. // Pipeline is a go implementation of a GstPipeline.

View File

@@ -16,8 +16,19 @@ gboolean cgoGlobalPluginInit(GstPlugin * plugin)
return goGlobalPluginInit(plugin); return goGlobalPluginInit(plugin);
} }
GstPluginDesc * exportPluginMeta (gint major, gint minor, gchar * name, gchar * description, GstPluginInitFunc init, gchar * version, gchar * license, gchar * source, gchar * package, gchar * origin, gchar * release_datetime) GstPluginDesc * getPluginMeta (gint major,
gint minor,
gchar * name,
gchar * description,
GstPluginInitFunc init,
gchar * version,
gchar * license,
gchar * source,
gchar * package,
gchar * origin,
gchar * release_datetime)
{ {
GstPluginDesc * desc = malloc ( sizeof (GstPluginDesc) ); GstPluginDesc * desc = malloc ( sizeof (GstPluginDesc) );
desc->major_version = major; desc->major_version = major;
@@ -42,7 +53,7 @@ import (
"errors" "errors"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
) )
@@ -80,10 +91,10 @@ var globalPluginInit PluginInitFunc
// Export will export the PluginMetadata to an unsafe pointer to a GstPluginDesc. // Export will export the PluginMetadata to an unsafe pointer to a GstPluginDesc.
func (p *PluginMetadata) Export() unsafe.Pointer { func (p *PluginMetadata) Export() unsafe.Pointer {
globalPluginInit = p.Init globalPluginInit = p.Init
desc := C.exportPluginMeta( desc := C.getPluginMeta(
C.gint(p.MajorVersion), C.gint(p.MajorVersion),
C.gint(p.MinorVersion), C.gint(p.MinorVersion),
(*C.gchar)(C.CString(p.Name)), (*C.gchar)(unsafe.Pointer(&[]byte(p.Name)[0])),
(*C.gchar)(C.CString(p.Description)), (*C.gchar)(C.CString(p.Description)),
(C.GstPluginInitFunc(C.cgoGlobalPluginInit)), (C.GstPluginInitFunc(C.cgoGlobalPluginInit)),
(*C.gchar)(C.CString(p.Version)), (*C.gchar)(C.CString(p.Version)),

View File

@@ -6,7 +6,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// PluginFeature wraps the C GstPluginFeature. // PluginFeature wraps the C GstPluginFeature.

View File

@@ -6,7 +6,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Query is a go wrapper around a GstQuery. // Query is a go wrapper around a GstQuery.
@@ -332,7 +332,7 @@ func (q *Query) ParseLatency() (live bool, minLatency, maxLatency time.Duration)
var min, max C.GstClockTime var min, max C.GstClockTime
var gl C.gboolean var gl C.gboolean
C.gst_query_parse_latency(q.Instance(), &gl, &min, &max) C.gst_query_parse_latency(q.Instance(), &gl, &min, &max)
return gobool(gl), clockTimeToDuration(ClockTime(min)), clockTimeToDuration(ClockTime(max)) return gobool(gl), time.Duration(min), time.Duration(max)
} }
// ParseNumFormats parses the number of formats in the formats query. // ParseNumFormats parses the number of formats in the formats query.
@@ -517,7 +517,7 @@ func (q *Query) SetFormats(formats ...Format) {
// SetLatency answers a latency query by setting the requested values in the given format. // SetLatency answers a latency query by setting the requested values in the given format.
func (q *Query) SetLatency(live bool, minLatency, maxLatency time.Duration) { func (q *Query) SetLatency(live bool, minLatency, maxLatency time.Duration) {
C.gst_query_set_latency(q.Instance(), gboolean(live), C.GstClockTime(durationToClockTime(minLatency)), C.GstClockTime(durationToClockTime(maxLatency))) C.gst_query_set_latency(q.Instance(), gboolean(live), C.guint64(minLatency.Nanoseconds()), C.guint64(maxLatency.Nanoseconds()))
} }
// SetAllocationParamAt sets allocation params in query. // SetAllocationParamAt sets allocation params in query.

View File

@@ -7,7 +7,7 @@ import (
"fmt" "fmt"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Registry is a go representation of a GstRegistry. // Registry is a go representation of a GstRegistry.

View File

@@ -6,7 +6,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// Stream is a Go representation of a GstStream. // Stream is a Go representation of a GstStream.

View File

@@ -7,7 +7,7 @@ import (
"fmt" "fmt"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// StreamCollection is a Go representation of a GstStreamCollection. // StreamCollection is a Go representation of a GstStreamCollection.

View File

@@ -20,8 +20,8 @@ import (
"sync" "sync"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
) )
// Structure is a go implementation of a C GstStructure. // Structure is a go implementation of a C GstStructure.
@@ -52,7 +52,7 @@ func NewStructureFromString(stStr string) *Structure {
// StructureFromGValue extracts the GstStructure from a glib.Value, or nil // StructureFromGValue extracts the GstStructure from a glib.Value, or nil
// if one does not exist. // if one does not exist.
func StructureFromGValue(gval *glib.Value) *Structure { func StructureFromGValue(gval *glib.Value) *Structure {
st := C.gst_value_get_structure((*C.GValue)(gval.Native())) st := C.gst_value_get_structure((*C.GValue)(unsafe.Pointer(gval.GValue)))
if st == nil { if st == nil {
return nil return nil
} }

View File

@@ -5,7 +5,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// SystemClock wraps GstSystemClock // SystemClock wraps GstSystemClock

View File

@@ -17,8 +17,8 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
"github.com/tinyzimmer/go-glib/glib"
) )
// TagList is a go wrapper around a GstTagList. For now, until the rest of the methods are // TagList is a go wrapper around a GstTagList. For now, until the rest of the methods are
@@ -86,7 +86,7 @@ func (t *TagList) AddValue(mergeMode TagMergeMode, tag Tag, value interface{}) {
t.Instance(), t.Instance(),
C.GstTagMergeMode(mergeMode), C.GstTagMergeMode(mergeMode),
(*C.gchar)(ctag), (*C.gchar)(ctag),
(*C.GValue)(gVal.Native()), (*C.GValue)(unsafe.Pointer(gVal.GValue)),
) )
} }

View File

@@ -5,7 +5,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// InterfaceTagSetter represents the GstTagsetter interface GType. Use this when querying bins // InterfaceTagSetter represents the GstTagsetter interface GType. Use this when querying bins
@@ -57,7 +57,7 @@ func (t *gstTagSetter) AddTagValue(mergeMode TagMergeMode, tagKey Tag, tagValue
t.Instance(), t.Instance(),
C.GstTagMergeMode(mergeMode), C.GstTagMergeMode(mergeMode),
(*C.gchar)(unsafe.Pointer(ckey)), (*C.gchar)(unsafe.Pointer(ckey)),
(*C.GValue)(gVal.Native()), (*C.GValue)(unsafe.Pointer(gVal.GValue)),
) )
} }

View File

@@ -2,7 +2,7 @@ package gst
// #include "gst.go.h" // #include "gst.go.h"
import "C" import "C"
import "github.com/gotk3/gotk3/glib" import "github.com/tinyzimmer/go-glib/glib"
// InterfaceTOCSetter represents the GstTocSetter interface GType. Use this when querying bins // InterfaceTOCSetter represents the GstTocSetter interface GType. Use this when querying bins
// for elements that implement a TOCSetter. // for elements that implement a TOCSetter.

View File

@@ -8,7 +8,7 @@ import (
"errors" "errors"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
// InterfaceURIHandler represents the GstURIHandler interface GType. Use this when querying bins // InterfaceURIHandler represents the GstURIHandler interface GType. Use this when querying bins

View File

@@ -2,17 +2,85 @@ package gst
/* /*
#include "gst.go.h" #include "gst.go.h"
GValue * toGValue (guintptr p) { return (GValue*)(p); }
*/ */
import "C" import "C"
import ( import (
"time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
) )
func init() { func init() { registerMarshalers() }
// Object wrappers
func wrapAllocator(obj *glib.Object) *Allocator { return &Allocator{wrapObject(obj)} }
func wrapBin(obj *glib.Object) *Bin { return &Bin{wrapElement(obj)} }
func wrapBuffer(buf *C.GstBuffer) *Buffer { return &Buffer{ptr: buf} }
func wrapBufferList(bufList *C.GstBufferList) *BufferList { return &BufferList{ptr: bufList} }
func wrapBufferPool(obj *glib.Object) *BufferPool { return &BufferPool{wrapObject(obj)} }
func wrapBus(obj *glib.Object) *Bus { return &Bus{Object: wrapObject(obj)} }
func wrapCaps(caps *C.GstCaps) *Caps { return &Caps{native: caps} }
func wrapClock(obj *glib.Object) *Clock { return &Clock{wrapObject(obj)} }
func wrapContext(ctx *C.GstContext) *Context { return &Context{ptr: ctx} }
func wrapDevice(obj *glib.Object) *Device { return &Device{wrapObject(obj)} }
func wrapElement(obj *glib.Object) *Element { return &Element{wrapObject(obj)} }
func wrapEvent(ev *C.GstEvent) *Event { return &Event{ptr: ev} }
func wrapGhostPad(obj *glib.Object) *GhostPad { return &GhostPad{wrapProxyPad(obj)} }
func wrapMainContext(ctx *C.GMainContext) *MainContext { return &MainContext{ptr: ctx} }
func wrapMainLoop(loop *C.GMainLoop) *MainLoop { return &MainLoop{ptr: loop} }
func wrapMapInfo(mapInfo *C.GstMapInfo) *MapInfo { return &MapInfo{ptr: mapInfo} }
func wrapMemory(mem *C.GstMemory) *Memory { return &Memory{ptr: mem} }
func wrapMessage(msg *C.GstMessage) *Message { return &Message{msg: msg} }
func wrapMeta(meta *C.GstMeta) *Meta { return &Meta{ptr: meta} }
func wrapMetaInfo(info *C.GstMetaInfo) *MetaInfo { return &MetaInfo{ptr: info} }
func wrapPad(obj *glib.Object) *Pad { return &Pad{wrapObject(obj)} }
func wrapPadTemplate(obj *glib.Object) *PadTemplate { return &PadTemplate{wrapObject(obj)} }
func wrapPipeline(obj *glib.Object) *Pipeline { return &Pipeline{Bin: wrapBin(obj)} }
func wrapPluginFeature(obj *glib.Object) *PluginFeature { return &PluginFeature{wrapObject(obj)} }
func wrapPlugin(obj *glib.Object) *Plugin { return &Plugin{wrapObject(obj)} }
func wrapProxyPad(obj *glib.Object) *ProxyPad { return &ProxyPad{wrapPad(obj)} }
func wrapQuery(query *C.GstQuery) *Query { return &Query{ptr: query} }
func wrapRegistry(obj *glib.Object) *Registry { return &Registry{wrapObject(obj)} }
func wrapSample(sample *C.GstSample) *Sample { return &Sample{sample: sample} }
func wrapSegment(segment *C.GstSegment) *Segment { return &Segment{ptr: segment} }
func wrapStream(obj *glib.Object) *Stream { return &Stream{wrapObject(obj)} }
func wrapTagList(tagList *C.GstTagList) *TagList { return &TagList{ptr: tagList} }
func wrapTOC(toc *C.GstToc) *TOC { return &TOC{ptr: toc} }
func wrapTOCEntry(toc *C.GstTocEntry) *TOCEntry { return &TOCEntry{ptr: toc} }
func wrapCapsFeatures(features *C.GstCapsFeatures) *CapsFeatures {
return &CapsFeatures{native: features}
}
func wrapObject(obj *glib.Object) *Object {
return &Object{InitiallyUnowned: &glib.InitiallyUnowned{Object: obj}}
}
func wrapElementFactory(obj *glib.Object) *ElementFactory {
return &ElementFactory{wrapPluginFeature(obj)}
}
func wrapStreamCollection(obj *glib.Object) *StreamCollection {
return &StreamCollection{wrapObject(obj)}
}
func wrapAllocationParams(obj *C.GstAllocationParams) *AllocationParams {
return &AllocationParams{ptr: obj}
}
func wrapElementClass(klass C.gpointer) *ElementClass {
return &ElementClass{&ObjectClass{ptr: C.toGObjectClass(unsafe.Pointer(klass))}}
}
// Marshallers
func uintptrToGVal(p uintptr) *C.GValue { return (*C.GValue)(C.toGValue(C.guintptr(p))) }
func registerMarshalers() {
tm := []glib.TypeMarshaler{ tm := []glib.TypeMarshaler{
{ {
T: glib.Type(C.gst_buffering_mode_get_type()), T: glib.Type(C.gst_buffering_mode_get_type()),
@@ -147,92 +215,6 @@ func init() {
glib.RegisterGValueMarshalers(tm) glib.RegisterGValueMarshalers(tm)
} }
func uintptrToGVal(p uintptr) *C.GValue {
return (*C.GValue)(unsafe.Pointer(p)) // vet thinks this is unsafe and there is no way around it for now.
// but the given ptr is an address to a C object so go's concerns are misplaced.
}
// Object wrappers
func wrapAllocator(obj *glib.Object) *Allocator { return &Allocator{wrapObject(obj)} }
func wrapBin(obj *glib.Object) *Bin { return &Bin{wrapElement(obj)} }
func wrapBuffer(buf *C.GstBuffer) *Buffer { return &Buffer{ptr: buf} }
func wrapBufferList(bufList *C.GstBufferList) *BufferList { return &BufferList{ptr: bufList} }
func wrapBufferPool(obj *glib.Object) *BufferPool { return &BufferPool{wrapObject(obj)} }
func wrapBus(obj *glib.Object) *Bus { return &Bus{Object: wrapObject(obj)} }
func wrapCaps(caps *C.GstCaps) *Caps { return &Caps{native: caps} }
func wrapClock(obj *glib.Object) *Clock { return &Clock{wrapObject(obj)} }
func wrapContext(ctx *C.GstContext) *Context { return &Context{ptr: ctx} }
func wrapDevice(obj *glib.Object) *Device { return &Device{wrapObject(obj)} }
func wrapElement(obj *glib.Object) *Element { return &Element{wrapObject(obj)} }
func wrapEvent(ev *C.GstEvent) *Event { return &Event{ptr: ev} }
func wrapGhostPad(obj *glib.Object) *GhostPad { return &GhostPad{wrapProxyPad(obj)} }
func wrapMainContext(ctx *C.GMainContext) *MainContext { return &MainContext{ptr: ctx} }
func wrapMainLoop(loop *C.GMainLoop) *MainLoop { return &MainLoop{ptr: loop} }
func wrapMapInfo(mapInfo *C.GstMapInfo) *MapInfo { return &MapInfo{ptr: mapInfo} }
func wrapMemory(mem *C.GstMemory) *Memory { return &Memory{ptr: mem} }
func wrapMessage(msg *C.GstMessage) *Message { return &Message{msg: msg} }
func wrapMeta(meta *C.GstMeta) *Meta { return &Meta{ptr: meta} }
func wrapMetaInfo(info *C.GstMetaInfo) *MetaInfo { return &MetaInfo{ptr: info} }
func wrapPad(obj *glib.Object) *Pad { return &Pad{wrapObject(obj)} }
func wrapPadTemplate(obj *glib.Object) *PadTemplate { return &PadTemplate{wrapObject(obj)} }
func wrapPipeline(obj *glib.Object) *Pipeline { return &Pipeline{Bin: wrapBin(obj)} }
func wrapPluginFeature(obj *glib.Object) *PluginFeature { return &PluginFeature{wrapObject(obj)} }
func wrapPlugin(obj *glib.Object) *Plugin { return &Plugin{wrapObject(obj)} }
func wrapProxyPad(obj *glib.Object) *ProxyPad { return &ProxyPad{wrapPad(obj)} }
func wrapQuery(query *C.GstQuery) *Query { return &Query{ptr: query} }
func wrapRegistry(obj *glib.Object) *Registry { return &Registry{wrapObject(obj)} }
func wrapSample(sample *C.GstSample) *Sample { return &Sample{sample: sample} }
func wrapSegment(segment *C.GstSegment) *Segment { return &Segment{ptr: segment} }
func wrapStream(obj *glib.Object) *Stream { return &Stream{wrapObject(obj)} }
func wrapTagList(tagList *C.GstTagList) *TagList { return &TagList{ptr: tagList} }
func wrapTOC(toc *C.GstToc) *TOC { return &TOC{ptr: toc} }
func wrapTOCEntry(toc *C.GstTocEntry) *TOCEntry { return &TOCEntry{ptr: toc} }
func wrapCapsFeatures(features *C.GstCapsFeatures) *CapsFeatures {
return &CapsFeatures{native: features}
}
func wrapObject(obj *glib.Object) *Object {
return &Object{InitiallyUnowned: &glib.InitiallyUnowned{Object: obj}}
}
func wrapElementFactory(obj *glib.Object) *ElementFactory {
return &ElementFactory{wrapPluginFeature(obj)}
}
func wrapStreamCollection(obj *glib.Object) *StreamCollection {
return &StreamCollection{wrapObject(obj)}
}
func wrapAllocationParams(obj *C.GstAllocationParams) *AllocationParams {
return &AllocationParams{ptr: obj}
}
func wrapElementClass(klass C.gpointer) *ElementClass {
return &ElementClass{&ObjectClass{ptr: C.toGObjectClass(unsafe.Pointer(klass))}}
}
// Clock wrappers
func clockTimeToDuration(n ClockTime) time.Duration {
if n == ClockTimeNone {
return time.Duration(-1)
}
return time.Duration(uint64(n)) * time.Nanosecond
}
func guint64ToDuration(n C.guint64) time.Duration { return clockTimeToDuration(ClockTime(n)) }
func durationToClockTime(dur time.Duration) ClockTime {
if dur.Nanoseconds() < 0 {
return ClockTimeNone
}
return ClockTime(dur.Nanoseconds())
}
// Marshallers
func marshalBufferingMode(p uintptr) (interface{}, error) { func marshalBufferingMode(p uintptr) (interface{}, error) {
c := C.g_value_get_enum(uintptrToGVal(p)) c := C.g_value_get_enum(uintptrToGVal(p))
return BufferingMode(c), nil return BufferingMode(c), nil

View File

@@ -15,13 +15,13 @@ import (
"reflect" "reflect"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
gopointer "github.com/mattn/go-pointer" gopointer "github.com/mattn/go-pointer"
) )
// GoElement is an interface to be implemented by GStreamer elements built using the // GoElement is an interface to be implemented by GStreamer elements built using the
// go bindings. Select methods from other interfaces can be overridden and declared via // go bindings. Select methods from other interfaces can be overridden and declared via
// the Extendable properties. // the Extendable property provided at plugin registration.
// //
// Typically, at the very least, an element will want to implement methods from the Element // Typically, at the very least, an element will want to implement methods from the Element
// Extendable (and by extension the GoObject). // Extendable (and by extension the GoObject).
@@ -68,7 +68,6 @@ type classData struct {
func gtypeForGoElement(name string, elem GoElement, extendable Extendable) C.GType { func gtypeForGoElement(name string, elem GoElement, extendable Extendable) C.GType {
registerMutex.Lock() registerMutex.Lock()
defer registerMutex.Unlock() defer registerMutex.Unlock()
// fmt.Printf("Checking registration of %v\n", reflect.TypeOf(elem).String())
if registered, ok := registeredTypes[reflect.TypeOf(elem).String()]; ok { if registered, ok := registeredTypes[reflect.TypeOf(elem).String()]; ok {
return registered return registered
} }
@@ -96,7 +95,6 @@ func gtypeForGoElement(name string, elem GoElement, extendable Extendable) C.GTy
C.GTypeFlags(0), C.GTypeFlags(0),
) )
elem.TypeInit(&TypeInstance{gtype: gtype, gotype: elem}) elem.TypeInit(&TypeInstance{gtype: gtype, gotype: elem})
// fmt.Printf("Registering %v to type %v\n", reflect.TypeOf(elem).String(), gtype)
registeredTypes[reflect.TypeOf(elem).String()] = gtype registeredTypes[reflect.TypeOf(elem).String()] = gtype
return gtype return gtype
} }

View File

@@ -8,7 +8,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst" "github.com/tinyzimmer/go-gst/gst"
) )

View File

@@ -2,7 +2,7 @@ package gst
/* /*
#cgo pkg-config: gstreamer-1.0 #cgo pkg-config: gstreamer-1.0
#cgo CFLAGS: -Wno-deprecated-declarations -g -Wall #cgo CFLAGS: -Wno-deprecated-declarations -Wno-format-security -g -Wall
#cgo LDFLAGS: -lm #cgo LDFLAGS: -lm
*/ */
import "C" import "C"

View File

@@ -13,7 +13,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/gotk3/gotk3/glib" "github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst" "github.com/tinyzimmer/go-gst/gst"
) )

View File

@@ -35,7 +35,6 @@ gint infoWidth (GstVideoInfo * info)
*/ */
import "C" import "C"
import ( import (
"runtime"
"unsafe" "unsafe"
"github.com/tinyzimmer/go-gst/gst" "github.com/tinyzimmer/go-gst/gst"
@@ -164,10 +163,13 @@ type Info struct {
func wrapInfo(vinfo *C.GstVideoInfo) *Info { func wrapInfo(vinfo *C.GstVideoInfo) *Info {
info := &Info{vinfo} info := &Info{vinfo}
runtime.SetFinalizer(info, func(i *Info) { C.gst_video_info_free(vinfo) })
return info return info
} }
func (i *Info) Free() {
C.gst_video_info_free(i.instance())
}
// instance returns the underlying GstVideoInfo instance. // instance returns the underlying GstVideoInfo instance.
func (i *Info) instance() *C.GstVideoInfo { return i.ptr } func (i *Info) instance() *C.GstVideoInfo { return i.ptr }