diff --git a/gst/c_util.go b/gst/c_util.go index 546ef45..9e1268d 100644 --- a/gst/c_util.go +++ b/gst/c_util.go @@ -11,6 +11,10 @@ import ( "github.com/gotk3/gotk3/glib" ) +func toGObject(data unsafe.Pointer) *glib.Object { + return &glib.Object{GObject: glib.ToGObject(data)} +} + // gobool provides an easy type conversion between C.gboolean and a go bool. func gobool(b C.gboolean) bool { return int(b) > 0 @@ -103,7 +107,7 @@ func glistToStreamSlice(glist *C.GList) []*Stream { out := make([]*Stream, 0) l.FreeFull(func(item interface{}) { st := item.(*C.GstStream) - out = append(out, wrapStream(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(st))})) + out = append(out, wrapStream(toGObject(unsafe.Pointer(st)))) }) return out } diff --git a/gst/cgo_exports.go b/gst/cgo_exports.go index 376d7d3..85f8500 100644 --- a/gst/cgo_exports.go +++ b/gst/cgo_exports.go @@ -14,51 +14,19 @@ import ( ) //export goPadProbeFunc -func goPadProbeFunc(gstPad *C.GstPad, gstProbeInfo *C.GstPadProbeInfo, userData C.gpointer) C.GstPadProbeReturn { +func goPadProbeFunc(gstPad *C.GstPad, info *C.GstPadProbeInfo, userData C.gpointer) C.GstPadProbeReturn { cbIface := gopointer.Restore(unsafe.Pointer(userData)) cbFunc := cbIface.(PadProbeCallback) pad := wrapPad(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gstPad))}) - probeInfo := &PadProbeInfo{ - ID: uint32(gstProbeInfo.id), - Type: PadProbeType(gstProbeInfo._type), - Offset: uint64(gstProbeInfo.offset), - Size: uint64(gstProbeInfo.size), - } - populateProbeInfoData(probeInfo, gstProbeInfo.data) - return C.GstPadProbeReturn(cbFunc(pad, probeInfo)) + return C.GstPadProbeReturn(cbFunc(pad, &PadProbeInfo{info})) } -// Figures out what to populate the probe info data with based on the type. -func populateProbeInfoData(probeInfo *PadProbeInfo, data C.gpointer) { - switch probeInfo.Type { - - // Buffer - case PadProbeTypeBuffer: - probeInfo.Data = wrapBuffer((*C.GstBuffer)(unsafe.Pointer(data))) - - // BufferList - case PadProbeTypeBufferList: - probeInfo.Data = wrapBufferList((*C.GstBufferList)(unsafe.Pointer(data))) - - // Events - case PadProbeTypeEventDownstream: - probeInfo.Data = wrapEvent((*C.GstEvent)(unsafe.Pointer(data))) - case PadProbeTypeEventUpstream: - probeInfo.Data = wrapEvent((*C.GstEvent)(unsafe.Pointer(data))) - case PadProbeTypeEventFlush: - probeInfo.Data = wrapEvent((*C.GstEvent)(unsafe.Pointer(data))) - case PadProbeTypeEventBoth: - probeInfo.Data = wrapEvent((*C.GstEvent)(unsafe.Pointer(data))) - - // Queries - case PadProbeTypeQueryDownstream: - probeInfo.Data = wrapQuery((*C.GstQuery)(unsafe.Pointer(data))) - case PadProbeTypeQueryUpstream: - probeInfo.Data = wrapQuery((*C.GstQuery)(unsafe.Pointer(data))) - case PadProbeTypeQueryBoth: - probeInfo.Data = wrapQuery((*C.GstQuery)(unsafe.Pointer(data))) - - } +//export goPadForwardFunc +func goPadForwardFunc(gpad *C.GstPad, userData C.gpointer) C.gboolean { + cbIface := gopointer.Restore(unsafe.Pointer(userData)) + cbFunc := cbIface.(PadForwardFunc) + pad := wrapPad(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gpad))}) + return gboolean(cbFunc(pad)) } //export goTagForEachFunc diff --git a/gst/constants.go b/gst/constants.go index a3d9748..94fd8c4 100644 --- a/gst/constants.go +++ b/gst/constants.go @@ -775,6 +775,16 @@ const ( QueryTypeSerialized QueryTypeFlags = C.GST_QUERY_TYPE_SERIALIZED // (4) – Set if the query should be serialized with data flow. ) +// TaskState casts GstTaskState +type TaskState int + +// Type castings +const ( + TaskStarted TaskState = C.GST_TASK_STARTED // (0) – the task is started and running + TaskStopped TaskState = C.GST_TASK_STOPPED // (1) – the task is stopped + TaskPaused TaskState = C.GST_TASK_PAUSED // (2) – the task is paused +) + // TOCScope represents the scope of a TOC. type TOCScope int diff --git a/gst/gst_object.go b/gst/gst_object.go index b8dba7d..0384cbe 100644 --- a/gst/gst_object.go +++ b/gst/gst_object.go @@ -24,8 +24,11 @@ func (o *Object) Unsafe() unsafe.Pointer { // Instance returns the native C GstObject. func (o *Object) Instance() *C.GstObject { return C.toGstObject(o.Unsafe()) } -// Object is an alias to Instance on the underlying GstObject of any extending struct. -func (o *Object) Object() *C.GstObject { return C.toGstObject(o.Unsafe()) } +// BaseObject returns this object for embedding structs. +func (o *Object) BaseObject() *Object { return o } + +// GstObject is an alias to Instance on the underlying GstObject of any extending struct. +func (o *Object) GstObject() *C.GstObject { return C.toGstObject(o.Unsafe()) } // Class returns the GObjectClass of this instance. func (o *Object) Class() *C.GObjectClass { return C.getGObjectClass(o.Unsafe()) } diff --git a/gst/gst_pad.go b/gst/gst_pad.go index 8eea59c..a94f699 100644 --- a/gst/gst_pad.go +++ b/gst/gst_pad.go @@ -1,12 +1,34 @@ package gst -// #include "gst.go.h" +/* +#include "gst.go.h" + +extern GstPadProbeReturn goPadProbeFunc (GstPad * pad, GstPadProbeInfo * info, gpointer user_data); +extern gboolean goPadForwardFunc (GstPad * pad, gpointer user_data); +extern void goGDestroyNotifyFuncNoRun (gpointer user_data); + +GstPadProbeReturn cgoPadProbeFunc (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + return goPadProbeFunc(pad, info, user_data); +} + +gboolean cgoPadForwardFunc (GstPad * pad, gpointer user_data) +{ + return goPadForwardFunc(pad, user_data); +} + +void cgoGDestroyNotifyFuncNoRun (gpointer user_data) +{ + goGDestroyNotifyFuncNoRun(user_data); +} + +*/ import "C" import ( "unsafe" - "github.com/gotk3/gotk3/glib" + gopointer "github.com/mattn/go-pointer" ) // Pad is a go representation of a GstPad @@ -24,7 +46,7 @@ func NewPad(name string, direction PadDirection) *Pad { if pad == nil { return nil } - return wrapPad(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(pad))}) + return wrapPad(toGObject(unsafe.Pointer(pad))) } // NewPadFromTemplate creates a new pad with the given name from the given template. If name is empty, one will @@ -40,7 +62,7 @@ func NewPadFromTemplate(tmpl *PadTemplate, name string) *Pad { if pad == nil { return nil } - return wrapPad(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(pad))}) + return wrapPad(toGObject(unsafe.Pointer(pad))) } // Instance returns the underlying C GstPad. @@ -53,7 +75,7 @@ func (p *Pad) Direction() PadDirection { // Template returns the template for this pad or nil. func (p *Pad) Template() *PadTemplate { - return wrapPadTemplate(glib.Take(unsafe.Pointer(p.Instance().padtemplate))) + return wrapPadTemplate(toGObject(unsafe.Pointer(p.Instance().padtemplate))) } // CurrentCaps returns the caps for this Pad or nil. @@ -73,14 +95,328 @@ func (p *Pad) ActivateMode(mode PadMode, active bool) { C.gst_pad_activate_mode(p.Instance(), C.GstPadMode(mode), gboolean(active)) } -// PadProbeInfo represents the info passed to a PadProbeCallback. -type PadProbeInfo struct { - ID uint32 - Type PadProbeType - // The data in the interface depends on the Type in the probe info - Data interface{} - Offset, Size uint64 -} - // PadProbeCallback is a callback used by Pad AddProbe. It gets called to notify about the current blocking type. type PadProbeCallback func(*Pad, *PadProbeInfo) PadProbeReturn + +// AddProbe adds a callback to be notified of different states of pads. The provided callback is called for every state that matches mask. +// +// Probes are called in groups: First GST_PAD_PROBE_TYPE_BLOCK probes are called, then others, then finally GST_PAD_PROBE_TYPE_IDLE. The only +// exception here are GST_PAD_PROBE_TYPE_IDLE probes that are called immediately if the pad is already idle while calling gst_pad_add_probe. +// In each of the groups, probes are called in the order in which they were added. +// +// A probe ID is returned that can be used to remove the probe. +func (p *Pad) AddProbe(mask PadProbeType, f PadProbeCallback) uint64 { + ptr := gopointer.Save(f) + ret := C.gst_pad_add_probe( + p.Instance(), + C.GstPadProbeType(mask), + C.GstPadProbeCallback(C.cgoPadProbeFunc), + (C.gpointer)(unsafe.Pointer(ptr)), + C.GDestroyNotify(C.cgoGDestroyNotifyFuncNoRun), + ) + return uint64(ret) +} + +// CanLink checks if this pad is compatible with the given sink pad. +func (p *Pad) CanLink(sink *Pad) bool { + return gobool(C.gst_pad_can_link(p.Instance(), sink.Instance())) +} + +// Chain a buffer to pad. +// +// The function returns FlowFlushing if the pad was flushing. +// +// If the buffer type is not acceptable for pad (as negotiated with a preceding EventCaps event), this function returns FlowNotNegotiated. +// +// The function proceeds calling the chain function installed on pad (see SetChainFunction) and the return value of that function is returned to +// the caller. FlowNotSupported is returned if pad has no chain function. +// +// In all cases, success or failure, the caller loses its reference to buffer after calling this function. +func (p *Pad) Chain(buffer *Buffer) FlowReturn { + return FlowReturn(C.gst_pad_chain(p.Instance(), buffer.Instance())) +} + +// ChainList chains a bufferlist to pad. +// +// The function returns FlowFlushing if the pad was flushing. +// +// If pad was not negotiated properly with a CAPS event, this function returns FlowNotNegotiated. +// +// The function proceeds calling the chainlist function installed on pad (see SetChainListFunction) and the return value of that function is returned +// to the caller. FlowNotSupported is returned if pad has no chainlist function. +// +// In all cases, success or failure, the caller loses its reference to list after calling this function. +func (p *Pad) ChainList(bufferList *BufferList) FlowReturn { + return FlowReturn(C.gst_pad_chain_list(p.Instance(), bufferList.Instance())) +} + +// CheckReconfigure checks and clear the PadFlagNeedReconfigure flag on pad and return TRUE if the flag was set. +func (p *Pad) CheckReconfigure() bool { + return gobool(C.gst_pad_check_reconfigure(p.Instance())) +} + +// CreateStreamID creates a stream-id for the source GstPad pad by combining the upstream information with the optional stream_id of the stream of pad. +// Pad must have a parent GstElement and which must have zero or one sinkpad. stream_id can only be NULL if the parent element of pad has only a single +// source pad. +// +// This function generates an unique stream-id by getting the upstream stream-start event stream ID and appending stream_id to it. If the element has no +// sinkpad it will generate an upstream stream-id by doing an URI query on the element and in the worst case just uses a random number. Source elements +// that don't implement the URI handler interface should ideally generate a unique, deterministic stream-id manually instead. +// +// Since stream IDs are sorted alphabetically, any numbers in the stream ID should be printed with a fixed number of characters, preceded by 0's, such as +// by using the format %03u instead of %u. +func (p *Pad) CreateStreamID(parent *Element, streamID string) string { + var gstreamID *C.gchar + if streamID != "" { + ptr := C.CString(streamID) + defer C.free(unsafe.Pointer(ptr)) + gstreamID = (*C.gchar)(unsafe.Pointer(ptr)) + } + ret := C.gst_pad_create_stream_id(p.Instance(), parent.Instance(), gstreamID) + if ret == nil { + return "" + } + defer C.g_free((C.gpointer)(unsafe.Pointer(ret))) + return C.GoString(ret) +} + +// EventDefault invokes the default event handler for the given pad. +// +// The EOS event will pause the task associated with pad before it is forwarded to all internally linked pads, +// +// The event is sent to all pads internally linked to pad. This function takes ownership of event. +func (p *Pad) EventDefault(parent *Object, event *Event) bool { + return gobool(C.gst_pad_event_default(p.Instance(), parent.Instance(), event.Instance())) +} + +// PadForwardFunc is called for all internally linked pads, see Pad Forward(). +// If the function returns true, the procedure is stopped. +type PadForwardFunc func(pad *Pad) bool + +// Forward calls the given function for all internally linked pads of pad. This function deals with dynamically changing internal pads and will make sure +// that the forward function is only called once for each pad. +// +// When forward returns TRUE, no further pads will be processed. +func (p *Pad) Forward(f PadForwardFunc) bool { + ptr := gopointer.Save(f) + defer gopointer.Unref(ptr) + return gobool(C.gst_pad_forward( + p.Instance(), + C.GstPadForwardFunction(C.cgoPadForwardFunc), + (C.gpointer)(unsafe.Pointer(ptr)), + )) +} + +// GetAllowedCaps getss the capabilities of the allowed media types that can flow through pad and its peer. +// +// The allowed capabilities is calculated as the intersection of the results of calling QueryCaps on pad and its peer. The caller owns a reference on the +// resulting caps. +func (p *Pad) GetAllowedCaps() *Caps { + return wrapCaps(C.gst_pad_get_allowed_caps( + p.Instance(), + )) +} + +// GetCurrentCaps gets the capabilities currently configured on pad with the last EventCaps event. +func (p *Pad) GetCurrentCaps() *Caps { + return wrapCaps(C.gst_pad_get_current_caps( + p.Instance(), + )) +} + +// GetDirection gets the direction of the pad. The direction of the pad is decided at construction time so this function does not take the LOCK. +func (p *Pad) GetDirection() PadDirection { + return PadDirection(C.gst_pad_get_direction(p.Instance())) +} + +// GetElementPrivate gets the private data of a pad. No locking is performed in this function. +func (p *Pad) GetElementPrivate() interface{} { + ptr := C.gst_pad_get_element_private(p.Instance()) + return gopointer.Restore(unsafe.Pointer(ptr)) +} + +// GetLastFlowReturn gets the FlowReturn return from the last data passed by this pad. +func (p *Pad) GetLastFlowReturn() FlowReturn { + return FlowReturn(C.gst_pad_get_last_flow_return( + p.Instance(), + )) +} + +// GetOffset gets the offset applied to the running time of pad. pad has to be a source pad. +func (p *Pad) GetOffset() int64 { + return int64(C.gst_pad_get_offset(p.Instance())) +} + +// GetPadTemplate gets the template for this pad. +func (p *Pad) GetPadTemplate() *PadTemplate { + tmpl := C.gst_pad_get_pad_template(p.Instance()) + if tmpl == nil { + return nil + } + return wrapPadTemplate(toGObject(unsafe.Pointer(tmpl))) +} + +// GetPadTemplateCaps gets the capabilities for pad's template. +func (p *Pad) GetPadTemplateCaps() *Caps { + caps := C.gst_pad_get_pad_template_caps(p.Instance()) + if caps == nil { + return nil + } + return wrapCaps(caps) +} + +// GetParentElement gets the parent of pad, cast to a Element. If a pad has no parent or its +// parent is not an element, return nil. +func (p *Pad) GetParentElement() *Element { + elem := C.gst_pad_get_parent_element(p.Instance()) + if elem == nil { + return nil + } + return wrapElement(toGObject(unsafe.Pointer(elem))) +} + +// GetPeer gets the peer of pad. This function refs the peer pad so you need to unref it after use. +func (p *Pad) GetPeer() *Pad { + peer := C.gst_pad_get_peer(p.Instance()) + if peer == nil { + return nil + } + return wrapPad(toGObject(unsafe.Pointer(peer))) +} + +// GetRange calls the getrange function of pad, see PadGetRangeFunc for a description of a getrange function. +// If pad has no getrange function installed (see SetGetRangeFunction) this function returns FlowNotSupported. +// +// If buffer points to a variable holding nil, a valid new GstBuffer will be placed in buffer when this function +// returns FlowOK. The new buffer must be freed with Unref after usage. +// +// When buffer points to a variable that points to a valid Buffer, the buffer will be filled with the result data +// when this function returns FlowOK. If the provided buffer is larger than size, only size bytes will be filled +// in the result buffer and its size will be updated accordingly. +// +// Note that less than size bytes can be returned in buffer when, for example, an EOS condition is near or when +// buffer is not large enough to hold size bytes. The caller should check the result buffer size to get the result +// size. +// +// When this function returns any other result value than FlowOK, buffer will be unchanged. +// +// This is a lowlevel function. Usually PullRange is used. +func (p *Pad) GetRange(offset uint64, size uint, buffer *Buffer) (FlowReturn, *Buffer) { + var buf *C.GstBuffer + if buffer != nil { + buf = buffer.Instance() + } + ret := C.gst_pad_get_range(p.Instance(), C.guint64(offset), C.guint(size), &buf) + var newBuf *Buffer + if buf != nil { + newBuf = wrapBuffer(buf) + } else { + newBuf = nil + } + return FlowReturn(ret), newBuf +} + +// GetSingleInternalLink checks if there is a single internal link of the given pad, and returns it. Otherwise, it will +// return nil. +func (p *Pad) GetSingleInternalLink() *Pad { + pad := C.gst_pad_get_single_internal_link(p.Instance()) + if pad == nil { + return nil + } + return wrapPad(toGObject(unsafe.Pointer(pad))) +} + +// GetStickyEvent returns a new reference of the sticky event of type event_type from the event. +func (p *Pad) GetStickyEvent(eventType EventType, idx uint) *Event { + ev := C.gst_pad_get_sticky_event(p.Instance(), C.GstEventType(eventType), C.guint(idx)) + if ev == nil { + return nil + } + return wrapEvent(ev) +} + +// GetStream returns the current Stream for the pad, or nil if none has been set yet, i.e. the pad has not received a +// stream-start event yet. +// +// This is a convenience wrapper around GetStickyEvent and Event ParseStream. +func (p *Pad) GetStream() *Stream { + st := C.gst_pad_get_stream(p.Instance()) + if st == nil { + return nil + } + return wrapStream(toGObject(unsafe.Pointer(st))) +} + +// GetStreamID returns the current stream-id for the pad, or an empty string if none has been set yet, i.e. the pad has not received +// a stream-start event yet. +// +// This is a convenience wrapper around gst_pad_get_sticky_event and gst_event_parse_stream_start. +// +// The returned stream-id string should be treated as an opaque string, its contents should not be interpreted. +func (p *Pad) GetStreamID() string { + id := C.gst_pad_get_stream_id(p.Instance()) + if id == nil { + return "" + } + defer C.g_free((C.gpointer)(unsafe.Pointer(id))) + return C.GoString(id) +} + +// GetTaskState gets the pad task state. If no task is currently set, TaskStopped is returned. +func (p *Pad) GetTaskState() TaskState { + return TaskState(C.gst_pad_get_task_state(p.Instance())) +} + +// PadProbeInfo represents the info passed to a PadProbeCallback. +type PadProbeInfo struct { + ptr *C.GstPadProbeInfo +} + +// ID returns the id of the probe. +func (p *PadProbeInfo) ID() uint32 { return uint32(p.ptr.id) } + +// Type returns the type of the probe. The type indicates the type of data that can be expected +// with the probe. +func (p *PadProbeInfo) Type() PadProbeType { return PadProbeType(p.ptr._type) } + +// Offset returns the offset of pull probe, this field is valid when type contains PadProbeTypePull. +func (p *PadProbeInfo) Offset() uint64 { return uint64(p.ptr.offset) } + +// Size returns the size of pull probe, this field is valid when type contains PadProbeTypePull. +func (p *PadProbeInfo) Size() uint64 { return uint64(p.ptr.size) } + +// GetBuffer returns the buffer, if any, inside this probe info. +func (p *PadProbeInfo) GetBuffer() *Buffer { + buf := C.gst_pad_probe_info_get_buffer(p.ptr) + if buf == nil { + return nil + } + return wrapBuffer(buf) +} + +// GetBufferList returns the buffer list, if any, inside this probe info. +func (p *PadProbeInfo) GetBufferList() *BufferList { + bufList := C.gst_pad_probe_info_get_buffer_list(p.ptr) + if bufList == nil { + return nil + } + return wrapBufferList(bufList) +} + +// GetEvent returns the event, if any, inside this probe info. +func (p *PadProbeInfo) GetEvent() *Event { + ev := C.gst_pad_probe_info_get_event(p.ptr) + if ev == nil { + return nil + } + return wrapEvent(ev) +} + +// GetQuery returns the query, if any, inside this probe info. +func (p *PadProbeInfo) GetQuery() *Query { + q := C.gst_pad_probe_info_get_query(p.ptr) + if q == nil { + return nil + } + return wrapQuery(q) +}