change clockTime type, add more bindings

This commit is contained in:
RSWilli
2023-08-11 14:39:32 +02:00
parent d0fc9e926a
commit ca1a83e57d
21 changed files with 400 additions and 206 deletions

View File

@@ -6,7 +6,6 @@ import (
"math"
"os"
"os/signal"
"time"
"github.com/go-gst/go-gst/examples"
"github.com/go-gst/go-gst/gst"
@@ -116,7 +115,7 @@ func mainLoop(pipeline *gst.Pipeline) error {
// Loop over messsages from the pipeline
for {
msg := bus.TimedPop(time.Duration(-1))
msg := bus.TimedPop(gst.ClockTimeNone)
if msg == nil {
break
}

View File

@@ -13,7 +13,6 @@ import (
"errors"
"fmt"
"math"
"time"
"github.com/go-gst/go-glib/glib"
"github.com/go-gst/go-gst/examples"
@@ -87,7 +86,7 @@ func padProbes(mainLoop *glib.MainLoop) error {
// Block on messages coming in from the bus instead of using the main loop
for {
msg := pipeline.GetPipelineBus().TimedPop(time.Duration(-1))
msg := pipeline.GetPipelineBus().TimedPop(gst.ClockTimeNone)
if msg == nil {
break
}

View File

@@ -23,7 +23,6 @@ package main
import (
"fmt"
"time"
"github.com/go-gst/go-gst/examples"
"github.com/go-gst/go-gst/gst"
@@ -65,7 +64,7 @@ func tagsetter() error {
var cont bool
var pipelineErr error
for {
msg := pipeline.GetPipelineBus().TimedPop(time.Duration(-1))
msg := pipeline.GetPipelineBus().TimedPop(gst.ClockTimeNone)
if msg == nil {
break
}

View File

@@ -87,7 +87,7 @@ func tagsetter(mainLoop *glib.MainLoop) error {
// timed_pop on the bus with the desired timeout for when to stop waiting for new messages.
// (-1 = Wait forever)
for {
msg := pipeline.GetPipelineBus().TimedPop(time.Duration(-1))
msg := pipeline.GetPipelineBus().TimedPop(gst.ClockTimeNone)
switch msg.Type() {
// When we use this method of popping from the bus (instead of a Watch), we own a

View File

@@ -18,7 +18,6 @@ gboolean cgoSeekDataCb (GstAppSrc *src, guint64 offset, gpointer user_data) {
*/
import "C"
import (
"time"
"unsafe"
"github.com/go-gst/go-gst/gst"
@@ -91,12 +90,10 @@ func (a *Source) GetCurrentLevelBytes() uint64 {
var gstClockTimeNone C.GstClockTime = 0xffffffffffffffff
// 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() gst.ClockTime {
dur := C.gst_app_src_get_duration(a.Instance())
if dur == gstClockTimeNone {
return gst.ClockTimeNone
}
return time.Duration(uint64(dur)) * time.Nanosecond
return gst.ClockTime(dur)
}
// GetEmitSignals checks if appsrc will emit the "new-preroll" and "new-buffer" signals.
@@ -189,8 +186,8 @@ func (a *Source) SetCaps(caps *gst.Caps) {
// SetDuration sets the duration of the source stream. You should call
// this if the value is known.
func (a *Source) SetDuration(dur time.Duration) {
C.gst_app_src_set_duration((*C.GstAppSrc)(a.Instance()), C.GstClockTime(dur.Nanoseconds()))
func (a *Source) SetDuration(dur gst.ClockTime) {
C.gst_app_src_set_duration((*C.GstAppSrc)(a.Instance()), C.GstClockTime(dur))
}
// SetEmitSignals makes appsrc emit the "new-preroll" and "new-buffer" signals. This option is by default disabled because signal emission

View File

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

View File

@@ -38,18 +38,11 @@ const (
type ClockTimeDiff int64
// ClockTimeNone means infinite timeout or an empty value
var ClockTimeNone time.Duration = time.Duration(-1)
var ClockTimeNone ClockTime = C.GST_CLOCK_TIME_NONE
// 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.
gstClockTimeNone C.GstClockTime = 0xffffffffffffffff
// // BufferOffsetNone is a constant for no-offset return results.
// gstBufferOffsetNone C.GstClockTime = 0xffffffffffffffff
)
// ClockEntryType wraps GstClockEntryType
type ClockEntryType int

30
gst/control_binding.go Normal file
View File

@@ -0,0 +1,30 @@
package gst
// #include "gst.go.h"
import "C"
import (
"unsafe"
"github.com/go-gst/go-glib/glib"
)
type ControlBinding struct{ *Object }
func (cb *ControlBinding) Instance() *C.GstControlBinding {
return C.toGstControlBinding(cb.Unsafe())
}
type DirectControlBinding struct{ ControlBinding }
func NewDirectControlBinding(obj *Object, prop string, csource *InterpolationControlSource) *DirectControlBinding {
cprop := C.CString(prop)
defer C.free(unsafe.Pointer(cprop))
cbinding := C.gst_direct_control_binding_new(obj.Instance(), cprop, csource.Instance())
return &DirectControlBinding{
ControlBinding: ControlBinding{
Object: wrapObject(glib.TransferNone(unsafe.Pointer(cbinding))),
},
}
}

27
gst/control_source.go Normal file
View File

@@ -0,0 +1,27 @@
package gst
// #include "gst.go.h"
import "C"
import (
"unsafe"
"github.com/go-gst/go-glib/glib"
)
type InterpolationControlSource struct{ *Object }
func (cs *InterpolationControlSource) Instance() *C.GstControlSource {
return C.toGstControlSource(cs.Unsafe())
}
func NewInterpolationControlSource() *InterpolationControlSource {
cCs := C.gst_interpolation_control_source_new()
return &InterpolationControlSource{
Object: wrapObject(glib.TransferNone(unsafe.Pointer(cCs))),
}
}
func (cs *InterpolationControlSource) SetTimedValue(time ClockTime, value float64) {
C.gst_timed_value_control_source_set(C.toGstTimedValueControlSource(cs.Unsafe()), C.ulong(time), C.double(value))
}

View File

@@ -42,6 +42,9 @@ GstTask * toGstTask (void *p) { return (GST_TASK_CAST(
GstTaskPool * toGstTaskPool (void *p) { return (GST_TASK_POOL_CAST(p)); }
GstURIHandler * toGstURIHandler (void *p) { return (GST_URI_HANDLER(p)); }
GstUri * toGstURI (void *p) { return (GST_URI(p)); }
GstControlBinding * toGstControlBinding (void *p) { return (GST_CONTROL_BINDING(p)); }
GstControlSource * toGstControlSource (void *p) { return (GST_CONTROL_SOURCE(p)); }
GstTimedValueControlSource * toGstTimedValueControlSource (void *p) { return (GST_TIMED_VALUE_CONTROL_SOURCE(p)); }
/* Buffer Utilities */

View File

@@ -4,6 +4,8 @@
#include <stdlib.h>
#include <gst/gst.h>
#include <gst/base/base.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/controller/gstdirectcontrolbinding.h>
typedef struct _PadDestroyNotifyInfo {
gpointer pad_ptr;
@@ -56,6 +58,9 @@ extern GstTask * toGstTask (void *p);
extern GstTaskPool * toGstTaskPool (void *p);
extern GstURIHandler * toGstURIHandler (void *p);
extern GstUri * toGstURI (void *p);
extern GstControlBinding * toGstControlBinding (void *p);
extern GstControlSource * toGstControlSource (void *p);
extern GstTimedValueControlSource * toGstTimedValueControlSource (void *p);
/* Buffer Utilities */

View File

@@ -176,12 +176,10 @@ func (b *Buffer) Bytes() []byte {
// PresentationTimestamp returns the presentation timestamp of the buffer, or a negative duration
// if not known or relevant. This value contains the timestamp when the media should be
// presented to the user.
func (b *Buffer) PresentationTimestamp() time.Duration {
func (b *Buffer) PresentationTimestamp() ClockTime {
pts := b.Instance().pts
if pts == gstClockTimeNone {
return ClockTimeNone
}
return time.Duration(pts)
return ClockTime(pts)
}
// SetPresentationTimestamp sets the presentation timestamp on the buffer.
@@ -192,22 +190,18 @@ func (b *Buffer) SetPresentationTimestamp(dur time.Duration) {
// 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.
func (b *Buffer) DecodingTimestamp() time.Duration {
func (b *Buffer) DecodingTimestamp() ClockTime {
dts := b.Instance().dts
if dts == gstClockTimeNone {
return ClockTimeNone
}
return time.Duration(dts)
return ClockTime(dts)
}
// Duration returns the length of the data inside this buffer, or a negative duration if not known
// or relevant.
func (b *Buffer) Duration() time.Duration {
func (b *Buffer) Duration() ClockTime {
dur := b.Instance().duration
if dur == gstClockTimeNone {
return ClockTimeNone
}
return time.Duration(dur)
return ClockTime(dur)
}
// SetDuration sets the duration on the buffer.
@@ -287,7 +281,7 @@ func (b *Buffer) AddProtectionMeta(info *Structure) *ProtectionMeta {
type ReferenceTimestampMeta struct {
Parent *Meta
Reference *Caps
Timestamp, Duration time.Duration
Timestamp, Duration ClockTime
}
// AddReferenceTimestampMeta adds a ReferenceTimestampMeta to this buffer that holds a
@@ -295,21 +289,16 @@ type ReferenceTimestampMeta struct {
//
// See the documentation of GstReferenceTimestampMeta for details.
// https://gstreamer.freedesktop.org/documentation/gstreamer/gstbuffer.html?gi-language=c#GstReferenceTimestampMeta
func (b *Buffer) AddReferenceTimestampMeta(ref *Caps, timestamp, duration time.Duration) *ReferenceTimestampMeta {
durClockTime := C.GstClockTime(ClockTimeNone)
if duration > time.Duration(0) {
durClockTime = C.GstClockTime(duration.Nanoseconds())
}
tsClockTime := C.GstClockTime(timestamp.Nanoseconds())
meta := C.gst_buffer_add_reference_timestamp_meta(b.Instance(), ref.Instance(), tsClockTime, durClockTime)
func (b *Buffer) AddReferenceTimestampMeta(ref *Caps, timestamp, duration ClockTime) *ReferenceTimestampMeta {
meta := C.gst_buffer_add_reference_timestamp_meta(b.Instance(), ref.Instance(), C.GstClockTime(timestamp), C.GstClockTime(duration))
if meta == nil {
return nil
}
return &ReferenceTimestampMeta{
Parent: wrapMeta(&meta.parent),
Reference: wrapCaps(meta.reference),
Timestamp: time.Duration(meta.timestamp),
Duration: time.Duration(meta.duration),
Timestamp: ClockTime(meta.timestamp),
Duration: ClockTime(meta.duration),
}
}
@@ -502,8 +491,8 @@ func (b *Buffer) GetReferenceTimestampMeta(caps *Caps) *ReferenceTimestampMeta {
}
refMeta := &ReferenceTimestampMeta{
Parent: wrapMeta(&meta.parent),
Timestamp: time.Duration(meta.timestamp),
Duration: time.Duration(meta.duration),
Timestamp: ClockTime(meta.timestamp),
Duration: ClockTime(meta.duration),
}
if meta.reference != nil {
refMeta.Reference = wrapCaps(meta.reference)

View File

@@ -97,8 +97,8 @@ func (b *Bus) AddSignalWatch() { C.gst_bus_add_signal_watch(b.Instance()) }
//
// It is much safer and easier to use the AddWatch or other polling functions. Only use this method if you
// are unable to also run a MainLoop, or for convenience sake.
func (b *Bus) PopMessage(timeout int) *Message {
return b.TimedPop(time.Duration(timeout) * time.Second)
func (b *Bus) PopMessage(timeout ClockTime) *Message {
return b.TimedPop(timeout)
}
// BlockPopMessage blocks until a message is available on the bus and then returns it.
@@ -315,15 +315,9 @@ func (b *Bus) SetSyncHandler(f BusSyncHandler) {
// TimedPop gets a message from the bus, waiting up to the specified timeout. Unref returned messages after usage.
//
// 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 {
var cTime C.GstClockTime
if dur == ClockTimeNone {
cTime = C.GstClockTime(gstClockTimeNone)
} else {
cTime = C.GstClockTime(dur.Nanoseconds())
}
msg := C.gst_bus_timed_pop(b.Instance(), cTime)
// If timeout is 0, this function behaves like Pop. If timeout is ClockTimeNone, this function will block forever until a message was posted on the bus.
func (b *Bus) TimedPop(dur ClockTime) *Message {
msg := C.gst_bus_timed_pop(b.Instance(), C.GstClockTime(dur))
if msg == nil {
return nil
}
@@ -333,16 +327,10 @@ func (b *Bus) TimedPop(dur time.Duration) *Message {
// TimedPopFiltered gets a message from the bus whose type matches the message type mask types, waiting up to the specified timeout
// (and discarding any messages that do not match the mask provided).
//
// If timeout is 0, this function behaves like PopFiltered. If timeout is < 0, this function will block forever until a matching message
// If timeout is 0, this function behaves like PopFiltered. If timeout is ClockTimeNone, this function will block forever until a matching message
// was posted on the bus.
func (b *Bus) TimedPopFiltered(dur time.Duration, msgTypes MessageType) *Message {
var cTime C.GstClockTime
if dur == ClockTimeNone {
cTime = C.GstClockTime(gstClockTimeNone)
} else {
cTime = C.GstClockTime(dur.Nanoseconds())
}
msg := C.gst_bus_timed_pop_filtered(b.Instance(), cTime, C.GstMessageType(msgTypes))
func (b *Bus) TimedPopFiltered(dur ClockTime, msgTypes MessageType) *Message {
msg := C.gst_bus_timed_pop_filtered(b.Instance(), C.GstClockTime(dur), C.GstMessageType(msgTypes))
if msg == nil {
return nil
}

View File

@@ -20,6 +20,7 @@ void clockDestroyNotify (gpointer user_data)
import "C"
import (
"fmt"
"runtime"
"time"
"unsafe"
@@ -28,8 +29,28 @@ import (
gopointer "github.com/mattn/go-pointer"
)
type ClockTime C.GstClockTime
func (ct ClockTime) String() string {
if ct == ClockTimeNone {
return "ClockTimeNone"
}
return fmt.Sprint(uint64(ct))
}
func (ct ClockTime) AsDuration() *time.Duration {
if ct == ClockTimeNone {
return nil
}
dur := time.Duration(uint64(ct))
return &dur
}
// ClockCallback is the prototype of a clock callback function.
type ClockCallback func(clock *Clock, clockTime time.Duration) bool
type ClockCallback func(clock *Clock, clockTime ClockTime) bool
// ClockID is a go wrapper around a GstClockID.
type ClockID struct {
@@ -46,8 +67,8 @@ func (c *ClockID) GetClock() *Clock {
}
// GetTime returns the time for this ClockID
func (c *ClockID) GetTime() time.Duration {
return time.Duration(C.gst_clock_id_get_time(c.Instance()))
func (c *ClockID) GetTime() ClockTime {
return ClockTime(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.
@@ -89,7 +110,7 @@ func (c *ClockID) Wait() (ret ClockReturn, jitter ClockTimeDiff) {
//
// id := clock.NewSingleShotID(gst.ClockTime(1000000000)) // 1 second
//
// id.WaitAsync(func(clock *gst.Clock, clockTime time.Duration) bool {
// id.WaitAsync(func(clock *gst.Clock, clockTime ClockTime) bool {
// fmt.Println("Single shot triggered at", clockTime.Nanoseconds())
// pipeline.SetState(gst.StateNull)
// return true
@@ -143,7 +164,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
// 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 time.Duration) (bool, float64) {
func (c *Clock) AddObservation(slaveTime, masterTime ClockTime) (bool, float64) {
var out C.gdouble
ok := gobool(C.gst_clock_add_observation(
c.Instance(),
@@ -158,7 +179,7 @@ func (c *Clock) AddObservation(slaveTime, masterTime time.Duration) (bool, float
// 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.
func (c *Clock) AddObservationUnapplied(slaveTime, masterTime time.Duration) (ok bool, rSquared float64, internalTime, externalTime, rateNum, rateDenom time.Duration) {
func (c *Clock) AddObservationUnapplied(slaveTime, masterTime ClockTime) (ok bool, rSquared float64, internalTime, externalTime, rateNum, rateDenom ClockTime) {
var ginternal, gexternal, grateNum, grateDenom C.GstClockTime
var grSquared C.gdouble
ok = gobool(C.gst_clock_add_observation_unapplied(
@@ -167,7 +188,7 @@ func (c *Clock) AddObservationUnapplied(slaveTime, masterTime time.Duration) (ok
C.GstClockTime(masterTime),
&grSquared, &ginternal, &gexternal, &grateNum, &grateDenom,
))
return ok, float64(grSquared), time.Duration(ginternal), time.Duration(gexternal), time.Duration(grateNum), time.Duration(grateDenom)
return ok, float64(grSquared), ClockTime(ginternal), ClockTime(gexternal), ClockTime(grateNum), ClockTime(grateDenom)
}
// AdjustUnlocked converts the given internal clock time to the external time, adjusting for the rate and reference time set with
@@ -175,8 +196,8 @@ func (c *Clock) AddObservationUnapplied(slaveTime, masterTime time.Duration) (ok
// held and is mainly used by clock subclasses.
//
// This function is the reverse of UnadjustUnlocked.
func (c *Clock) AdjustUnlocked(internal time.Duration) time.Duration {
return time.Duration(C.gst_clock_adjust_unlocked(c.Instance(), C.GstClockTime(internal)))
func (c *Clock) AdjustUnlocked(internal ClockTime) ClockTime {
return ClockTime(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.
@@ -184,8 +205,8 @@ func (c *Clock) AdjustUnlocked(internal time.Duration) time.Duration {
// doesn't ensure a monotonically increasing result as AdjustUnlocked does.
//
// See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstclock.html#gst_clock_adjust_with_calibration
func (c *Clock) AdjustWithCalibration(internalTarget, cinternal, cexternal, cnum, cdenom time.Duration) time.Duration {
return time.Duration(C.gst_clock_adjust_with_calibration(
func (c *Clock) AdjustWithCalibration(internalTarget, cinternal, cexternal, cnum, cdenom ClockTime) ClockTime {
return ClockTime(C.gst_clock_adjust_with_calibration(
c.Instance(),
C.GstClockTime(internalTarget),
C.GstClockTime(cinternal),
@@ -196,30 +217,26 @@ 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.
func (c *Clock) GetCalibration() (internal, external, rateNum, rateDenom time.Duration) {
func (c *Clock) GetCalibration() (internal, external, rateNum, rateDenom ClockTime) {
var ginternal, gexternal, grateNum, grateDenom C.GstClockTime
C.gst_clock_get_calibration(c.Instance(), &ginternal, &gexternal, &grateNum, &grateDenom)
return time.Duration(ginternal), time.Duration(gexternal), time.Duration(grateNum), time.Duration(grateDenom)
return ClockTime(ginternal), ClockTime(gexternal), ClockTime(grateNum), ClockTime(grateDenom)
}
// 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.
func (c *Clock) GetTime() time.Duration {
func (c *Clock) GetTime() ClockTime {
res := C.gst_clock_get_time(c.Instance())
if res == gstClockTimeNone {
return ClockTimeNone
}
return time.Duration(res)
return ClockTime(res)
}
// 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.
func (c *Clock) GetInternalTime() time.Duration {
func (c *Clock) GetInternalTime() ClockTime {
res := C.gst_clock_get_internal_time(c.Instance())
if res == gstClockTimeNone {
return ClockTimeNone
}
return time.Duration(res)
return ClockTime(res)
}
// GetMaster returns the master clock that this clock is slaved to or nil when the clock
@@ -234,13 +251,13 @@ func (c *Clock) GetMaster() *Clock {
// GetResolution gets the accuracy of the clock. The accuracy of the clock is the granularity
// of the values returned by GetTime.
func (c *Clock) GetResolution() time.Duration {
return time.Duration(C.gst_clock_get_resolution(c.Instance()))
func (c *Clock) GetResolution() ClockTime {
return ClockTime(C.gst_clock_get_resolution(c.Instance()))
}
// GetTimeout gets the amount of time that master and slave clocks are sampled.
func (c *Clock) GetTimeout() time.Duration {
return time.Duration(C.gst_clock_get_timeout(c.Instance()))
func (c *Clock) GetTimeout() ClockTime {
return ClockTime(C.gst_clock_get_timeout(c.Instance()))
}
// IsSynced returns true if the clock is synced.
@@ -248,7 +265,7 @@ 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
// 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 time.Duration) *ClockID {
func (c *Clock) NewPeriodicID(startTime, interval ClockTime) *ClockID {
id := C.gst_clock_new_periodic_id(
c.Instance(),
C.GstClockTime(startTime),
@@ -261,7 +278,7 @@ func (c *Clock) NewPeriodicID(startTime, interval time.Duration) *ClockID {
// 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.
func (c *Clock) NewSingleShotID(at time.Duration) *ClockID {
func (c *Clock) NewSingleShotID(at ClockTime) *ClockID {
id := C.gst_clock_new_single_shot_id(
c.Instance(),
C.GstClockTime(at),
@@ -273,7 +290,7 @@ func (c *Clock) NewSingleShotID(at time.Duration) *ClockID {
// PeriodicIDReinit reinitializes the provided periodic id to the provided start time and interval. Does not
// / modify the reference count.
func (c *Clock) PeriodicIDReinit(clockID *ClockID, startTime, interval time.Duration) bool {
func (c *Clock) PeriodicIDReinit(clockID *ClockID, startTime, interval ClockTime) bool {
return gobool(C.gst_clock_periodic_id_reinit(
c.Instance(),
clockID.Instance(),
@@ -284,7 +301,7 @@ func (c *Clock) PeriodicIDReinit(clockID *ClockID, startTime, interval time.Dura
// SetCalibration adjusts the rate and time of clock.
// See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstclock.html#gst_clock_set_calibration.
func (c *Clock) SetCalibration(internal, external, rateNum, rateDenom time.Duration) {
func (c *Clock) SetCalibration(internal, external, rateNum, rateDenom ClockTime) {
C.gst_clock_set_calibration(
c.Instance(),
C.GstClockTime(internal),
@@ -311,8 +328,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
// 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.
func (c *Clock) SetResolution(resolution time.Duration) time.Duration {
return time.Duration(C.gst_clock_set_resolution(c.Instance(), C.GstClockTime(resolution)))
func (c *Clock) SetResolution(resolution ClockTime) ClockTime {
return ClockTime(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.
@@ -322,12 +339,12 @@ func (c *Clock) SetResolution(resolution time.Duration) time.Duration {
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
func (c *Clock) SetTimeout(timeout time.Duration) {
func (c *Clock) SetTimeout(timeout ClockTime) {
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.
func (c *Clock) SingleShotIDReinit(clockID *ClockID, at time.Duration) bool {
func (c *Clock) SingleShotIDReinit(clockID *ClockID, at ClockTime) bool {
return gobool(C.gst_clock_single_shot_id_reinit(c.Instance(), clockID.Instance(), C.GstClockTime(at)))
}
@@ -335,14 +352,14 @@ func (c *Clock) SingleShotIDReinit(clockID *ClockID, at time.Duration) bool {
// 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.
func (c *Clock) UnadjustUnlocked(external time.Duration) time.Duration {
return time.Duration(C.gst_clock_unadjust_unlocked(c.Instance(), C.GstClockTime(external)))
func (c *Clock) UnadjustUnlocked(external ClockTime) ClockTime {
return ClockTime(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.
// This function performs the same calculation as UnadjustUnlocked when called using the current calibration parameters.
func (c *Clock) UnadjustWithCalibration(externalTarget, cinternal, cexternal, cnum, cdenom time.Duration) time.Duration {
return time.Duration(C.gst_clock_unadjust_with_calibration(
func (c *Clock) UnadjustWithCalibration(externalTarget, cinternal, cexternal, cnum, cdenom ClockTime) ClockTime {
return ClockTime(C.gst_clock_unadjust_with_calibration(
c.Instance(),
C.GstClockTime(externalTarget),
C.GstClockTime(cinternal),
@@ -358,12 +375,12 @@ func (c *Clock) UnadjustWithCalibration(externalTarget, cinternal, cexternal, cn
// 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.
func (c *Clock) WaitForSync(timeout time.Duration) bool {
func (c *Clock) WaitForSync(timeout ClockTime) bool {
return gobool(C.gst_clock_wait_for_sync(c.Instance(), C.GstClockTime(timeout)))
}
// String returns the string representation of this clock value.
func (c *Clock) String() string { return c.GetTime().String() }
func (c *Clock) String() string { return fmt.Sprintf("%d", c.GetTime()) }
// InternalString returns the string representation of this clock's internal value.
func (c *Clock) InternalString() string { return c.GetInternalTime().String() }
func (c *Clock) InternalString() string { return fmt.Sprintf("%d", c.GetInternalTime()) }

View File

@@ -520,3 +520,39 @@ func (e *Element) GetRequestPad(name string) *Pad {
func (e *Element) ReleaseRequestPad(pad *Pad) {
C.gst_element_release_request_pad(e.Instance(), pad.Instance())
}
// Set the start time of an element. The start time of the element is the running time of the element
// when it last went to the PAUSED state. In READY or after a flushing seek, it is set to 0.
//
// Toplevel elements like GstPipeline will manage the start_time and base_time on its children.
// Setting the start_time to GST_CLOCK_TIME_NONE on such a toplevel element will disable the distribution of the base_time
// to the children and can be useful if the application manages the base_time itself, for example if you want to synchronize
// capture from multiple pipelines, and you can also ensure that the pipelines have the same clock.
//
// MT safe.
func (e *Element) SetStartTime(startTime ClockTime) {
C.gst_element_set_start_time(e.Instance(), C.GstClockTime(startTime))
}
// Returns the start time of the element. The start time is the running time of the clock when this element was last put to PAUSED.
// Usually the start_time is managed by a toplevel element such as GstPipeline.
// MT safe.
func (e *Element) GetStartTime() ClockTime {
ctime := C.gst_element_get_start_time(e.Instance())
return ClockTime(ctime)
}
// Set the base time of an element. The base time is the absolute time of the clock
// when this element was last put to PLAYING. Subtracting the base time from the clock time gives the running time of the element.
func (e *Element) SetBaseTime(startTime ClockTime) {
C.gst_element_set_base_time(e.Instance(), C.GstClockTime(startTime))
}
// Returns the base time of the element. The base time is the absolute time of the clock
// when this element was last put to PLAYING. Subtracting the base time from the clock time gives the running time of the element.
func (e *Element) GetBaseTime() ClockTime {
ctime := C.gst_element_get_base_time(e.Instance())
return ClockTime(ctime)
}

View File

@@ -28,11 +28,52 @@ func NewElementWithName(factory string, name string) (*Element, error) {
elem = C.gst_element_factory_make((*C.gchar)(elemName), (*C.gchar)(cname))
}
if elem == nil {
return nil, fmt.Errorf("Could not create element: %s", factory)
return nil, fmt.Errorf("could not create element: %s", factory)
}
return wrapElement(glib.TransferNone(unsafe.Pointer(elem))), nil
}
// Create a new element of the type defined by the given elementfactory. The supplied list of properties, will be passed at object construction.
//
// using this results in a free() panic :( DO NOT USE
func NewElementWithProperties(factory string, properties map[string]interface{}) (*Element, error) {
props := make([]*C.char, 0)
values := make([]C.GValue, 0)
for p, v := range properties {
cpropName := C.CString(p)
defer C.free(unsafe.Pointer(cpropName))
props = append(props, cpropName)
cValue, err := glib.GValue(v)
if err != nil {
return nil, err
}
values = append(values, *(*C.GValue)(cValue.Unsafe()))
}
cfactory := C.CString(factory)
defer C.free(unsafe.Pointer(cfactory))
n := C.uint(len(properties))
var elem *C.GstElement
if n > 0 {
elem = C.gst_element_factory_make_with_properties(cfactory, n, &props[0], &values[0])
} else {
elem = C.gst_element_factory_make_with_properties(cfactory, n, nil, nil)
}
if elem == nil {
return nil, fmt.Errorf("could not create element: %s", factory)
}
return wrapElement(glib.TransferFull(unsafe.Pointer(elem))), nil
}
// NewElementMany is a convenience wrapper around building many GstElements in a
// single function call. It returns an error if the creation of any element fails. A
// slice in the order the names were given is returned.

View File

@@ -34,20 +34,15 @@ func NewApplicationMessage(src interface{}, structure *Structure) *Message {
// RunningTime contains the time of the desired running time when this elements goes to PLAYING.
// A value less than 0 for runningTime means that the element has no clock interaction and thus doesn't
// care about the running time of the pipeline.
func NewAsyncDoneMessage(src interface{}, runningTime time.Duration) *Message {
func NewAsyncDoneMessage(src interface{}, runningTime ClockTime) *Message {
srcObj := getMessageSourceObj(src)
if srcObj == nil {
return nil
}
var cTime C.GstClockTime
if runningTime.Nanoseconds() < 0 {
cTime = C.GstClockTime(gstClockTimeNone)
} else {
cTime = C.GstClockTime(runningTime.Nanoseconds())
}
return FromGstMessageUnsafeFull(unsafe.Pointer(C.gst_message_new_async_done(
srcObj,
cTime,
C.GstClockTime(runningTime),
)))
}

View File

@@ -93,3 +93,7 @@ func (o *Object) Ref() *Object {
func (o *Object) Unref() {
C.gst_object_unref((C.gpointer)(o.Unsafe()))
}
func (o *Object) AddControlBinding(binding *ControlBinding) {
C.gst_object_add_control_binding(o.Instance(), binding.Instance())
}

View File

@@ -78,6 +78,15 @@ func (p *Pipeline) GetPipelineClock() *Clock {
return FromGstClockUnsafeFull(unsafe.Pointer(cClock))
}
// Force pipeline to use the given clock. The pipeline will always use the given clock even if new clock providers are added to this pipeline.
//
// If clock is NULL all clocking will be disabled which will make the pipeline run as fast as possible.
//
// MT safe.
func (p *Pipeline) ForceClock(clock *Clock) {
C.gst_pipeline_use_clock(p.Instance(), clock.Instance())
}
/*
SetAutoFlushBus can be used to disable automatically flushing the message bus
when a pipeline goes to StateNull.

View File

@@ -0,0 +1,64 @@
package gstnet
// #include "gst.go.h"
import "C"
import (
"context"
"errors"
"time"
"unsafe"
"github.com/go-gst/go-gst/gst"
)
// NTP timestamps are realtive to 1. Jan 1900, so we need an offset for 70 Years to be Unix TS compatible
const NTPTimeToUnixEpoch = gst.ClockTime(2208988800 * time.Second)
// NTPClock wraps GstClock
type NTPClock struct{ *gst.Clock }
// ObtainNTPClock returns the default NTPClock. The refcount of the clock will be
// increased so you need to unref the clock after usage.
func ObtainNTPClock(ctx context.Context, name, address string, port int) (*NTPClock, error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
caddr := C.CString(address)
defer C.free(unsafe.Pointer(caddr))
currentSystemTime := time.Now().UnixNano() + int64(NTPTimeToUnixEpoch)
ntpC := &NTPClock{gst.FromGstClockUnsafeFull(unsafe.Pointer(C.gst_ntp_clock_new(cname, caddr, C.gint(port), C.GstClockTime(currentSystemTime))))}
for {
select {
case <-ctx.Done():
return nil, errors.New("timeout reached while trying to sync")
default:
if ntpC.IsSynced() {
return ntpC, nil
}
time.Sleep(100 * time.Millisecond)
}
}
}
// get the current time of the clock
//
// if you want to access the clocks actual time value, use the underlying NTPClock.Clock.GetTime() instead
func (ntp *NTPClock) GetTime() time.Time {
// nanos since 1. Jan 1900
ntpNanos := NTPClockTime(ntp.Clock.GetTime())
return ntpNanos.ToDate()
}
type NTPClockTime gst.ClockTime
func (ct NTPClockTime) ToDate() time.Time {
return time.Unix(0, int64(ct)-int64(NTPTimeToUnixEpoch))
}
func NewNTPClockTime(t time.Time) NTPClockTime {
return NTPClockTime(t.UnixNano() + int64(NTPTimeToUnixEpoch))
}

View File

@@ -1,7 +1,7 @@
package gst
/*
#cgo pkg-config: gstreamer-1.0
#cgo pkg-config: gstreamer-1.0 gstreamer-controller-1.0
#cgo CFLAGS: -Wno-deprecated-declarations -Wno-format-security -g -Wall -Wno-unused-variable
#cgo LDFLAGS: -lm
*/