From 5f21e41f70d8513788cdd400c00b1fdb742d3eff Mon Sep 17 00:00:00 2001 From: tinyzimmer <38474291+tinyzimmer@users.noreply.github.com> Date: Tue, 29 Sep 2020 12:32:55 +0300 Subject: [PATCH] implement GstMeta, organize C code, add github action for linting --- .github/workflows/tests.yml | 46 ++++++ README.md | 6 +- gst/app/gst.go.c | 14 -- gst/app/gst.go.h | 4 +- gst/c_util.go | 3 +- gst/cgo_exports.go | 58 +++++++ gst/gst.go.c | 301 ----------------------------------- gst/gst.go.h | 155 ++++++++++-------- gst/gst_allocator.go | 1 + gst/gst_atomic_queue.go | 1 + gst/gst_bin.go | 1 + gst/gst_buffer.go | 10 ++ gst/gst_bus.go | 34 ++-- gst/gst_clock.go | 1 + gst/gst_constants.go | 35 ++++ gst/gst_device.go | 1 + gst/gst_element_factory.go | 16 +- gst/{init.go => gst_init.go} | 0 gst/gst_memory.go | 1 + gst/gst_meta.go | 40 +++++ gst/gst_pad.go | 1 + gst/gst_plugin_feature.go | 1 + gst/gst_registry.go | 1 + gst/gst_sample.go | 1 + gst/gst_stream.go | 1 + gst/gst_stream_collection.go | 1 + gst/gst_structure.go | 32 ++-- gst/gst_tag_list.go | 1 + gst/gst_uri.go | 26 --- gst/gst_wrappers.go | 49 +++--- gst/pkg_config.go | 1 + 31 files changed, 355 insertions(+), 488 deletions(-) create mode 100644 .github/workflows/tests.yml delete mode 100644 gst/app/gst.go.c create mode 100644 gst/cgo_exports.go delete mode 100644 gst/gst.go.c rename gst/{init.go => gst_init.go} (100%) create mode 100644 gst/gst_meta.go delete mode 100644 gst/gst_uri.go diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..345b566 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,46 @@ +name: Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + + setup: + name: Tests + runs-on: ubuntu-20.04 + steps: + + - name: Set up Go 1.15 + uses: actions/setup-go@v1 + with: + go-version: 1.15 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Get dependencies + run: | + go mod download + + - name: Install gstreamer/pulse dependencies + run: | + sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y libgstreamer1.0-0 libgstreamer1.0-dev libgstreamer-plugins-base1.0-0 pkg-config build-essential + + - name: Lint all packages + run: | + CGO_ENABLED=1 make lint + + # - name: Run all unit tests + # run: | + # CGO_ENABLED=1 make test diff --git a/README.md b/README.md index ef20249..1f6ce16 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,8 @@ Go bindings for the gstreamer C library [![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-rounded)](https://pkg.go.dev/github.com/tinyzimmer/go-gst) [![godoc reference](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/tinyzimmer/go-gst) -[![GoReportCard example](https://goreportcard.com/badge/github.com/nanomsg/mangos)](https://goreportcard.com/report/github.com/tinyzimmer/go-gst) - -This package was originally written to aid the audio support in [`kvdi`](https://github.com/tinyzimmer/kvdi). -But it made sense to turn it into an independent, consumable package. The intention now is to progressively implement the entire API. +[![GoReportCard](https://goreportcard.com/badge/github.com/nanomsg/mangos)](https://goreportcard.com/report/github.com/tinyzimmer/go-gst) +![](https://github.com/tinyzimmer/go-gst/workflows/Tests/badge.svg) See the go.dev reference for documentation and examples. diff --git a/gst/app/gst.go.c b/gst/app/gst.go.c deleted file mode 100644 index 499c09d..0000000 --- a/gst/app/gst.go.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -GstAppSink * -toGstAppSink(void *p) -{ - return (GST_APP_SINK(p)); -} - -GstAppSrc * -toGstAppSrc(void *p) -{ - return (GST_APP_SRC(p)); -} diff --git a/gst/app/gst.go.h b/gst/app/gst.go.h index 146755e..f175d0a 100644 --- a/gst/app/gst.go.h +++ b/gst/app/gst.go.h @@ -1,5 +1,5 @@ #include #include -GstAppSink * toGstAppSink (void *p); -GstAppSrc * toGstAppSrc (void *p); +inline GstAppSink * toGstAppSink (void *p) { return (GST_APP_SINK(p)); } +inline GstAppSrc * toGstAppSrc (void *p) { return (GST_APP_SRC(p)); } diff --git a/gst/c_util.go b/gst/c_util.go index dd581af..b4ddbd0 100644 --- a/gst/c_util.go +++ b/gst/c_util.go @@ -1,7 +1,8 @@ package gst -// #include +// #include "gst.go.h" import "C" + import ( "unsafe" ) diff --git a/gst/cgo_exports.go b/gst/cgo_exports.go new file mode 100644 index 0000000..c9c311f --- /dev/null +++ b/gst/cgo_exports.go @@ -0,0 +1,58 @@ +package gst + +// CGO exports have to be defined in a separate file from where they are used or else +// there will be double linkage issues. + +// #include +import "C" + +import ( + "unsafe" + + "github.com/gotk3/gotk3/glib" + gopointer "github.com/mattn/go-pointer" +) + +//export structForEachCb +func structForEachCb(fieldID C.GQuark, val *C.GValue, chPtr C.gpointer) C.gboolean { + ptr := gopointer.Restore(unsafe.Pointer(chPtr)) + resCh := ptr.(chan interface{}) + fieldName := C.GoString(C.g_quark_to_string(fieldID)) + + var resValue interface{} + + gVal := glib.ValueFromNative(unsafe.Pointer(val)) + if resValue, _ = gVal.GoValue(); resValue == nil { + // serialize the value if we can't do anything else with it + serialized := C.gst_value_serialize(val) + defer C.free(unsafe.Pointer(serialized)) + resValue = C.GoString(serialized) + } + + resCh <- fieldName + resCh <- resValue + return gboolean(true) +} + +//export goBusFunc +func goBusFunc(bus *C.GstBus, cMsg *C.GstMessage, userData C.gpointer) C.gboolean { + // wrap the message + msg := wrapMessage(cMsg) + + // retrieve the ptr to the function + ptr := unsafe.Pointer(userData) + funcIface := gopointer.Restore(ptr) + busFunc, ok := funcIface.(BusWatchFunc) + if !ok { + gopointer.Unref(ptr) + return gboolean(false) + } + + // run the call back + if cont := busFunc(msg); !cont { + gopointer.Unref(ptr) + return gboolean(false) + } + + return gboolean(true) +} diff --git a/gst/gst.go.c b/gst/gst.go.c deleted file mode 100644 index 001f641..0000000 --- a/gst/gst.go.c +++ /dev/null @@ -1,301 +0,0 @@ -#include -#include "gst.go.h" - -/* - Utilitits -*/ - -gboolean isParamSpecTypeCaps (GParamSpec * p) -{ - return p->value_type == GST_TYPE_CAPS; -} - -gboolean isParamSpecEnum (GParamSpec * p) -{ - return G_IS_PARAM_SPEC_ENUM(p); -} - -gboolean isParamSpecFlags (GParamSpec * p) -{ - return G_IS_PARAM_SPEC_FLAGS(p); -} - -gboolean isParamSpecObject (GParamSpec * p) -{ - return G_IS_PARAM_SPEC_OBJECT(p); -} - -gboolean isParamSpecBoxed (GParamSpec * p) -{ - return G_IS_PARAM_SPEC_BOXED(p); -} - -gboolean isParamSpecPointer (GParamSpec * p) -{ - return G_IS_PARAM_SPEC_POINTER(p); -} - -gboolean isParamSpecFraction (GParamSpec * p) -{ - return GST_IS_PARAM_SPEC_FRACTION(p); -} - -gboolean isParamSpecGstArray (GParamSpec * p) -{ - return p->value_type == GST_TYPE_ARRAY; -} - -GEnumValue * getEnumValues (GParamSpec * p, guint * size) -{ - GEnumValue * values; - values = G_ENUM_CLASS (g_type_class_ref (p->value_type))->values; - guint i = 0; - while (values[i].value_name) { - ++i; - } - *size = i; - return values; -} - -GFlagsValue * getParamSpecFlags (GParamSpec * p, guint * size) -{ - GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (p); - GFlagsValue *vals = pflags->flags_class->values; - guint i = 0; - while (vals[i].value_name) { - ++i; - } - *size = i; - return vals; -} - -gboolean cgoBusFunc (GstBus * bus, GstMessage * msg, gpointer user_data) -{ - return goBusFunc(bus, msg, user_data); -} - -gboolean structureForEach (GQuark field_id, GValue * value, gpointer user_data) -{ - return structForEachCb(field_id, value, user_data); -} - -GObjectClass * getGObjectClass (void * p) { - return G_OBJECT_GET_CLASS (p); -} - -int sizeOfGCharArray (gchar ** arr) { - int i; - for (i = 0 ; 1 ; i = i + 1) { - if (arr[i] == NULL) { return i; }; - } -} - -gboolean gstObjectFlagIsSet (GstObject * obj, GstElementFlags flags) -{ - return GST_OBJECT_FLAG_IS_SET (obj, flags); -} - -gboolean gstElementIsURIHandler (GstElement * elem) -{ - return GST_IS_URI_HANDLER (elem); -} - -/* - Number functions -*/ - -GParamSpecUInt * getParamUInt (GParamSpec * param) -{ - return G_PARAM_SPEC_UINT (param); -} - -GParamSpecInt * getParamInt (GParamSpec * param) -{ - return G_PARAM_SPEC_INT (param); -} - -GParamSpecUInt64 * getParamUInt64 (GParamSpec * param) -{ - return G_PARAM_SPEC_UINT64 (param); -} - -GParamSpecInt64 * getParamInt64 (GParamSpec * param) -{ - return G_PARAM_SPEC_INT64 (param); -} - -GParamSpecFloat * getParamFloat (GParamSpec * param) -{ - return G_PARAM_SPEC_FLOAT (param); -} - -GParamSpecDouble * getParamDouble(GParamSpec * param) -{ - return G_PARAM_SPEC_DOUBLE (param); -} - -/* - Type Castings -*/ - -GstAllocator * -toGstAllocator(void *p) -{ - return (GST_ALLOCATOR_CAST(p)); -} - -GstUri * -toGstURI(void *p) -{ - return (GST_URI(p)); -} - -GstURIHandler * -toGstURIHandler(void *p) -{ - return (GST_URI_HANDLER(p)); -} - -GstRegistry * -toGstRegistry(void *p) -{ - return (GST_REGISTRY(p)); -} - -GstPlugin * -toGstPlugin(void *p) -{ - return (GST_PLUGIN(p)); -} - -GstPluginFeature * -toGstPluginFeature(void *p) -{ - return (GST_PLUGIN_FEATURE(p)); -} - -GstObject * -toGstObject(void *p) -{ - return (GST_OBJECT(p)); -} - -GstElementFactory * -toGstElementFactory(void *p) -{ - return (GST_ELEMENT_FACTORY(p)); -} - -GstElement * -toGstElement(void *p) -{ - return (GST_ELEMENT(p)); -} - -GstBin * -toGstBin(void *p) -{ - return (GST_BIN(p)); -} - -GstBus * -toGstBus(void *p) -{ - return (GST_BUS(p)); -} - -GstMessage * -toGstMessage(void *p) -{ - return (GST_MESSAGE(p)); -} - -GstPipeline * -toGstPipeline(void *p) -{ - return (GST_PIPELINE(p)); -} - -GstPad * -toGstPad(void *p) -{ - return (GST_PAD(p)); -} - -GstPadTemplate * -toGstPadTemplate(void *p) -{ - return (GST_PAD_TEMPLATE(p)); -} - -GstStructure * -toGstStructure(void *p) -{ - return (GST_STRUCTURE(p)); -} - -GstClock * -toGstClock(void *p) -{ - return (GST_CLOCK(p)); -} - -GstMiniObject * -toGstMiniObject(void *p) -{ - return (GST_MINI_OBJECT(p)); -} - -GstCaps * -toGstCaps(void *p) -{ - return (GST_CAPS(p)); -} - -GstCapsFeatures * -toGstCapsFeatures(void *p) -{ - return (GST_CAPS_FEATURES(p)); -} - -GstBuffer * -toGstBuffer(void *p) -{ - return (GST_BUFFER(p)); -} - -GstBufferPool * -toGstBufferPool(void *p) -{ - return (GST_BUFFER_POOL(p)); -} - -GstSample * -toGstSample(void *p) -{ - return (GST_SAMPLE(p)); -} - -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)); -} - -GstMemory * -toGstMemory(void *p) -{ - return (GST_MEMORY_CAST(p)); -} \ No newline at end of file diff --git a/gst/gst.go.h b/gst/gst.go.h index acdf0fa..ad4897d 100644 --- a/gst/gst.go.h +++ b/gst/gst.go.h @@ -1,69 +1,98 @@ +#ifndef __GST_GO_H__ +#define __GST_GO_H__ + #include -extern gboolean structForEachCb (GQuark field_id, GValue * value, gpointer user_data); -extern gboolean goBusFunc (GstBus * bus, GstMessage * msg, gpointer user_data); - -gboolean structureForEach (GQuark field_id, GValue * value, gpointer user_data); -gboolean cgoBusFunc (GstBus * bus, GstMessage * msg, gpointer user_data); - -GEnumValue * getEnumValues (GParamSpec * p, guint * size); -GFlagsValue * getParamSpecFlags (GParamSpec * p, guint * size); - -int sizeOfGCharArray (gchar ** arr); - -gboolean isParamSpecTypeCaps (GParamSpec * p); -gboolean isParamSpecEnum (GParamSpec * p); -gboolean isParamSpecFlags (GParamSpec * p); -gboolean isParamSpecObject (GParamSpec * p); -gboolean isParamSpecBoxed (GParamSpec * p); -gboolean isParamSpecPointer (GParamSpec * p); -gboolean isParamSpecFraction (GParamSpec * p); -gboolean isParamSpecGstArray (GParamSpec * p); - -GObjectClass * getGObjectClass (void * p); - -gboolean gstObjectFlagIsSet (GstObject * obj, GstElementFlags flags); -gboolean gstElementIsURIHandler (GstElement * elem); - -/* - Number functions -*/ - -GParamSpecUInt * getParamUInt (GParamSpec * param); -GParamSpecInt * getParamInt (GParamSpec * param); -GParamSpecUInt64 * getParamUInt64 (GParamSpec * param); -GParamSpecInt64 * getParamInt64 (GParamSpec * param); -GParamSpecFloat * getParamFloat (GParamSpec * param); -GParamSpecDouble * getParamDouble (GParamSpec * param); - /* Type Castings */ -GstAllocator * toGstAllocator (void *p); -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); -GstMemory * toGstMemory (void *p); \ No newline at end of file +inline GstAllocator * toGstAllocator (void *p) { return (GST_ALLOCATOR_CAST(p)); } +inline GstBin * toGstBin (void *p) { return (GST_BIN(p)); } +inline GstBufferPool * toGstBufferPool (void *p) { return (GST_BUFFER_POOL(p)); } +inline GstBuffer * toGstBuffer (void *p) { return (GST_BUFFER(p)); } +inline GstBus * toGstBus (void *p) { return (GST_BUS(p)); } +inline GstCapsFeatures * toGstCapsFeatures (void *p) { return (GST_CAPS_FEATURES(p)); } +inline GstCaps * toGstCaps (void *p) { return (GST_CAPS(p)); } +inline GstClock * toGstClock (void *p) { return (GST_CLOCK(p)); } +inline GstDevice * toGstDevice (void *p) { return (GST_DEVICE_CAST(p)); } +inline GstElementFactory * toGstElementFactory (void *p) { return (GST_ELEMENT_FACTORY(p)); } +inline GstElement * toGstElement (void *p) { return (GST_ELEMENT(p)); } +inline GstMemory * toGstMemory (void *p) { return (GST_MEMORY_CAST(p)); } +inline GstMessage * toGstMessage (void *p) { return (GST_MESSAGE(p)); } +inline GstMeta * toGstMeta (void *p) { return (GST_META_CAST(p)); } +inline GstMiniObject * toGstMiniObject (void *p) { return (GST_MINI_OBJECT(p)); } +inline GstObject * toGstObject (void *p) { return (GST_OBJECT(p)); } +inline GstPadTemplate * toGstPadTemplate (void *p) { return (GST_PAD_TEMPLATE(p)); } +inline GstPad * toGstPad (void *p) { return (GST_PAD(p)); } +inline GstPipeline * toGstPipeline (void *p) { return (GST_PIPELINE(p)); } +inline GstPluginFeature * toGstPluginFeature (void *p) { return (GST_PLUGIN_FEATURE(p)); } +inline GstPlugin * toGstPlugin (void *p) { return (GST_PLUGIN(p)); } +inline GstRegistry * toGstRegistry (void *p) { return (GST_REGISTRY(p)); } +inline GstSample * toGstSample (void *p) { return (GST_SAMPLE(p)); } +inline GstStreamCollection * toGstStreamCollection (void *p) { return (GST_STREAM_COLLECTION_CAST(p)); } +inline GstStream * toGstStream (void *p) { return (GST_STREAM_CAST(p)); } +inline GstStructure * toGstStructure (void *p) { return (GST_STRUCTURE(p)); } +inline GstURIHandler * toGstURIHandler (void *p) { return (GST_URI_HANDLER(p)); } +inline GstUri * toGstURI (void *p) { return (GST_URI(p)); } + +/* Object Utilities */ + +inline GObjectClass * getGObjectClass (void * p) { return (G_OBJECT_GET_CLASS(p)); } +inline gboolean gstElementIsURIHandler (GstElement * elem) { return (GST_IS_URI_HANDLER(elem)); } +inline gboolean gstObjectFlagIsSet (GstObject * obj, GstElementFlags flags) { return (GST_OBJECT_FLAG_IS_SET(obj, flags)); } + +/* + ParamSpec Utilities +*/ + +inline gboolean isParamSpecTypeCaps (GParamSpec * p) { return p->value_type == GST_TYPE_CAPS; } +inline gboolean isParamSpecEnum (GParamSpec * p) { return (G_IS_PARAM_SPEC_ENUM(p)); } +inline gboolean isParamSpecFlags (GParamSpec * p) { return (G_IS_PARAM_SPEC_FLAGS(p)); } +inline gboolean isParamSpecObject (GParamSpec * p) { return (G_IS_PARAM_SPEC_OBJECT(p)); } +inline gboolean isParamSpecBoxed (GParamSpec * p) { return (G_IS_PARAM_SPEC_BOXED(p)); } +inline gboolean isParamSpecPointer (GParamSpec * p) { return (G_IS_PARAM_SPEC_POINTER(p)); } +inline gboolean isParamSpecFraction (GParamSpec * p) { return (GST_IS_PARAM_SPEC_FRACTION(p)); } +inline gboolean isParamSpecGstArray (GParamSpec * p) { return p->value_type == GST_TYPE_ARRAY; } + +inline GParamSpecUInt * getParamUInt (GParamSpec * param) { return (G_PARAM_SPEC_UINT(param)); } +inline GParamSpecInt * getParamInt (GParamSpec * param) { return (G_PARAM_SPEC_INT(param)); } +inline GParamSpecUInt64 * getParamUInt64 (GParamSpec * param) { return (G_PARAM_SPEC_UINT64(param)); } +inline GParamSpecInt64 * getParamInt64 (GParamSpec * param) { return (G_PARAM_SPEC_INT64(param)); } +inline GParamSpecFloat * getParamFloat (GParamSpec * param) { return (G_PARAM_SPEC_FLOAT(param)); } +inline GParamSpecDouble * getParamDouble (GParamSpec * param) { return (G_PARAM_SPEC_DOUBLE(param)); } + +inline GEnumValue * getEnumValues (GParamSpec * p, guint * size) +{ + GEnumValue * values; + values = G_ENUM_CLASS (g_type_class_ref (p->value_type))->values; + guint i = 0; + while (values[i].value_name) { + ++i; + } + *size = i; + return values; +} + +inline GFlagsValue * getParamSpecFlags (GParamSpec * p, guint * size) +{ + GParamSpecFlags * pflags = G_PARAM_SPEC_FLAGS (p); + GFlagsValue * vals = pflags->flags_class->values; + guint i = 0; + while (vals[i].value_name) { + ++i; + } + *size = i; + return vals; +} + +/* Misc */ +inline int sizeOfGCharArray (gchar ** arr) +{ + int i; + for (i = 0 ; 1 ; i = i + 1) { + if (arr[i] == NULL) { return i; }; + } +} + +#endif diff --git a/gst/gst_allocator.go b/gst/gst_allocator.go index aaf159b..eaa0387 100644 --- a/gst/gst_allocator.go +++ b/gst/gst_allocator.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "unsafe" diff --git a/gst/gst_atomic_queue.go b/gst/gst_atomic_queue.go index 35e98fd..fab93e7 100644 --- a/gst/gst_atomic_queue.go +++ b/gst/gst_atomic_queue.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "unsafe" diff --git a/gst/gst_bin.go b/gst/gst_bin.go index 61bb803..45bf0f7 100644 --- a/gst/gst_bin.go +++ b/gst/gst_bin.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "errors" "fmt" diff --git a/gst/gst_buffer.go b/gst/gst_buffer.go index 9f764cf..b4832b7 100644 --- a/gst/gst_buffer.go +++ b/gst/gst_buffer.go @@ -2,12 +2,15 @@ package gst // #include "gst.go.h" import "C" + import ( "bytes" "io" "io/ioutil" "time" "unsafe" + + "github.com/gotk3/gotk3/glib" ) // Buffer is a go representation of a GstBuffer. @@ -100,3 +103,10 @@ func (b *Buffer) Map() *MapInfo { C.gst_buffer_unmap(b.Instance(), (*C.GstMapInfo)(unsafe.Pointer(&mapInfo))) }) } + +// GetMeta retrieves the metadata on the buffer for the given api. If none exists +// then nil is returned. +func (b *Buffer) GetMeta(api glib.Type) *Meta { + meta := C.gst_buffer_get_meta(b.Instance(), C.GType(api)) + return wrapMeta(meta) +} diff --git a/gst/gst_bus.go b/gst/gst_bus.go index 772a3dd..baacf37 100644 --- a/gst/gst_bus.go +++ b/gst/gst_bus.go @@ -1,6 +1,15 @@ package gst -// #include "gst.go.h" +/* +#include "gst.go.h" + +extern gboolean goBusFunc (GstBus * bus, GstMessage * msg, gpointer user_data); + +gboolean cgoBusFunc (GstBus * bus, GstMessage * msg, gpointer user_data) +{ + return goBusFunc(bus, msg, user_data); +} +*/ import "C" import ( @@ -100,29 +109,6 @@ func (b *Bus) BlockPopMessage() *Message { // the message unless addtional references are placed on it during processing. type BusWatchFunc func(msg *Message) bool -//export goBusFunc -func goBusFunc(bus *C.GstBus, cMsg *C.GstMessage, userData C.gpointer) C.gboolean { - // wrap the message - msg := wrapMessage(cMsg) - - // retrieve the ptr to the function - ptr := unsafe.Pointer(userData) - funcIface := gopointer.Restore(ptr) - busFunc, ok := funcIface.(BusWatchFunc) - if !ok { - gopointer.Unref(ptr) - return gboolean(false) - } - - // run the call back - if cont := busFunc(msg); !cont { - gopointer.Unref(ptr) - return gboolean(false) - } - - return gboolean(true) -} - // AddWatch adds a watch to the default MainContext for messages emitted on this bus. // This function is used to receive asynchronous messages in the main loop. There can // only be a single bus watch per bus, you must remove it before you can set a new one. diff --git a/gst/gst_clock.go b/gst/gst_clock.go index 4bf5418..4928ef8 100644 --- a/gst/gst_clock.go +++ b/gst/gst_clock.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import "time" // Clock is a go wrapper around a GstClock. diff --git a/gst/gst_constants.go b/gst/gst_constants.go index 74758a2..44f5905 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 @@ -413,3 +414,37 @@ const ( MemoryFlagNotMappable MemoryFlags = C.GST_MEMORY_FLAG_NOT_MAPPABLE // (256) – the memory can't be mapped via gst_memory_map without any preconditions. (Since: 1.2) MemoryFlagLast MemoryFlags = 1048576 // first flag that can be used for custom purposes ) + +// URIType casts C GstURIType to a go type +type URIType int + +// Type cast URI types +const ( + URIUnknown URIType = C.GST_URI_UNKNOWN // (0) – The URI direction is unknown + URISink URIType = C.GST_URI_SINK // (1) – The URI is a consumer. + URISource URIType = C.GST_URI_SRC // (2) - The URI is a producer. +) + +func (u URIType) String() string { + switch u { + case URIUnknown: + return "Unknown" + case URISink: + return "Sink" + case URISource: + return "Source" + } + return "" +} + +// MetaFlags casts C GstMetaFlags to a go type. +type MetaFlags int + +// Type casts of GstMetaFlags +const ( + MetaFlagNone MetaFlags = C.GST_META_FLAG_NONE // (0) – no flags + MetaFlagReadOnly MetaFlags = C.GST_META_FLAG_READONLY // (1) – metadata should not be modified + MetaFlagPooled MetaFlags = C.GST_META_FLAG_POOLED // (2) – metadata is managed by a bufferpool + MetaFlagLocked MetaFlags = C.GST_META_FLAG_LOCKED // (4) – metadata should not be removed + MetaFlagLast MetaFlags = C.GST_META_FLAG_LAST // (65536) – additional flags can be added starting from this flag. +) diff --git a/gst/gst_device.go b/gst/gst_device.go index 245cfe7..91bb553 100644 --- a/gst/gst_device.go +++ b/gst/gst_device.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "fmt" "strings" diff --git a/gst/gst_element_factory.go b/gst/gst_element_factory.go index e30f08c..8f95e38 100644 --- a/gst/gst_element_factory.go +++ b/gst/gst_element_factory.go @@ -54,23 +54,23 @@ func Find(name string) *ElementFactory { func (e *ElementFactory) Instance() *C.GstElementFactory { return C.toGstElementFactory(e.Unsafe()) } // CanSinkAllCaps checks if the factory can sink all possible capabilities. -func (e *ElementFactory) CanSinkAllCaps(caps *C.GstCaps) bool { - return gobool(C.gst_element_factory_can_sink_all_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps))) +func (e *ElementFactory) CanSinkAllCaps(caps *Caps) bool { + return gobool(C.gst_element_factory_can_sink_all_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps.Instance()))) } // CanSinkAnyCaps checks if the factory can sink any possible capability. -func (e *ElementFactory) CanSinkAnyCaps(caps *C.GstCaps) bool { - return gobool(C.gst_element_factory_can_sink_any_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps))) +func (e *ElementFactory) CanSinkAnyCaps(caps *Caps) bool { + return gobool(C.gst_element_factory_can_sink_any_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps.Instance()))) } // CanSourceAllCaps checks if the factory can src all possible capabilities. -func (e *ElementFactory) CanSourceAllCaps(caps *C.GstCaps) bool { - return gobool(C.gst_element_factory_can_src_all_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps))) +func (e *ElementFactory) CanSourceAllCaps(caps *Caps) bool { + return gobool(C.gst_element_factory_can_src_all_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps.Instance()))) } // CanSourceAnyCaps checks if the factory can src any possible capability. -func (e *ElementFactory) CanSourceAnyCaps(caps *C.GstCaps) bool { - return gobool(C.gst_element_factory_can_src_any_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps))) +func (e *ElementFactory) CanSourceAnyCaps(caps *Caps) bool { + return gobool(C.gst_element_factory_can_src_any_caps((*C.GstElementFactory)(e.Instance()), (*C.GstCaps)(caps.Instance()))) } // GetMetadata gets the metadata on this factory with key. diff --git a/gst/init.go b/gst/gst_init.go similarity index 100% rename from gst/init.go rename to gst/gst_init.go diff --git a/gst/gst_memory.go b/gst/gst_memory.go index 17915b4..e262db7 100644 --- a/gst/gst_memory.go +++ b/gst/gst_memory.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "fmt" "unsafe" diff --git a/gst/gst_meta.go b/gst/gst_meta.go new file mode 100644 index 0000000..8468203 --- /dev/null +++ b/gst/gst_meta.go @@ -0,0 +1,40 @@ +package gst + +// #include "gst.go.h" +import "C" +import ( + "unsafe" + + "github.com/gotk3/gotk3/glib" +) + +// Meta is a go representation of GstMeta. +type Meta struct { + ptr *C.GstMeta +} + +// Instance returns the underlying GstMeta instance. +func (m *Meta) Instance() *C.GstMeta { return C.toGstMeta(unsafe.Pointer(m.ptr)) } + +// Flags returns the flags on this Meta instance. +func (m *Meta) Flags() MetaFlags { return MetaFlags(m.Instance().flags) } + +// Info returns the extra info with this metadata. +func (m *Meta) Info() *MetaInfo { return wrapMetaInfo(m.Instance().info) } + +// MetaInfo is a go representation of GstMetaInfo +type MetaInfo struct { + ptr *C.GstMetaInfo +} + +// Instance returns the underlying GstMetaInfo instance. +func (m *MetaInfo) Instance() *C.GstMetaInfo { return m.ptr } + +// API returns the tag identifying the metadata structure and api. +func (m *MetaInfo) API() glib.Type { return glib.Type(m.Instance().api) } + +// Type returns the type identifying the implementor of the api. +func (m *MetaInfo) Type() glib.Type { return glib.Type(m.Instance()._type) } + +// Size returns the size of the metadata. +func (m *MetaInfo) Size() int64 { return int64(m.Instance().size) } diff --git a/gst/gst_pad.go b/gst/gst_pad.go index d310cae..0e13060 100644 --- a/gst/gst_pad.go +++ b/gst/gst_pad.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "unsafe" diff --git a/gst/gst_plugin_feature.go b/gst/gst_plugin_feature.go index a17faf2..d29c8ba 100644 --- a/gst/gst_plugin_feature.go +++ b/gst/gst_plugin_feature.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "unsafe" diff --git a/gst/gst_registry.go b/gst/gst_registry.go index 869df8b..5cdcb8b 100644 --- a/gst/gst_registry.go +++ b/gst/gst_registry.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "fmt" "unsafe" diff --git a/gst/gst_sample.go b/gst/gst_sample.go index dde5470..3a101d2 100644 --- a/gst/gst_sample.go +++ b/gst/gst_sample.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import "unsafe" // Sample is a go wrapper around a GstSample object. diff --git a/gst/gst_stream.go b/gst/gst_stream.go index 939327a..293d1a3 100644 --- a/gst/gst_stream.go +++ b/gst/gst_stream.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "unsafe" diff --git a/gst/gst_stream_collection.go b/gst/gst_stream_collection.go index 1690da4..e66456f 100644 --- a/gst/gst_stream_collection.go +++ b/gst/gst_stream_collection.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "fmt" "unsafe" diff --git a/gst/gst_structure.go b/gst/gst_structure.go index ee3fc5c..61e4407 100644 --- a/gst/gst_structure.go +++ b/gst/gst_structure.go @@ -1,6 +1,15 @@ package gst -// #include "gst.go.h" +/* +#include "gst.go.h" + +extern gboolean structForEachCb (GQuark field_id, GValue * value, gpointer user_data); + +gboolean structureForEach (GQuark field_id, GValue * value, gpointer user_data) +{ + return structForEachCb(field_id, value, user_data); +} +*/ import "C" import ( @@ -101,27 +110,6 @@ func (s *Structure) RemoveValue(key string) { C.gst_structure_remove_field(s.Instance(), cKey) } -//export structForEachCb -func structForEachCb(fieldID C.GQuark, val *C.GValue, chPtr C.gpointer) C.gboolean { - ptr := gopointer.Restore(unsafe.Pointer(chPtr)) - resCh := ptr.(chan interface{}) - fieldName := C.GoString(C.g_quark_to_string(fieldID)) - - var resValue interface{} - - gVal := glib.ValueFromNative(unsafe.Pointer(val)) - if resValue, _ = gVal.GoValue(); resValue == nil { - // serialize the value if we can't do anything else with it - serialized := C.gst_value_serialize(val) - defer C.free(unsafe.Pointer(serialized)) - resValue = C.GoString(serialized) - } - - resCh <- fieldName - resCh <- resValue - return gboolean(true) -} - // Values returns a map of all the values inside this structure. If values cannot be // converted to an equivalent go type, they are serialized to a string. func (s *Structure) Values() map[string]interface{} { diff --git a/gst/gst_tag_list.go b/gst/gst_tag_list.go index 6355638..075c2fe 100644 --- a/gst/gst_tag_list.go +++ b/gst/gst_tag_list.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import "unsafe" // TagList is a go wrapper around a GstTagList. For now, until the rest of the methods are diff --git a/gst/gst_uri.go b/gst/gst_uri.go deleted file mode 100644 index 3a80075..0000000 --- a/gst/gst_uri.go +++ /dev/null @@ -1,26 +0,0 @@ -package gst - -// #include "gst.go.h" -import "C" - -// URIType casts C GstURIType to a go type -type URIType C.GstURIType - -// Type cast URI types -const ( - URIUnknown URIType = C.GST_URI_UNKNOWN // (0) – The URI direction is unknown - URISink = C.GST_URI_SINK // (1) – The URI is a consumer. - URISource = C.GST_URI_SRC // (2) - The URI is a producer. -) - -func (u URIType) String() string { - switch u { - case URIUnknown: - return "Unknown" - case URISink: - return "Sink" - case URISource: - return "Source" - } - return "" -} diff --git a/gst/gst_wrappers.go b/gst/gst_wrappers.go index c62315f..cf1cf86 100644 --- a/gst/gst_wrappers.go +++ b/gst/gst_wrappers.go @@ -2,6 +2,7 @@ package gst // #include "gst.go.h" import "C" + import ( "time" "unsafe" @@ -103,6 +104,31 @@ func init() { // Object wrappers +func wrapAllocator(obj *glib.Object) *Allocator { return &Allocator{wrapObject(obj)} } +func wrapAtomicQueue(queue *C.GstAtomicQueue) *AtomicQueue { return &AtomicQueue{ptr: queue} } +func wrapBin(obj *glib.Object) *Bin { return &Bin{wrapElement(obj)} } +func wrapBuffer(buf *C.GstBuffer) *Buffer { return &Buffer{ptr: buf} } +func wrapBus(obj *glib.Object) *Bus { return &Bus{Object: wrapObject(obj)} } +func wrapClock(obj *glib.Object) *Clock { return &Clock{wrapObject(obj)} } +func wrapDevice(obj *glib.Object) *Device { return &Device{wrapObject(obj)} } +func wrapElement(obj *glib.Object) *Element { return &Element{wrapObject(obj)} } +func wrapGhostPad(obj *glib.Object) *GhostPad { return &GhostPad{wrapPad(obj)} } +func wrapMainContext(ctx *C.GMainContext) *MainContext { return &MainContext{ptr: ctx} } +func wrapMainLoop(loop *C.GMainLoop) *MainLoop { return &MainLoop{ptr: loop} } +func wrapMemory(mem *C.GstMemory) *Memory { return &Memory{ptr: mem} } +func wrapMessage(msg *C.GstMessage) *Message { return &Message{msg: msg} } +func wrapMeta(meta *C.GstMeta) *Meta { return &Meta{ptr: meta} } +func wrapMetaInfo(info *C.GstMetaInfo) *MetaInfo { return &MetaInfo{ptr: info} } +func wrapPad(obj *glib.Object) *Pad { return &Pad{wrapObject(obj)} } +func wrapPadTemplate(obj *glib.Object) *PadTemplate { return &PadTemplate{wrapObject(obj)} } +func wrapPipeline(obj *glib.Object) *Pipeline { return &Pipeline{Bin: wrapBin(obj)} } +func wrapPluginFeature(obj *glib.Object) *PluginFeature { return &PluginFeature{wrapObject(obj)} } +func wrapPlugin(obj *glib.Object) *Plugin { return &Plugin{wrapObject(obj)} } +func wrapRegistry(obj *glib.Object) *Registry { return &Registry{wrapObject(obj)} } +func wrapSample(sample *C.GstSample) *Sample { return &Sample{sample: sample} } +func wrapStream(obj *glib.Object) *Stream { return &Stream{wrapObject(obj)} } +func wrapTagList(tagList *C.GstTagList) *TagList { return &TagList{ptr: tagList} } + func wrapObject(obj *glib.Object) *Object { return &Object{InitiallyUnowned: &glib.InitiallyUnowned{Object: obj}} } @@ -111,29 +137,6 @@ func wrapElementFactory(obj *glib.Object) *ElementFactory { return &ElementFactory{wrapPluginFeature(obj)} } -func wrapAtomicQueue(queue *C.GstAtomicQueue) *AtomicQueue { return &AtomicQueue{ptr: queue} } -func wrapDevice(obj *glib.Object) *Device { return &Device{wrapObject(obj)} } -func wrapPluginFeature(obj *glib.Object) *PluginFeature { return &PluginFeature{wrapObject(obj)} } -func wrapPipeline(obj *glib.Object) *Pipeline { return &Pipeline{Bin: wrapBin(obj)} } -func wrapElement(obj *glib.Object) *Element { return &Element{wrapObject(obj)} } -func wrapBin(obj *glib.Object) *Bin { return &Bin{wrapElement(obj)} } -func wrapClock(obj *glib.Object) *Clock { return &Clock{wrapObject(obj)} } -func wrapBus(obj *glib.Object) *Bus { return &Bus{Object: wrapObject(obj)} } -func wrapMessage(msg *C.GstMessage) *Message { return &Message{msg: msg} } -func wrapTagList(tagList *C.GstTagList) *TagList { return &TagList{ptr: tagList} } -func wrapPad(obj *glib.Object) *Pad { return &Pad{wrapObject(obj)} } -func wrapPadTemplate(obj *glib.Object) *PadTemplate { return &PadTemplate{wrapObject(obj)} } -func wrapGhostPad(obj *glib.Object) *GhostPad { return &GhostPad{wrapPad(obj)} } -func wrapPlugin(obj *glib.Object) *Plugin { return &Plugin{wrapObject(obj)} } -func wrapRegistry(obj *glib.Object) *Registry { return &Registry{wrapObject(obj)} } -func wrapSample(sample *C.GstSample) *Sample { return &Sample{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 wrapAllocator(obj *glib.Object) *Allocator { return &Allocator{wrapObject(obj)} } -func wrapMemory(mem *C.GstMemory) *Memory { return &Memory{ptr: mem} } - func wrapStreamCollection(obj *glib.Object) *StreamCollection { return &StreamCollection{wrapObject(obj)} } diff --git a/gst/pkg_config.go b/gst/pkg_config.go index 802b653..29e76e4 100644 --- a/gst/pkg_config.go +++ b/gst/pkg_config.go @@ -3,5 +3,6 @@ package gst /* #cgo pkg-config: gstreamer-1.0 #cgo CFLAGS: -Wno-deprecated-declarations -g -Wall +#cgo LDFLAGS: -lm */ import "C"