Files
go-gst/gst/base/gst_base_sink.go
2021-01-20 15:39:17 +02:00

326 lines
14 KiB
Go

package base
/*
#include "gst.go.h"
gboolean baseSinkParentEvent (GstBaseSink * sink, GstEvent * event)
{
GObjectClass * this_class = G_OBJECT_GET_CLASS(G_OBJECT(sink));
GstBaseSinkClass * parent = toGstBaseSinkClass(g_type_class_peek_parent(this_class));
return parent->event(sink, event);
}
*/
import "C"
import (
"time"
"unsafe"
"github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst"
)
// GstBaseSink represents a GstBaseSink.
type GstBaseSink struct{ *gst.Element }
// ToGstBaseSink returns a GstBaseSink object for the given object. It will work on either gst.Object
// or glib.Object interfaces.
func ToGstBaseSink(obj interface{}) *GstBaseSink {
switch obj := obj.(type) {
case *gst.Object:
return &GstBaseSink{&gst.Element{Object: obj}}
case *glib.Object:
return &GstBaseSink{&gst.Element{Object: &gst.Object{InitiallyUnowned: &glib.InitiallyUnowned{Object: obj}}}}
}
return nil
}
// Instance returns the underlying C GstBaseSrc instance
func (g *GstBaseSink) Instance() *C.GstBaseSink {
return C.toGstBaseSink(g.Unsafe())
}
// DoPreroll is for if the sink spawns its own thread for pulling buffers from upstream.
// It should call this method after it has pulled a buffer. If the element needed to preroll,
// this function will perform the preroll and will then block until the element state is changed.
//
// This function should be called with the PREROLL_LOCK held and the object that caused the preroll.
//
// Since the object will always be a gst.MiniObject (which is not implemented properly), this method will check
// against the provided types for structs known to be used in this context. The currently known options
// are events, messages, queries, structures, and buffers. If you come across a need to use this function with
// an unsupported type, feel free to raise an Issue or open a PR.
func (g *GstBaseSink) DoPreroll(obj interface{}) gst.FlowReturn {
miniobj := getPrerollObj(obj)
if miniobj == nil {
return gst.FlowError
}
return gst.FlowReturn(C.gst_base_sink_do_preroll(g.Instance(), miniobj))
}
func getPrerollObj(obj interface{}) *C.GstMiniObject {
switch obj := obj.(type) {
case *gst.Event:
return (*C.GstMiniObject)(unsafe.Pointer(obj.Instance()))
case *gst.Buffer:
return (*C.GstMiniObject)(unsafe.Pointer(obj.Instance()))
case *gst.Message:
return (*C.GstMiniObject)(unsafe.Pointer(obj.Instance()))
case *gst.Query:
return (*C.GstMiniObject)(unsafe.Pointer(obj.Instance()))
case *gst.Structure:
return (*C.GstMiniObject)(unsafe.Pointer(obj.Instance()))
default:
return nil
}
}
// GetBlocksize gets the number of bytes that the sink will pull when it is operating in pull mode.
func (g *GstBaseSink) GetBlocksize() uint { return uint(C.gst_base_sink_get_blocksize(g.Instance())) }
// GetDropOutOfSegment checks if sink is currently configured to drop buffers which are outside the current segment
func (g *GstBaseSink) GetDropOutOfSegment() bool {
return gobool(C.gst_base_sink_get_drop_out_of_segment(g.Instance()))
}
// GetLastSample gets the last sample that arrived in the sink and was used for preroll or for rendering.
// This property can be used to generate thumbnails.
//
// The GstCaps on the sample can be used to determine the type of the buffer. Unref after usage. Sample will
// be nil if no buffer has arrived yet.
func (g *GstBaseSink) GetLastSample() *gst.Sample {
sample := C.gst_base_sink_get_last_sample(g.Instance())
if sample == nil {
return nil
}
return gst.FromGstSampleUnsafeFull(unsafe.Pointer(sample))
}
// GetLatency gets the currently configured latency.
func (g *GstBaseSink) GetLatency() time.Duration {
return time.Duration(C.gst_base_sink_get_latency(g.Instance()))
}
// GetMaxBitrate gets the maximum amount of bits per second the sink will render.
func (g *GstBaseSink) GetMaxBitrate() uint64 {
return uint64(C.gst_base_sink_get_max_bitrate(g.Instance()))
}
// GetMaxLateness gets the max lateness value.
func (g *GstBaseSink) GetMaxLateness() int64 {
return int64(C.gst_base_sink_get_max_lateness(g.Instance()))
}
// 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()))
}
// 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()))
}
// SINCE 1.18
// // SinkStats represents the current statistics on a GstBaseSink.
// type SinkStats struct {
// AverageRate float64
// Dropped uint64
// Rendered uint64
// }
// // GetSinkStats returns various GstBaseSink statistics.
// func (g *GstBaseSink) GetSinkStats() *SinkStats {
// st := gst.FromGstStructureUnsafe(unsafe.Pointer(C.gst_base_sink_get_stats(g.Instance())))
// stats := &SinkStats{}
// if avgRate, err := st.GetValue("average-rate"); err == nil {
// stats.AverageRate = avgRate.(float64)
// }
// if dropped, err := st.GetValue("dropped"); err == nil {
// stats.Dropped = dropped.(uint64)
// }
// if rendered, err := st.GetValue("rendered"); err == nil {
// stats.Rendered = rendered.(uint64)
// }
// return stats
// }
// GetSync checks if the sink is currently configured to synchronize on the clock.
func (g *GstBaseSink) GetSync() bool { return gobool(C.gst_base_sink_get_sync(g.Instance())) }
// GetThrottleTime gets the time that will be inserted between frames to control maximum buffers
// per second.
func (g *GstBaseSink) GetThrottleTime() uint64 {
return uint64(C.gst_base_sink_get_throttle_time(g.Instance()))
}
// 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()))
}
// IsAsyncEnabled checks if the sink is currently configured to perform asynchronous state changes to PAUSED.
func (g *GstBaseSink) IsAsyncEnabled() bool {
return gobool(C.gst_base_sink_is_async_enabled(g.Instance()))
}
// IsLastSampleEnabled checks if the sink is currently configured to store the last received sample.
func (g *GstBaseSink) IsLastSampleEnabled() bool {
return gobool(C.gst_base_sink_is_last_sample_enabled(g.Instance()))
}
// IsQoSEnabled checks if sink is currently configured to send QoS events upstream.
func (g *GstBaseSink) IsQoSEnabled() bool {
return gobool(C.gst_base_sink_is_qos_enabled(g.Instance()))
}
// ParentEvent calls the parent class's event handler for the given event.
func (g *GstBaseSink) ParentEvent(ev *gst.Event) bool {
return gobool(C.baseSinkParentEvent(
g.Instance(),
(*C.GstEvent)(unsafe.Pointer(ev.Instance())),
))
}
// QueryLatency queries the sink for the latency parameters. The latency will be queried from the
// upstream elements. live will be TRUE if sink is configured to synchronize against the clock.
// upstreamLive will be TRUE if an upstream element is live.
//
// If both live and upstreamLive are TRUE, the sink will want to compensate for the latency introduced
// 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) {
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)
}
// SetAsyncEnabled configures sink to perform all state changes asynchronously. When async is disabled,
// the sink will immediately go to PAUSED instead of waiting for a preroll buffer. This feature is useful
// if the sink does not synchronize against the clock or when it is dealing with sparse streams.
func (g *GstBaseSink) SetAsyncEnabled(enabled bool) {
C.gst_base_sink_set_async_enabled(g.Instance(), gboolean(enabled))
}
// SetBlocksize sets the number of bytes this sink will pull when operating in pull mode.
func (g *GstBaseSink) SetBlocksize(blocksize uint) {
C.gst_base_sink_set_blocksize(g.Instance(), C.guint(blocksize))
}
// SetDropOutOfSegment configures sink to drop buffers which are outside the current segment.
func (g *GstBaseSink) SetDropOutOfSegment(drop bool) {
C.gst_base_sink_set_drop_out_of_segment(g.Instance(), gboolean(drop))
}
// SetLastSampleEnabled configures the sink to store the last received sample.
func (g *GstBaseSink) SetLastSampleEnabled(enabled bool) {
C.gst_base_sink_set_last_sample_enabled(g.Instance(), gboolean(enabled))
}
// SetMaxBitrate sets the maximum amount of bits per second the sink will render.
func (g *GstBaseSink) SetMaxBitrate(bitrate uint64) {
C.gst_base_sink_set_max_bitrate(g.Instance(), C.guint64(bitrate))
}
// SetMaxLateness sets the new max lateness value to max_lateness. This value is used to decide if
// a buffer should be dropped or not based on the buffer timestamp and the current clock time. A
// value of -1 means an unlimited time.
func (g *GstBaseSink) SetMaxLateness(maxLateness int64) {
C.gst_base_sink_set_max_lateness(g.Instance(), C.gint64(maxLateness))
}
// SetProcessingDeadline sets the maximum amount of time (in nanoseconds) that the pipeline can take
// 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()))
}
// SetQoSEnabled configures sink to send Quality-of-Service events upstream.
func (g *GstBaseSink) SetQoSEnabled(enabled bool) {
C.gst_base_sink_set_qos_enabled(g.Instance(), gboolean(enabled))
}
// SetRenderDelay sets the render delay in sink to delay. The render delay is the time between actual
// rendering of a buffer and its synchronisation time. Some devices might delay media rendering which
// can be compensated for with this function.
//
// After calling this function, this sink will report additional latency and other sinks will adjust
// 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()))
}
// SetSync configures sink to synchronize on the clock or not. When sync is FALSE, incoming samples will
// be played as fast as possible. If sync is TRUE, the timestamps of the incoming buffers will be used to
// schedule the exact render time of its contents.
func (g *GstBaseSink) SetSync(sync bool) { C.gst_base_sink_set_sync(g.Instance(), gboolean(sync)) }
// SetThrottleTime sets the time that will be inserted between rendered buffers. This can be used to control
// the maximum buffers per second that the sink will render.
func (g *GstBaseSink) SetThrottleTime(throttle uint64) {
C.gst_base_sink_set_throttle_time(g.Instance(), C.guint64(throttle))
}
// 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()))
}
// Wait will wait for preroll to complete and will then block until timeout is reached. It is usually called by
// subclasses that use their own internal synchronization but want to let some synchronization (like EOS) be
// handled by the base class.
//
// This function should only be called with the PREROLL_LOCK held (like when receiving an EOS event in the
// ::event vmethod or when handling buffers in ::render).
//
// 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) {
var jit C.GstClockTimeDiff
gret := C.gst_base_sink_wait(g.Instance(), C.GstClockTime(timeout.Nanoseconds()), &jit)
return gst.FlowReturn(gret), time.Duration(jit)
}
// WaitClock will block until timeout is reached. It is usually called by subclasses that use their own
// internal synchronization.
//
// If time is not valid, no synchronisation is done and GST_CLOCK_BADTIME is returned. Likewise, if synchronization
// is disabled in the element or there is no clock, no synchronization is done and GST_CLOCK_BADTIME is returned.
//
// This function should only be called with the PREROLL_LOCK held, like when receiving an EOS event in the event()
// vmethod or when receiving a buffer in the render() vmethod.
//
// 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) {
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)
}
// WaitPreroll will block until the preroll is complete.
//
// If the render() method performs its own synchronisation against the clock it must unblock when going from
// PLAYING to the PAUSED state and call this method before continuing to render the remaining data.
//
// If the render() method can block on something else than the clock, it must also be ready to unblock immediately
// on the unlock() method and cause the render() method to immediately call this function. In this case, the
// subclass must be prepared to continue rendering where it left off if this function returns GST_FLOW_OK.
//
// This function will block until a state change to PLAYING happens (in which case this function returns
// GST_FLOW_OK) or the processing must be stopped due to a state change to READY or a FLUSH event (in which case
// this function returns GST_FLOW_FLUSHING).
//
// This function should only be called with the PREROLL_LOCK held, like in the render function.
func (g *GstBaseSink) WaitPreroll() gst.FlowReturn {
return gst.FlowReturn(C.gst_base_sink_wait_preroll(g.Instance()))
}