From 2927ae7b1def5e7bad6f81bb1e176652663faaa6 Mon Sep 17 00:00:00 2001 From: tinyzimmer <38474291+tinyzimmer@users.noreply.github.com> Date: Mon, 28 Sep 2020 20:16:51 +0300 Subject: [PATCH] implement streams and streamcollections and finish message parsers --- gst/gst.go.c | 12 +++++++ gst/gst.go.h | 48 +++++++++++++------------ gst/gst_constants.go | 31 ++++++++++++++++ gst/gst_message.go | 43 ++++++++++++++++++++++ gst/gst_message_stringer.go | 5 +++ gst/gst_stream.go | 70 ++++++++++++++++++++++++++++++++++++ gst/gst_stream_collection.go | 51 ++++++++++++++++++++++++++ gst/gst_wrappers.go | 4 +++ 8 files changed, 241 insertions(+), 23 deletions(-) create mode 100644 gst/gst_stream.go create mode 100644 gst/gst_stream_collection.go diff --git a/gst/gst.go.c b/gst/gst.go.c index 88bcf7d..980e1eb 100644 --- a/gst/gst.go.c +++ b/gst/gst.go.c @@ -274,4 +274,16 @@ GstDevice * toGstDevice(void *p) { return (GST_DEVICE_CAST(p)); +} + +GstStreamCollection * +toGstStreamCollection(void *p) +{ + return (GST_STREAM_COLLECTION_CAST(p)); +} + +GstStream * +toGstStream(void *p) +{ + return (GST_STREAM_CAST(p)); } \ No newline at end of file diff --git a/gst/gst.go.h b/gst/gst.go.h index 25455ee..1fdfbe8 100644 --- a/gst/gst.go.h +++ b/gst/gst.go.h @@ -40,26 +40,28 @@ GParamSpecDouble * getParamDouble (GParamSpec * param); Type Castings */ -GstUri * toGstURI (void *p); -GstURIHandler * toGstURIHandler (void *p); -GstRegistry * toGstRegistry (void *p); -GstPlugin * toGstPlugin (void *p); -GstPluginFeature * toGstPluginFeature (void *p); -GstObject * toGstObject (void *p); -GstElementFactory * toGstElementFactory (void *p); -GstElement * toGstElement (void *p); -GstBin * toGstBin (void *p); -GstBus * toGstBus (void *p); -GstMessage * toGstMessage (void *p); -GstPipeline * toGstPipeline (void *p); -GstPad * toGstPad (void *p); -GstPadTemplate * toGstPadTemplate (void *p); -GstStructure * toGstStructure (void *p); -GstClock * toGstClock (void *p); -GstMiniObject * toGstMiniObject (void *p); -GstCaps * toGstCaps (void *p); -GstCapsFeatures * toGstCapsFeatures (void *p); -GstBuffer * toGstBuffer (void *p); -GstBufferPool * toGstBufferPool (void *p); -GstSample * toGstSample (void *p); -GstDevice * toGstDevice (void *p); \ No newline at end of file +GstUri * toGstURI (void *p); +GstURIHandler * toGstURIHandler (void *p); +GstRegistry * toGstRegistry (void *p); +GstPlugin * toGstPlugin (void *p); +GstPluginFeature * toGstPluginFeature (void *p); +GstObject * toGstObject (void *p); +GstElementFactory * toGstElementFactory (void *p); +GstElement * toGstElement (void *p); +GstBin * toGstBin (void *p); +GstBus * toGstBus (void *p); +GstMessage * toGstMessage (void *p); +GstPipeline * toGstPipeline (void *p); +GstPad * toGstPad (void *p); +GstPadTemplate * toGstPadTemplate (void *p); +GstStructure * toGstStructure (void *p); +GstClock * toGstClock (void *p); +GstMiniObject * toGstMiniObject (void *p); +GstCaps * toGstCaps (void *p); +GstCapsFeatures * toGstCapsFeatures (void *p); +GstBuffer * toGstBuffer (void *p); +GstBufferPool * toGstBufferPool (void *p); +GstSample * toGstSample (void *p); +GstDevice * toGstDevice (void *p); +GstStreamCollection * toGstStreamCollection (void *p); +GstStream * toGstStream (void *p); \ No newline at end of file diff --git a/gst/gst_constants.go b/gst/gst_constants.go index f0f453a..528ac3e 100644 --- a/gst/gst_constants.go +++ b/gst/gst_constants.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" +import "unsafe" // ClockTime is a go representation of a GstClockTime. Most of the time these are casted // to time.Duration objects. It represents a time value in nanoseconds. @@ -368,3 +369,33 @@ func (p ProgressType) String() string { } return "" } + +// StreamType is a go representation of a GstStreamType +type StreamType int + +// Type castings of stream types +const ( + StreamTypeUnknown StreamType = C.GST_STREAM_TYPE_UNKNOWN // (1) – The stream is of unknown (unclassified) type. + StreamTypeAudio StreamType = C.GST_STREAM_TYPE_AUDIO // (2) – The stream is of audio data + StreamTypeVideo StreamType = C.GST_STREAM_TYPE_VIDEO // (4) – The stream carries video data + StreamTypeContainer StreamType = C.GST_STREAM_TYPE_CONTAINER // (8) – The stream is a muxed container type + StreamTypeText StreamType = C.GST_STREAM_TYPE_TEXT // (16) – The stream contains subtitle / subpicture data. +) + +// String implements a stringer on StreamTypes. +func (s StreamType) String() string { + name := C.gst_stream_type_get_name((C.GstStreamType)(s)) + defer C.free(unsafe.Pointer(name)) + return C.GoString(name) +} + +// StreamFlags represent configuration options for a new stream. +type StreamFlags int + +// Type castings of StreamFlags +const ( + StreamFlagNone StreamFlags = C.GST_STREAM_FLAG_NONE // (0) – This stream has no special attributes + StreamFlagSparse StreamFlags = C.GST_STREAM_FLAG_SPARSE // (1) – This stream is a sparse stream (e.g. a subtitle stream), data may flow only in irregular intervals with large gaps in between. + StreamFlagSelect StreamFlags = C.GST_STREAM_FLAG_SELECT // (2) – This stream should be selected by default. This flag may be used by demuxers to signal that a stream should be selected by default in a playback scenario. + StreamFlagUnselect StreamFlags = C.GST_STREAM_FLAG_UNSELECT // (4) – This stream should not be selected by default. This flag may be used by demuxers to signal that a stream should not be selected by default in a playback scenario, but only if explicitly selected by the user (e.g. an audio track for the hard of hearing or a director's commentary track). +) diff --git a/gst/gst_message.go b/gst/gst_message.go index 5265861..6f7f5b0 100644 --- a/gst/gst_message.go +++ b/gst/gst_message.go @@ -424,3 +424,46 @@ func (m *Message) ParsePropertyNotify() (obj *Object, propertName string, proper string(C.GoBytes(namePtr, C.sizeOfGCharArray((**C.gchar)(namePtr)))), glib.ValueFromNative(unsafe.Pointer(gval)) } + +// ParseStreamCollection parses a stream-collection message. +func (m *Message) ParseStreamCollection() *StreamCollection { + var collection *C.GstStreamCollection + C.gst_message_parse_stream_collection( + (*C.GstMessage)(m.Instance()), + &collection, + ) + return wrapStreamCollection(glib.Take(unsafe.Pointer(collection))) +} + +// ParseStreamsSelected parses a streams-selected message. +func (m *Message) ParseStreamsSelected() *StreamCollection { + var collection *C.GstStreamCollection + C.gst_message_parse_streams_selected( + (*C.GstMessage)(m.Instance()), + &collection, + ) + return wrapStreamCollection(glib.Take(unsafe.Pointer(collection))) +} + +// NumRedirectEntries returns the number of redirect entries in a MessageRedirect. +func (m *Message) NumRedirectEntries() int64 { + return int64(C.gst_message_get_num_redirect_entries((*C.GstMessage)(m.Instance()))) +} + +// ParseRedirectEntryAt parses the redirect entry at the given index. Total indices can be retrieved +// with NumRedirectEntries(). +func (m *Message) ParseRedirectEntryAt(idx int64) (location string, tags *TagList, structure *Structure) { + locPtr := C.malloc(C.sizeof_char * 1024) + defer C.free(unsafe.Pointer(locPtr)) + var tagList *C.GstTagList + var entryStruct *C.GstStructure + C.gst_message_parse_redirect_entry( + (*C.GstMessage)(m.Instance()), + C.gsize(idx), + (**C.char)(locPtr), + &tagList, + &entryStruct, + ) + return string(C.GoBytes(locPtr, C.sizeOfGCharArray((**C.gchar)(locPtr)))), + wrapTagList(tagList), wrapStructure(entryStruct) +} diff --git a/gst/gst_message_stringer.go b/gst/gst_message_stringer.go index 78a5df9..90cf314 100644 --- a/gst/gst_message_stringer.go +++ b/gst/gst_message_stringer.go @@ -169,10 +169,15 @@ func (m *Message) String() string { } case MessageStreamCollection: + collection := m.ParseStreamCollection() + msg += fmt.Sprintf("New stream collection with upstream id: %s", collection.GetUpstreamID()) case MessageStreamsSelected: + collection := m.ParseStreamsSelected() + msg += fmt.Sprintf("Stream with upstream id '%s' has selected new streams", collection.GetUpstreamID()) case MessageRedirect: + msg += fmt.Sprintf("Received redirect message with %d entries", m.NumRedirectEntries()) case MessageUnknown: msg += "Unknown message type" diff --git a/gst/gst_stream.go b/gst/gst_stream.go new file mode 100644 index 0000000..939327a --- /dev/null +++ b/gst/gst_stream.go @@ -0,0 +1,70 @@ +package gst + +// #include "gst.go.h" +import "C" +import ( + "unsafe" + + "github.com/gotk3/gotk3/glib" +) + +// Stream is a Go representation of a GstStream. +type Stream struct{ *Object } + +// NewStream returns a new Stream with the given ID, caps, type, and flags. +func NewStream(id string, caps *Caps, sType StreamType, flags StreamFlags) *Stream { + cID := C.CString(id) + defer C.free(unsafe.Pointer(cID)) + stream := C.gst_stream_new(cID, caps.Instance(), C.GstStreamType(sType), C.GstStreamFlags(flags)) + return wrapStream(glib.Take(unsafe.Pointer(stream))) +} + +// Instance returns the underlying GstStream. +func (s *Stream) Instance() *C.GstStream { + return C.toGstStream(s.Unsafe()) +} + +// Caps returns the caps for this stream. +func (s *Stream) Caps() *Caps { + return wrapCaps(C.gst_stream_get_caps(s.Instance())) +} + +// StreamFlags returns the flags for this stream. +func (s *Stream) StreamFlags() StreamFlags { + return StreamFlags(C.gst_stream_get_stream_flags(s.Instance())) +} + +// StreamID returns the id of this stream. +func (s *Stream) StreamID() string { + return C.GoString(C.gst_stream_get_stream_id(s.Instance())) +} + +// StreamType returns the type of this stream. +func (s *Stream) StreamType() StreamType { + return StreamType(C.gst_stream_get_stream_type(s.Instance())) +} + +// Tags returns the tag list for this stream. +func (s *Stream) Tags() *TagList { + return wrapTagList(C.gst_stream_get_tags(s.Instance())) +} + +// SetCaps sets the caps for this stream. +func (s *Stream) SetCaps(caps *Caps) { + C.gst_stream_set_caps(s.Instance(), caps.Instance()) +} + +// SetStreamFlags sets the flags for this stream. +func (s *Stream) SetStreamFlags(flags StreamFlags) { + C.gst_stream_set_stream_flags(s.Instance(), C.GstStreamFlags(flags)) +} + +// SetStreamType sets the type of this stream. +func (s *Stream) SetStreamType(sType StreamType) { + C.gst_stream_set_stream_type(s.Instance(), C.GstStreamType(sType)) +} + +// SetTags sets the tags for this stream. +func (s *Stream) SetTags(tags *TagList) { + C.gst_stream_set_tags(s.Instance(), tags.Instance()) +} diff --git a/gst/gst_stream_collection.go b/gst/gst_stream_collection.go new file mode 100644 index 0000000..1690da4 --- /dev/null +++ b/gst/gst_stream_collection.go @@ -0,0 +1,51 @@ +package gst + +// #include "gst.go.h" +import "C" +import ( + "fmt" + "unsafe" + + "github.com/gotk3/gotk3/glib" +) + +// StreamCollection is a Go representation of a GstStreamCollection. +type StreamCollection struct{ *Object } + +// NewStreamCollection returns a new StreamCollection with an upstream parent +// of the given stream ID. +func NewStreamCollection(upstreamID string) *StreamCollection { + cID := C.CString(upstreamID) + defer C.free(unsafe.Pointer(cID)) + collection := C.gst_stream_collection_new(cID) + return wrapStreamCollection(glib.Take(unsafe.Pointer(collection))) +} + +// Instance returns the underlying GstStreamCollection. +func (s *StreamCollection) Instance() *C.GstStreamCollection { + return C.toGstStreamCollection(s.Unsafe()) +} + +// AddStream adds the given stream to this collection. +func (s *StreamCollection) AddStream(stream *Stream) error { + if ok := gobool(C.gst_stream_collection_add_stream(s.Instance(), stream.Instance())); !ok { + return fmt.Errorf("Failed to add stream %s to collection", stream.StreamID()) + } + return nil +} + +// GetSize returns the size of this stream collection. +func (s *StreamCollection) GetSize() uint { + return uint(C.gst_stream_collection_get_size(s.Instance())) +} + +// GetStreamAt returns the stream at the given index in this collection. +func (s *StreamCollection) GetStreamAt(idx uint) *Stream { + stream := C.gst_stream_collection_get_stream(s.Instance(), C.guint(idx)) + return wrapStream(glib.Take(unsafe.Pointer(stream))) +} + +// GetUpstreamID retrieves the upstream ID for this collection. +func (s *StreamCollection) GetUpstreamID() string { + return C.GoString(C.gst_stream_collection_get_upstream_id(s.Instance())) +} diff --git a/gst/gst_wrappers.go b/gst/gst_wrappers.go index 4c3f91d..c2a3679 100644 --- a/gst/gst_wrappers.go +++ b/gst/gst_wrappers.go @@ -117,6 +117,10 @@ func wrapSample(sample *C.GstSample) *Sample { return &Sample{sample: func wrapBuffer(buf *C.GstBuffer) *Buffer { return &Buffer{ptr: buf} } func wrapMainLoop(loop *C.GMainLoop) *MainLoop { return &MainLoop{ptr: loop} } func wrapMainContext(ctx *C.GMainContext) *MainContext { return &MainContext{ptr: ctx} } +func wrapStream(obj *glib.Object) *Stream { return &Stream{wrapObject(obj)} } +func wrapStreamCollection(obj *glib.Object) *StreamCollection { + return &StreamCollection{wrapObject(obj)} +} // Clock wrappers