diff --git a/examples/appsrc/main.go b/examples/appsrc/main.go index c148193..4dda389 100644 --- a/examples/appsrc/main.go +++ b/examples/appsrc/main.go @@ -76,7 +76,7 @@ func createPipeline() (*gst.Pipeline, error) { // For each frame we produce, we set the timestamp when it should be displayed // The autovideosink will use this information to display the frame at the right time. - buffer.SetPresentationTimestamp(time.Duration(i) * 500 * time.Millisecond) + buffer.SetPresentationTimestamp(gst.ClockTime(time.Duration(i) * 500 * time.Millisecond)) // Produce an image frame for this iteration. pixels := produceImageFrame(palette[i]) diff --git a/gst/app/gst_app_sink.go b/gst/app/gst_app_sink.go index cd5dcfc..5329846 100644 --- a/gst/app/gst_app_sink.go +++ b/gst/app/gst_app_sink.go @@ -19,7 +19,6 @@ import "C" import ( "errors" - "time" "unsafe" gopointer "github.com/mattn/go-pointer" @@ -205,8 +204,8 @@ func (a *Sink) SetWaitOnEOS(wait bool) { // If an EOS event was received before any buffers or the timeout expires, this function returns NULL. Use IsEOS () to check for the EOS condition. // // This function blocks until a preroll sample or EOS is received, the appsink element is set to the READY/NULL state, or the timeout expires. -func (a *Sink) TryPullPreroll(timeout time.Duration) *gst.Sample { - tm := C.GstClockTime(timeout.Nanoseconds()) +func (a *Sink) TryPullPreroll(timeout gst.ClockTime) *gst.Sample { + tm := C.GstClockTime(timeout) smpl := C.gst_app_sink_try_pull_preroll(a.Instance(), tm) if smpl == nil { return nil @@ -221,8 +220,8 @@ func (a *Sink) TryPullPreroll(timeout time.Duration) *gst.Sample { // consume a lot of memory, especially when dealing with raw video frames. // // If an EOS event was received before any buffers or the timeout expires, this function returns NULL. Use IsEOS () to check for the EOS condition. -func (a *Sink) TryPullSample(timeout time.Duration) *gst.Sample { - tm := C.GstClockTime(timeout.Nanoseconds()) +func (a *Sink) TryPullSample(timeout gst.ClockTime) *gst.Sample { + tm := C.GstClockTime(timeout) smpl := C.gst_app_sink_try_pull_sample(a.Instance(), tm) if smpl == nil { return nil diff --git a/gst/app/gst_app_src.go b/gst/app/gst_app_src.go index c62b2da..0d9e17d 100644 --- a/gst/app/gst_app_src.go +++ b/gst/app/gst_app_src.go @@ -87,8 +87,6 @@ func (a *Source) GetCurrentLevelBytes() uint64 { 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. func (a *Source) GetDuration() gst.ClockTime { dur := C.gst_app_src_get_duration(a.Instance()) diff --git a/gst/audio/c_util.go b/gst/audio/c_util.go index 301f49a..0ade800 100644 --- a/gst/audio/c_util.go +++ b/gst/audio/c_util.go @@ -12,18 +12,20 @@ clockTimeToFrames(GstClockTime ct, gint rate) { return GST_CLOCK_TIME_TO_FRAMES( GValue * audioUtilToGValue (guintptr p) { return (GValue*)(p); } */ import "C" -import "time" +import ( + "github.com/go-gst/go-gst/gst" +) -// FramesToDuration calculates the Clocktime (which is usually referred to as a time.Duration in the bindings) +// FramesToClockTime calculates the Clocktime // from the given frames and rate. -func FramesToDuration(frames, rate int) time.Duration { +func FramesToClockTime(frames, rate int) gst.ClockTime { ct := C.framesToClockTime(C.gint(frames), C.gint(rate)) - return time.Duration(ct) + return gst.ClockTime(ct) } // DurationToFrames calculates the number of frames from the given duration and sample rate. -func DurationToFrames(dur time.Duration, rate int) int { - return int(C.clockTimeToFrames(C.GstClockTime(dur.Nanoseconds()), C.gint(rate))) +func DurationToFrames(dur gst.ClockTime, rate int) int { + return int(C.clockTimeToFrames(C.GstClockTime(dur), C.gint(rate))) } // gboolean converts a go bool to a C.gboolean. diff --git a/gst/audio/gst_audio_info.go b/gst/audio/gst_audio_info.go index c784c84..2e3ba18 100644 --- a/gst/audio/gst_audio_info.go +++ b/gst/audio/gst_audio_info.go @@ -84,8 +84,7 @@ func (i *Info) Free() { C.gst_audio_info_free(i.ptr) } // Convert converts among various gst.Format types. This function handles gst.FormatBytes, gst.FormatTime, // and gst.FormatDefault. For raw audio, gst.FormatDefault corresponds to audio frames. This function can -// be used to handle pad queries of the type gst.QueryConvert. To provide a value from a time.Duration, use the -// Nanoseconds() method. +// be used to handle pad queries of the type gst.QueryConvert. func (i *Info) Convert(srcFmt gst.Format, srcVal int64, destFmt gst.Format) (int64, bool) { var out C.gint64 ret := C.gst_audio_info_convert( diff --git a/gst/base/gst_base_sink.go b/gst/base/gst_base_sink.go index 16a2a49..0d34a22 100644 --- a/gst/base/gst_base_sink.go +++ b/gst/base/gst_base_sink.go @@ -13,7 +13,6 @@ gboolean baseSinkParentEvent (GstBaseSink * sink, GstEvent * event) import "C" import ( - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -97,8 +96,8 @@ func (g *GstBaseSink) GetLastSample() *gst.Sample { } // GetLatency gets the currently configured latency. -func (g *GstBaseSink) GetLatency() time.Duration { - return time.Duration(C.gst_base_sink_get_latency(g.Instance())) +func (g *GstBaseSink) GetLatency() gst.ClockTime { + return gst.ClockTime(C.gst_base_sink_get_latency(g.Instance())) } // GetMaxBitrate gets the maximum amount of bits per second the sink will render. @@ -112,13 +111,13 @@ func (g *GstBaseSink) GetMaxLateness() int64 { } // GetProcessingDeadline gets the processing deadline of the sink. -func (g *GstBaseSink) GetProcessingDeadline() time.Duration { - return time.Duration(C.gst_base_sink_get_processing_deadline(g.Instance())) +func (g *GstBaseSink) GetProcessingDeadline() gst.ClockTime { + return gst.ClockTime(C.gst_base_sink_get_processing_deadline(g.Instance())) } // GetRenderDelay gets the render delay for the sink. -func (g *GstBaseSink) GetRenderDelay() time.Duration { - return time.Duration(C.gst_base_sink_get_render_delay(g.Instance())) +func (g *GstBaseSink) GetRenderDelay() gst.ClockTime { + return gst.ClockTime(C.gst_base_sink_get_render_delay(g.Instance())) } // SINCE 1.18 @@ -155,8 +154,8 @@ func (g *GstBaseSink) GetThrottleTime() uint64 { } // GetTsOffset gets the synchronization offset of sink. -func (g *GstBaseSink) GetTsOffset() time.Duration { - return time.Duration(C.gst_base_sink_get_ts_offset(g.Instance())) +func (g *GstBaseSink) GetTsOffset() gst.ClockTime { + return gst.ClockTime(C.gst_base_sink_get_ts_offset(g.Instance())) } // IsAsyncEnabled checks if the sink is currently configured to perform asynchronous state changes to PAUSED. @@ -190,11 +189,11 @@ func (g *GstBaseSink) ParentEvent(ev *gst.Event) bool { // by the upstream elements by setting the minLatency to a strictly positive value. // // This function is mostly used by subclasses. -func (g *GstBaseSink) QueryLatency() (ok, live, upstreamLive bool, minLatency, maxLatency time.Duration) { +func (g *GstBaseSink) QueryLatency() (ok, live, upstreamLive bool, minLatency, maxLatency gst.ClockTime) { var glive, gupLive C.gboolean var gmin, gmax C.GstClockTime ret := C.gst_base_sink_query_latency(g.Instance(), &glive, &gupLive, &gmin, &gmax) - return gobool(ret), gobool(glive), gobool(gupLive), time.Duration(gmin), time.Duration(gmax) + return gobool(ret), gobool(glive), gobool(gupLive), gst.ClockTime(gmin), gst.ClockTime(gmax) } // SetAsyncEnabled configures sink to perform all state changes asynchronously. When async is disabled, @@ -235,8 +234,8 @@ func (g *GstBaseSink) SetMaxLateness(maxLateness int64) { // for processing the buffer. This is added to the latency of live pipelines. // // This function is usually called by subclasses. -func (g *GstBaseSink) SetProcessingDeadline(deadline time.Duration) { - C.gst_base_sink_set_processing_deadline(g.Instance(), C.GstClockTime(deadline.Nanoseconds())) +func (g *GstBaseSink) SetProcessingDeadline(deadline gst.ClockTime) { + C.gst_base_sink_set_processing_deadline(g.Instance(), C.GstClockTime(deadline)) } // SetQoSEnabled configures sink to send Quality-of-Service events upstream. @@ -252,8 +251,8 @@ func (g *GstBaseSink) SetQoSEnabled(enabled bool) { // their latency to delay the rendering of their media. // // This function is usually called by subclasses. -func (g *GstBaseSink) SetRenderDelay(delay time.Duration) { - C.gst_base_sink_set_render_delay(g.Instance(), C.GstClockTime(delay.Nanoseconds())) +func (g *GstBaseSink) SetRenderDelay(delay gst.ClockTime) { + C.gst_base_sink_set_render_delay(g.Instance(), C.GstClockTime(delay)) } // SetSync configures sink to synchronize on the clock or not. When sync is FALSE, incoming samples will @@ -270,8 +269,8 @@ func (g *GstBaseSink) SetThrottleTime(throttle uint64) { // SetTsOffset adjusts the synchronization of sink with offset. A negative value will render buffers earlier // than their timestamp. A positive value will delay rendering. This function can be used to fix playback of // badly timestamped buffers. -func (g *GstBaseSink) SetTsOffset(offset time.Duration) { - C.gst_base_sink_set_ts_offset(g.Instance(), C.GstClockTimeDiff(offset.Nanoseconds())) +func (g *GstBaseSink) SetTsOffset(offset gst.ClockTimeDiff) { + C.gst_base_sink_set_ts_offset(g.Instance(), C.GstClockTimeDiff(offset)) } // Wait will wait for preroll to complete and will then block until timeout is reached. It is usually called by @@ -283,10 +282,10 @@ func (g *GstBaseSink) SetTsOffset(offset time.Duration) { // // The timeout argument should be the running_time of when the timeout should happen and will be adjusted with any // latency and offset configured in the sink. -func (g *GstBaseSink) Wait(timeout time.Duration) (ret gst.FlowReturn, jitter time.Duration) { +func (g *GstBaseSink) Wait(timeout gst.ClockTime) (ret gst.FlowReturn, jitter gst.ClockTimeDiff) { var jit C.GstClockTimeDiff - gret := C.gst_base_sink_wait(g.Instance(), C.GstClockTime(timeout.Nanoseconds()), &jit) - return gst.FlowReturn(gret), time.Duration(jit) + gret := C.gst_base_sink_wait(g.Instance(), C.GstClockTime(timeout), &jit) + return gst.FlowReturn(gret), gst.ClockTimeDiff(jit) } // WaitClock will block until timeout is reached. It is usually called by subclasses that use their own @@ -300,10 +299,10 @@ func (g *GstBaseSink) Wait(timeout time.Duration) (ret gst.FlowReturn, jitter ti // // The timeout argument should be the running_time of when this method should return and is not adjusted with any // latency or offset configured in the sink. -func (g *GstBaseSink) WaitClock(timeout time.Duration) (ret gst.ClockReturn, jitter time.Duration) { +func (g *GstBaseSink) WaitClock(timeout gst.ClockTime) (ret gst.ClockReturn, jitter gst.ClockTimeDiff) { var jit C.GstClockTimeDiff - gret := C.gst_base_sink_wait_clock(g.Instance(), C.GstClockTime(timeout.Nanoseconds()), &jit) - return gst.ClockReturn(gret), time.Duration(jit) + gret := C.gst_base_sink_wait_clock(g.Instance(), C.GstClockTime(timeout), &jit) + return gst.ClockReturn(gret), gst.ClockTimeDiff(jit) } // WaitPreroll will block until the preroll is complete. diff --git a/gst/base/gst_base_sink_exports.go b/gst/base/gst_base_sink_exports.go index c0683cb..92c5d6b 100644 --- a/gst/base/gst_base_sink_exports.go +++ b/gst/base/gst_base_sink_exports.go @@ -72,7 +72,7 @@ func goGstBaseSinkGetTimes(sink *C.GstBaseSink, buf *C.GstBuffer, start, end *C. var retStart, retEnd time.Duration glib.WithPointerTransferOriginal(unsafe.Pointer(sink), func(gObject *glib.Object, goObject glib.GoObjectSubclass) { iface := goObject.(interface { - GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration) + GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration) // should this be a ClockTime? }) retStart, retEnd = iface.GetTimes(ToGstBaseSink(gObject), gst.ToGstBuffer(unsafe.Pointer(buf))) }) diff --git a/gst/base/gst_base_sink_impl.go b/gst/base/gst_base_sink_impl.go index 1d5e356..6b56b70 100644 --- a/gst/base/gst_base_sink_impl.go +++ b/gst/base/gst_base_sink_impl.go @@ -85,7 +85,7 @@ type GstBaseSinkImpl interface { // Called to get sink pad caps from the subclass GetCaps(self *GstBaseSink, filter *gst.Caps) *gst.Caps // Called to get the start and end times for synchronising the passed buffer to the clock - GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration) + GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration) // should this be a ClockTime? // Called to prepare the buffer for render and preroll. This function is called before synchronization // is performed. Prepare(self *GstBaseSink, buffer *gst.Buffer) gst.FlowReturn @@ -155,7 +155,7 @@ func (e *extendsBaseSink) InitClass(klass unsafe.Pointer, elem glib.GoObjectSubc } if _, ok := elem.(interface { - GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration) + GetTimes(self *GstBaseSink, buffer *gst.Buffer) (start, end time.Duration) // should this be a ClockTime? }); ok { C.setGstBaseSinkGetTimes(sinkClass) } diff --git a/gst/base/gst_base_src.go b/gst/base/gst_base_src.go index 94d6069..8562497 100644 --- a/gst/base/gst_base_src.go +++ b/gst/base/gst_base_src.go @@ -6,7 +6,6 @@ package base import "C" import ( - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -90,12 +89,12 @@ func (g *GstBaseSrc) IsLive() bool { return gobool(C.gst_base_src_is_live(g.Inst // of the first buffer. // // This function is mostly used by subclasses. -func (g *GstBaseSrc) QueryLatency() (ok, live bool, minLatency, maxLatency time.Duration) { +func (g *GstBaseSrc) QueryLatency() (ok, live bool, minLatency, maxLatency gst.ClockTime) { var glive C.gboolean var gmin C.GstClockTime var gmax C.GstClockTime gok := C.gst_base_src_query_latency(g.Instance(), &glive, &gmin, &gmax) - return gobool(gok), gobool(glive), time.Duration(gmin), time.Duration(gmax) + return gobool(gok), gobool(glive), gst.ClockTime(gmin), gst.ClockTime(gmax) } // SetAsync configures async behaviour in src, no state change will block. The open, close, start, stop, play and diff --git a/gst/base/gst_base_src_exports.go b/gst/base/gst_base_src_exports.go index 5721dd9..1455917 100644 --- a/gst/base/gst_base_src_exports.go +++ b/gst/base/gst_base_src_exports.go @@ -106,7 +106,7 @@ func goGstBaseSrcGetTimes(src *C.GstBaseSrc, buf *C.GstBuffer, start *C.GstClock var gostart, goend time.Duration glib.WithPointerTransferOriginal(unsafe.Pointer(src), func(gObject *glib.Object, goObject glib.GoObjectSubclass) { iface := goObject.(interface { - GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration) + GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration) // should this be a ClockTime? }) gostart, goend = iface.GetTimes(ToGstBaseSrc(gObject), gst.ToGstBuffer(unsafe.Pointer(buf))) }) diff --git a/gst/base/gst_base_src_impl.go b/gst/base/gst_base_src_impl.go index fdfc67f..78878f4 100644 --- a/gst/base/gst_base_src_impl.go +++ b/gst/base/gst_base_src_impl.go @@ -81,7 +81,7 @@ type GstBaseSrcImpl interface { Stop(*GstBaseSrc) bool // GetTimes should, given a buffer, return start and stop time when it should be pushed. // The base class will sync on the clock using these times. - GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration) + GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration) // should this be a ClockTime? // GetSize should get the total size of the resource in bytes. GetSize(*GstBaseSrc) (bool, int64) // IsSeekable should check if the resource is seekable. @@ -166,7 +166,7 @@ func (e *extendsBaseSrc) InitClass(klass unsafe.Pointer, elem glib.GoObjectSubcl } if _, ok := elem.(interface { - GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration) + GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration) // should this be a ClockTime? }); ok { C.setGstBaseSrcGetTimes(class) } diff --git a/gst/base/gst_base_transform.go b/gst/base/gst_base_transform.go index 7198838..c77aafd 100644 --- a/gst/base/gst_base_transform.go +++ b/gst/base/gst_base_transform.go @@ -22,7 +22,6 @@ setGstBaseTransformTransformIPOnPassthrough (GstBaseTransform * obj, gboolean en import "C" import ( - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -179,12 +178,12 @@ func (g *GstBaseTransform) SrcPad() *gst.Pad { // // proportion is the proportion, diff is the diff against the clock, and timestamp is the timestamp of the buffer // generating the QoS expressed in running_time. -func (g *GstBaseTransform) UpdateQoS(proportion float64, diff, timestamp time.Duration) { +func (g *GstBaseTransform) UpdateQoS(proportion float64, diff, timestamp gst.ClockTime) { C.gst_base_transform_update_qos( g.Instance(), C.gdouble(proportion), - C.GstClockTimeDiff(diff.Nanoseconds()), - C.GstClockTime(timestamp.Nanoseconds()), + C.GstClockTimeDiff(diff), + C.GstClockTime(timestamp), ) } diff --git a/gst/base/gst_collect_pads.go b/gst/base/gst_collect_pads.go index 38ce61c..4e6249e 100644 --- a/gst/base/gst_collect_pads.go +++ b/gst/base/gst_collect_pads.go @@ -83,7 +83,7 @@ type CollectPadsClipFunc func(self *CollectPads, data *CollectData, inbuffer *gs // one pad. The function should return an integer less than zero when first timestamp is deemed older than the // second one. Zero if the timestamps are deemed equally old. Integer greater than zero when second timestamp // is deemed older than the first one. -type CollectPadsCompareFunc func(self *CollectPads, data1 *CollectData, ts1 time.Duration, data2 *CollectData, ts2 time.Duration) int +type CollectPadsCompareFunc func(self *CollectPads, data1 *CollectData, ts1 time.Duration, data2 *CollectData, ts2 time.Duration) int // should this be a ClockTime? // CollectPadsEventFunc is a function that will be called while processing an event. It takes ownership of the // event and is responsible for chaining up (to EventDefault) or dropping events (such typical cases being handled diff --git a/gst/constants.go b/gst/constants.go index 10f34c4..2c448ab 100644 --- a/gst/constants.go +++ b/gst/constants.go @@ -38,11 +38,13 @@ const ( // ClockTimeDiff is a datatype to hold a time difference, measured in nanoseconds. type ClockTimeDiff int64 -// ClockTimeNone means infinite timeout or an empty value -var ClockTimeNone ClockTime = 0xffffffffffffffff // Ideally this would be set to C.GST_CLOCK_TIME_NONE but this causes issues on MacOS and Windows +// convinience function to convert the diff to a time.Duration +func (ctd ClockTimeDiff) AsDuration() time.Duration { + return time.Duration(ctd) +} -// BufferOffsetNone is a var for no-offset return results. -var BufferOffsetNone time.Duration = time.Duration(-1) +// ClockTimeNone means infinite timeout or an empty value +const ClockTimeNone ClockTime = 0xffffffffffffffff // Ideally this would be set to C.GST_CLOCK_TIME_NONE but this causes issues on MacOS and Windows // ClockEntryType wraps GstClockEntryType type ClockEntryType int diff --git a/gst/gst_buffer.go b/gst/gst_buffer.go index 3c3a899..351011d 100644 --- a/gst/gst_buffer.go +++ b/gst/gst_buffer.go @@ -24,7 +24,6 @@ import ( "io" "io/ioutil" "runtime" - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -183,9 +182,9 @@ func (b *Buffer) PresentationTimestamp() ClockTime { } // SetPresentationTimestamp sets the presentation timestamp on the buffer. -func (b *Buffer) SetPresentationTimestamp(dur time.Duration) { +func (b *Buffer) SetPresentationTimestamp(dur ClockTime) { ins := b.Instance() - ins.pts = C.GstClockTime(dur.Nanoseconds()) + ins.pts = C.GstClockTime(dur) } // DecodingTimestamp returns the decoding timestamp of the buffer, or a negative duration if not known @@ -205,9 +204,9 @@ func (b *Buffer) Duration() ClockTime { } // SetDuration sets the duration on the buffer. -func (b *Buffer) SetDuration(dur time.Duration) { +func (b *Buffer) SetDuration(dur ClockTime) { ins := b.Instance() - ins.duration = C.GstClockTime(dur.Nanoseconds()) + ins.duration = C.GstClockTime(dur) } // Offset returns a media specific offset for the buffer data. For video frames, this is the frame @@ -358,10 +357,10 @@ func (b *Buffer) CopyInto(dest *Buffer, flags BufferCopyFlags, offset, size int6 // CopyRegion creates a sub-buffer from this one at offset and size. This sub-buffer uses the actual memory // space of the parent buffer. This function will copy the offset and timestamp fields when the offset is 0. -// If not, they will be set to ClockTimeNone and BufferOffsetNone. +// If not, they will be set to ClockTimeNone. // // If offset equals 0 and size equals the total size of buffer, the duration and offset end fields are also -// copied. If not they will be set to ClockTimeNone and BufferOffsetNone. +// copied. If not they will be set to ClockTimeNone. func (b *Buffer) CopyRegion(flags BufferCopyFlags, offset, size int64) *Buffer { newbuf := C.gst_buffer_copy_region( b.Instance(), diff --git a/gst/gst_bus.go b/gst/gst_bus.go index 4f2d37b..aec6f3d 100644 --- a/gst/gst_bus.go +++ b/gst/gst_bus.go @@ -21,7 +21,6 @@ import "C" import ( "reflect" - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -252,8 +251,8 @@ func (b *Bus) Peek() *Message { // // 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. -func (b *Bus) Poll(msgTypes MessageType, timeout time.Duration) *Message { - cTime := C.GstClockTime(timeout.Nanoseconds()) +func (b *Bus) Poll(msgTypes MessageType, timeout ClockTime) *Message { + cTime := C.GstClockTime(timeout) mType := C.GstMessageType(msgTypes) msg := C.gst_bus_poll(b.Instance(), mType, cTime) if msg == nil { diff --git a/gst/gst_clock.go b/gst/gst_clock.go index 9646e04..fc9fff5 100644 --- a/gst/gst_clock.go +++ b/gst/gst_clock.go @@ -39,6 +39,7 @@ func (ct ClockTime) String() string { return fmt.Sprint(uint64(ct)) } +// interpret the clocktime as a duration, returns nil on ClockTimeNone func (ct ClockTime) AsDuration() *time.Duration { if ct == ClockTimeNone { return nil @@ -49,6 +50,17 @@ func (ct ClockTime) AsDuration() *time.Duration { return &dur } +// interpret the clocktime as a timestamp, returns nil on ClockTimeNone +func (ct ClockTime) AsTimestamp() *time.Time { + if ct == ClockTimeNone { + return nil + } + + dur := time.Unix(0, int64(ct)) + + return &dur +} + // ClockCallback is the prototype of a clock callback function. type ClockCallback func(clock *Clock, clockTime ClockTime) bool diff --git a/gst/gst_element_exports.go b/gst/gst_element_exports.go index 1e63f03..476a22f 100644 --- a/gst/gst_element_exports.go +++ b/gst/gst_element_exports.go @@ -29,7 +29,7 @@ func goGstElementClassGetState(elem *C.GstElement, state, pending *C.GstState, t var ret StateChangeReturn glib.WithPointerTransferOriginal(unsafe.Pointer(elem), func(gobj *glib.Object, obj glib.GoObjectSubclass) { iface := obj.(interface { - GetState(*Element, time.Duration) (ret StateChangeReturn, current, pending State) + GetState(*Element, time.Duration) (ret StateChangeReturn, current, pending State) // should this be a ClockTime? }) var cur, pend State ret, cur, pend = iface.GetState(wrapElement(gobj), time.Duration(timeout)*time.Nanosecond) diff --git a/gst/gst_element_impl.go b/gst/gst_element_impl.go index c216a38..7e218cc 100644 --- a/gst/gst_element_impl.go +++ b/gst/gst_element_impl.go @@ -55,7 +55,7 @@ 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) + GetState(self *Element, timeout time.Duration) (ret StateChangeReturn, current, pending State) // should this also be a ClockTime? // NoMorePads is called when there are no more pads on the element. NoMorePads(*Element) // PadAdded is called to add a pad to the element. diff --git a/gst/gst_event.go b/gst/gst_event.go index b112c6d..19c4b7a 100644 --- a/gst/gst_event.go +++ b/gst/gst_event.go @@ -155,10 +155,10 @@ func (e *Event) ParseGroupID() (ok bool, gid uint) { // func (e *Event) ParseInstantRateChange() {} // ParseLatency gets the latency in the latency event. -func (e *Event) ParseLatency() time.Duration { +func (e *Event) ParseLatency() ClockTime { var out C.GstClockTime C.gst_event_parse_latency(e.Instance(), &out) - return time.Duration(out) + return ClockTime(out) } // ParseProtection parses an event containing protection system specific information and stores the results in @@ -182,7 +182,7 @@ func (e *Event) ParseProtection() (systemID string, data *Buffer, origin string) // the different QoS values. // // timestamp will be adjusted for any pad offsets of pads it was passing through. -func (e *Event) ParseQOS() (qTtype QOSType, proportion float64, diff ClockTimeDiff, timestamp time.Duration) { +func (e *Event) ParseQOS() (qTtype QOSType, proportion float64, diff ClockTimeDiff, timestamp ClockTime) { var gtype C.GstQOSType var gprop C.gdouble var gdiff C.GstClockTimeDiff @@ -191,7 +191,7 @@ func (e *Event) ParseQOS() (qTtype QOSType, proportion float64, diff ClockTimeDi e.Instance(), >ype, &gprop, &gdiff, >s, ) - return QOSType(gtype), float64(gprop), ClockTimeDiff(gdiff), time.Duration(gts) + return QOSType(gtype), float64(gprop), ClockTimeDiff(gdiff), ClockTime(gts) } // ParseSeek parses a seek event. @@ -207,10 +207,10 @@ func (e *Event) ParseSeek() (rate float64, format Format, flags SeekFlags, start // ParseSeekTrickModeInterval retrieves the trickmode interval that may have been set on a seek event with // SetSeekTrickModeInterval. -func (e *Event) ParseSeekTrickModeInterval() (interval time.Duration) { +func (e *Event) ParseSeekTrickModeInterval() (interval ClockTime) { var out C.GstClockTime C.gst_event_parse_seek_trickmode_interval(e.Instance(), &out) - return time.Duration(out) + return ClockTime(out) } // ParseSegment parses a segment event and stores the result in the given segment location. segment remains valid @@ -346,8 +346,8 @@ func (e *Event) SetRunningTimeOffset(offset int64) { // 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. -func (e *Event) SetSeekTrickModeInterval(interval time.Duration) { - C.gst_event_set_seek_trickmode_interval(e.Instance(), C.GstClockTime(interval.Nanoseconds())) +func (e *Event) SetSeekTrickModeInterval(interval ClockTime) { + C.gst_event_set_seek_trickmode_interval(e.Instance(), C.GstClockTime(interval)) } // SetSeqnum sets the sequence number of a event. diff --git a/gst/gst_event_constructors.go b/gst/gst_event_constructors.go index 6cab9e4..0057d63 100644 --- a/gst/gst_event_constructors.go +++ b/gst/gst_event_constructors.go @@ -4,7 +4,6 @@ package gst import "C" import ( - "time" "unsafe" ) @@ -67,10 +66,10 @@ func NewFlushStopEvent(resetTime bool) *Event { // NewGapEvent creates a new GAP event. A gap event can be thought of as conceptually equivalent to a buffer to signal that there is no data for a // certain amount of time. This is useful to signal a gap to downstream elements which may wait for data, such as muxers or mixers or overlays, // especially for sparse streams such as subtitle streams. -func NewGapEvent(timestamp, duration time.Duration) *Event { +func NewGapEvent(timestamp, duration ClockTime) *Event { return FromGstEventUnsafeFull(unsafe.Pointer(C.gst_event_new_gap( - C.GstClockTime(timestamp.Nanoseconds()), - C.GstClockTime(duration.Nanoseconds()), + C.GstClockTime(timestamp), + C.GstClockTime(duration), ))) } @@ -105,9 +104,9 @@ func NewGapEvent(timestamp, duration time.Duration) *Event { // running time before synchronising against the clock. // // 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 ClockTime) *Event { return FromGstEventUnsafeFull(unsafe.Pointer(C.gst_event_new_latency( - C.GstClockTime(latency.Nanoseconds()), + C.GstClockTime(latency), ))) } @@ -165,12 +164,12 @@ func NewProtectionEvent(systemID string, buffer *Buffer, origin string) *Event { // late in the sink as well. A (negative) diff value so that timestamp + diff would yield a result smaller than 0 is not allowed. // // The application can use general event probes to intercept the QoS event and implement custom application specific QoS handling. -func NewQOSEvent(qType QOSType, proportion float64, diff ClockTimeDiff, timestamp time.Duration) *Event { +func NewQOSEvent(qType QOSType, proportion float64, diff ClockTimeDiff, timestamp ClockTime) *Event { return FromGstEventUnsafeFull(unsafe.Pointer(C.gst_event_new_qos( C.GstQOSType(qType), C.gdouble(proportion), C.GstClockTimeDiff(diff), - C.GstClockTime(timestamp.Nanoseconds()), + C.GstClockTime(timestamp), ))) } diff --git a/gst/gst_message.go b/gst/gst_message.go index 814fcaa..3c79f11 100644 --- a/gst/gst_message.go +++ b/gst/gst_message.go @@ -189,10 +189,10 @@ func (m *Message) ParseStreamStatus() (StreamStatusType, *Element) { } // ParseAsyncDone extracts the running time from the async task done message. -func (m *Message) ParseAsyncDone() time.Duration { +func (m *Message) ParseAsyncDone() ClockTime { var clockTime C.GstClockTime C.gst_message_parse_async_done((*C.GstMessage)(m.Instance()), &clockTime) - return time.Duration(clockTime) + return ClockTime(clockTime) } // BufferingStats represents the buffering stats as retrieved from a GST_MESSAGE_TYPE_BUFFERING. @@ -357,13 +357,13 @@ type QoSValues struct { // If the message was generated by a live element Live bool // The running time of the buffer that generated the message - RunningTime time.Duration + RunningTime time.Duration // should this be a uint64? // The stream time of the buffer that generated the message - StreamTime time.Duration + StreamTime time.Duration // should this be a uint64? // The timestamps of the buffer that generated the message - Timestamp time.Duration + Timestamp time.Duration // should this be a uint64? // The duration of the buffer that generated the message - Duration time.Duration + Duration time.Duration // should this be a uint64? } // ParseQoS extracts the timestamps and live status from the QoS message. @@ -404,10 +404,10 @@ func (m *Message) ParseProgress() (progressType ProgressType, code, text string) } // ParseResetTime extracts the running-time from the ResetTime message. -func (m *Message) ParseResetTime() time.Duration { +func (m *Message) ParseResetTime() ClockTime { var clockTime C.GstClockTime C.gst_message_parse_reset_time((*C.GstMessage)(m.Instance()), &clockTime) - return time.Duration(clockTime) + return ClockTime(clockTime) } // ParseDeviceAdded parses a device-added message. The device-added message is diff --git a/gst/gst_message_constructors.go b/gst/gst_message_constructors.go index 86cc4e4..83d2e5c 100644 --- a/gst/gst_message_constructors.go +++ b/gst/gst_message_constructors.go @@ -3,7 +3,6 @@ package gst // #include "gst.go.h" import "C" import ( - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -315,7 +314,7 @@ func NewPropertyNotifyMessage(src interface{}, propName string, val interface{}) // // running_time, stream_time, timestamp, duration should be set to the respective running-time, stream-time, timestamp and duration of the (dropped) buffer // that generated the QoS event. Values can be left to less than zero when unknown. -func NewQoSMessage(src interface{}, live bool, runningTime, streamTime, timestamp, duration time.Duration) *Message { +func NewQoSMessage(src interface{}, live bool, runningTime, streamTime, timestamp, duration uint64) *Message { srcObj := getMessageSourceObj(src) if srcObj == nil { return nil @@ -323,10 +322,10 @@ func NewQoSMessage(src interface{}, live bool, runningTime, streamTime, timestam return FromGstMessageUnsafeFull(unsafe.Pointer(C.gst_message_new_qos( srcObj, gboolean(live), - C.guint64((runningTime.Nanoseconds())), - C.guint64((streamTime.Nanoseconds())), - C.guint64((timestamp.Nanoseconds())), - C.guint64((duration.Nanoseconds())), + C.guint64(runningTime), + C.guint64(streamTime), + C.guint64(timestamp), + C.guint64(duration), ))) } @@ -400,12 +399,12 @@ func NewRequestStateMessage(src interface{}, state State) *Message { } // NewResetTimeMessage creates a message that is posted when the pipeline running-time should be reset to running_time, like after a flushing seek. -func NewResetTimeMessage(src interface{}, runningTime time.Duration) *Message { +func NewResetTimeMessage(src interface{}, runningTime ClockTime) *Message { srcObj := getMessageSourceObj(src) if srcObj == nil { return nil } - return FromGstMessageUnsafeFull(unsafe.Pointer(C.gst_message_new_reset_time(srcObj, C.GstClockTime(runningTime.Nanoseconds())))) + return FromGstMessageUnsafeFull(unsafe.Pointer(C.gst_message_new_reset_time(srcObj, C.GstClockTime(runningTime)))) } // NewSegmentDoneMessage creates a new segment done message. This message is posted by elements that finish playback of a segment as a result of a @@ -462,7 +461,7 @@ func NewStateDirtyMessage(src interface{}) *Message { // complete step operation. // // Duration will contain the amount of time of the stepped amount of media in format format. -func NewStepDoneMessage(src interface{}, format Format, amount uint64, rate float64, flush, intermediate bool, duration time.Duration, eos bool) *Message { +func NewStepDoneMessage(src interface{}, format Format, amount uint64, rate float64, flush, intermediate bool, duration uint64, eos bool) *Message { srcObj := getMessageSourceObj(src) if srcObj == nil { return nil @@ -474,7 +473,7 @@ func NewStepDoneMessage(src interface{}, format Format, amount uint64, rate floa C.gdouble(rate), gboolean(flush), gboolean(intermediate), - C.guint64(duration.Nanoseconds()), + C.guint64(duration), gboolean(eos), ))) } diff --git a/gst/gst_object.go b/gst/gst_object.go index a42f2a3..15848aa 100644 --- a/gst/gst_object.go +++ b/gst/gst_object.go @@ -4,7 +4,6 @@ package gst import "C" import ( - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -42,10 +41,10 @@ func (o *Object) GetName() string { } // GetValue retrieves the value for the given controlled property at the given timestamp. -func (o *Object) GetValue(property string, timestamp time.Duration) *glib.Value { +func (o *Object) GetValue(property string, timestamp ClockTime) *glib.Value { cprop := C.CString(property) defer C.free(unsafe.Pointer(cprop)) - gval := C.gst_object_get_value(o.Instance(), (*C.gchar)(cprop), C.GstClockTime(timestamp.Nanoseconds())) + gval := C.gst_object_get_value(o.Instance(), (*C.gchar)(cprop), C.GstClockTime(timestamp)) if gval == nil { return nil } diff --git a/gst/gst_query.go b/gst/gst_query.go index dda1067..9111429 100644 --- a/gst/gst_query.go +++ b/gst/gst_query.go @@ -4,7 +4,6 @@ package gst import "C" import ( "runtime" - "time" "unsafe" "github.com/go-gst/go-glib/glib" @@ -349,11 +348,11 @@ func (q *Query) ParseDuration() (format Format, duration int64) { } // ParseLatency parses a latency query answer. -func (q *Query) ParseLatency() (live bool, minLatency, maxLatency time.Duration) { +func (q *Query) ParseLatency() (live bool, minLatency, maxLatency ClockTime) { var min, max C.GstClockTime var gl C.gboolean C.gst_query_parse_latency(q.Instance(), &gl, &min, &max) - return gobool(gl), time.Duration(min), time.Duration(max) + return gobool(gl), ClockTime(min), ClockTime(max) } // ParseNumFormats parses the number of formats in the formats query. @@ -537,8 +536,8 @@ func (q *Query) SetFormats(formats ...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) { - C.gst_query_set_latency(q.Instance(), gboolean(live), C.guint64(minLatency.Nanoseconds()), C.guint64(maxLatency.Nanoseconds())) +func (q *Query) SetLatency(live bool, minLatency, maxLatency ClockTime) { + C.gst_query_set_latency(q.Instance(), gboolean(live), C.guint64(minLatency), C.guint64(maxLatency)) } // SetAllocationParamAt sets allocation params in query. diff --git a/gst/pbutils/discoverer.go b/gst/pbutils/discoverer.go index fb66b30..8e50200 100644 --- a/gst/pbutils/discoverer.go +++ b/gst/pbutils/discoverer.go @@ -83,16 +83,10 @@ func wrapDiscovererFull(d *C.GstDiscoverer) *Discoverer { } // NewDiscoverer creates a new Discoverer with the provided timeout. -func NewDiscoverer(timeout time.Duration) (*Discoverer, error) { +func NewDiscoverer(timeout gst.ClockTime) (*Discoverer, error) { initPbUtils() var gerr *C.GError - var cTime C.GstClockTime - if timeout < 0 { - cTime = C.GstClockTime(gst.ClockTimeNone) - } else { - cTime = C.GstClockTime(timeout.Nanoseconds()) - } - ret := C.gst_discoverer_new(C.GstClockTime(cTime), &gerr) + ret := C.gst_discoverer_new(C.GstClockTime(timeout), &gerr) if gerr != nil { return nil, wrapGerr(gerr) } @@ -151,10 +145,10 @@ func (d *DiscovererInfo) GetContainerStreams() []*DiscovererContainerInfo { return glistToContainerInfoSlice(gList) } -// GetDuration returns the durartion of the stream. -func (d *DiscovererInfo) GetDuration() time.Duration { +// GetDuration returns the duration of the stream. +func (d *DiscovererInfo) GetDuration() gst.ClockTime { dur := C.gst_discoverer_info_get_duration(d.Instance()) - return time.Duration(uint64(dur)) * time.Nanosecond + return gst.ClockTime(uint64(dur)) } // GetLive returns whether this is a live stream. diff --git a/gst/video/c_util.go b/gst/video/c_util.go index 4e8c0bc..4aec0bd 100644 --- a/gst/video/c_util.go +++ b/gst/video/c_util.go @@ -22,13 +22,6 @@ func wrapGerr(gerr *C.GError) error { return errors.New(C.GoString(gerr.message)) } -func durationToClockTime(d time.Duration) C.GstClockTime { - if d.Nanoseconds() < 0 { - return C.GstClockTime(gst.ClockTimeNone) - } - return C.GstClockTime(d.Nanoseconds()) -} - func fromCoreCaps(caps *gst.Caps) *C.GstCaps { return (*C.GstCaps)(unsafe.Pointer(caps.Instance())) } diff --git a/gst/video/convert_frame.go b/gst/video/convert_frame.go index 25b46b3..a2c0202 100644 --- a/gst/video/convert_frame.go +++ b/gst/video/convert_frame.go @@ -35,12 +35,12 @@ type ConvertSampleCallback func(*gst.Sample, error) // The output caps can be any raw video formats or any image formats (jpeg, png, ...). // // The width, height and pixel-aspect-ratio can also be specified in the output caps. -func ConvertSample(sample *gst.Sample, toCaps *gst.Caps, timeout time.Duration) (*gst.Sample, error) { +func ConvertSample(sample *gst.Sample, toCaps *gst.Caps, timeout gst.ClockTime) (*gst.Sample, error) { var gerr *C.GError ret := C.gst_video_convert_sample( fromCoreSample(sample), fromCoreCaps(toCaps), - durationToClockTime(timeout), + C.GstClockTime(timeout), &gerr, ) if gerr != nil { @@ -60,12 +60,12 @@ func ConvertSample(sample *gst.Sample, toCaps *gst.Caps, timeout time.Duration) // // The callback will be called after conversion, when an error occurred or if conversion // didn't finish after timeout. -func ConvertSampleAsync(sample *gst.Sample, toCaps *gst.Caps, timeout time.Duration, cb ConvertSampleCallback) { +func ConvertSampleAsync(sample *gst.Sample, toCaps *gst.Caps, timeout gst.ClockTime, cb ConvertSampleCallback) { ptr := gopointer.Save(cb) C.gst_video_convert_sample_async( fromCoreSample(sample), fromCoreCaps(toCaps), - durationToClockTime(timeout), + C.GstClockTime(timeout), C.GstVideoConvertSampleCallback(C.cgoVideoConvertSampleCb), (C.gpointer)(unsafe.Pointer(ptr)), C.GDestroyNotify(C.cgoVideoGDestroyNotifyFunc), diff --git a/gst/video/gst_video.go b/gst/video/gst_video.go index 4799faf..f264979 100644 --- a/gst/video/gst_video.go +++ b/gst/video/gst_video.go @@ -5,7 +5,6 @@ import "C" import ( "runtime" - "time" "unsafe" "github.com/go-gst/go-gst/gst" @@ -82,8 +81,8 @@ func CalculateDisplayRatio(videoWidth, videoHeight, videoParNum, videoParDenom, // It will calculate an arbitrary framerate if no close match was found, and return FALSE. // // It returns FALSE if a duration of 0 is passed. -func GuessFramerate(dur time.Duration) (destNum, destDenom int, ok bool) { +func GuessFramerate(dur gst.ClockTime) (destNum, destDenom int, ok bool) { var num, denom C.gint - gok := C.gst_video_guess_framerate(durationToClockTime(dur), &num, &denom) + gok := C.gst_video_guess_framerate(C.GstClockTime(dur), &num, &denom) return int(num), int(denom), gobool(gok) }