├── .gitignore ├── README.md ├── go.mod ├── gstreamer.c ├── gstreamer.go ├── gstreamer.h └── gstreamer_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gstreamer-go 2 | gstreamer simple wrap for golang 3 | 4 | 5 | ## You can also try https://github.com/notedit/gst 6 | 7 | ## Install 8 | 9 | 10 | Ubuntu or Dedian 11 | 12 | ```sh 13 | apt-get install pkg-config 14 | apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-ugly gstreamer1.0-libav 15 | ``` 16 | 17 | Mac os 18 | 19 | ```sh 20 | brew install gstreamer 21 | brew install gst-plugins-base 22 | brew install gst-plugins-good 23 | brew install gst-plugins-bad 24 | brew install gst-plugins-ugly 25 | ``` 26 | 27 | Then 28 | 29 | ```sh 30 | go get github.com/notedit/gstreamer-go 31 | ``` 32 | 33 | 34 | ## How to use 35 | 36 | ```go 37 | pipeline, err := New("videotestsrc ! capsfilter name=filter ! autovideosink") 38 | if err != nil { 39 | t.Error("pipeline create error", err) 40 | t.FailNow() 41 | } 42 | 43 | filter := pipeline.FindElement("filter") 44 | 45 | if filter == nil { 46 | t.Error("pipeline find element error ") 47 | } 48 | 49 | filter.SetCap("video/x-raw,width=1280,height=720") 50 | 51 | pipeline.Start() 52 | 53 | ``` 54 | 55 | 56 | ## Send Media data to pipeline 57 | 58 | ```go 59 | pipeline, err := New("appsrc name=mysource format=time is-live=true do-timestamp=true ! videoconvert ! autovideosink") 60 | 61 | if err != nil { 62 | t.Error("pipeline create error", err) 63 | t.FailNow() 64 | } 65 | 66 | appsrc := pipeline.FindElement("mysource") 67 | 68 | appsrc.SetCap("video/x-raw,format=RGB,width=320,height=240,bpp=24,depth=24") 69 | 70 | pipeline.Start() 71 | 72 | for { 73 | time.Sleep(1 * time.Second) 74 | appsrc.Push(make([]byte, 320*240*3)) 75 | } 76 | 77 | ``` 78 | 79 | push raw rgb data to the pipeline 80 | 81 | 82 | ## Poll Media data from pipeline 83 | 84 | ```go 85 | pipeline, err := New("videotestsrc ! video/x-raw,format=I420,framerate=15/1 ! x264enc bframes=0 speed-preset=veryfast key-int-max=60 ! video/x-h264,stream-format=byte-stream ! appsink name=sink") 86 | 87 | if err != nil { 88 | t.Error("pipeline create error", err) 89 | t.FailNow() 90 | } 91 | 92 | appsink := pipeline.FindElement("sink") 93 | 94 | pipeline.Start() 95 | 96 | out := appsink.Poll() 97 | 98 | for { 99 | buffer := <-out 100 | fmt.Println("push ", len(buffer)) 101 | } 102 | ``` 103 | 104 | now we can get the h264 raw data from the pipeline 105 | 106 | 107 | ## Check Plugins does exist 108 | 109 | ```go 110 | 111 | plugins := []string{"videotestsrc", "audiotestsrc", "rtp", "curl","x264", "rtmp"} 112 | 113 | err := CheckPlugins(plugins) 114 | 115 | if err != nil { 116 | panic(err) 117 | } 118 | 119 | ``` 120 | 121 | 122 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/notedit/gstreamer-go 2 | -------------------------------------------------------------------------------- /gstreamer.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "gstreamer.h" 4 | #include 5 | #include 6 | 7 | 8 | 9 | void gstreamer_init() { 10 | gst_init(NULL, NULL); 11 | } 12 | 13 | 14 | // MESSAGE_UNKNOWN MessageType = C.GST_MESSAGE_UNKNOWN 15 | // MESSAGE_EOS MessageType = C.GST_MESSAGE_EOS 16 | // MESSAGE_ERROR MessageType = C.GST_MESSAGE_ERROR 17 | // MESSAGE_TAG MessageType = C.GST_MESSAGE_TAG 18 | // MESSAGE_BUFFERING MessageType = C.GST_MESSAGE_BUFFERING 19 | // MESSAGE_STATE_CHANGED MessageType = C.GST_MESSAGE_STATE_CHANGED 20 | // MESSAGE_ANY MessageType = C.GST_MESSAGE_ANY 21 | 22 | 23 | typedef struct BusMessageUserData { 24 | int pipelineId; 25 | } BusMessageUserData; 26 | 27 | 28 | static gboolean gstreamer_bus_call(GstBus *bus, GstMessage *msg, gpointer user_data) { 29 | 30 | BusMessageUserData *s = (BusMessageUserData *)user_data; 31 | int pipelineId = s->pipelineId; 32 | 33 | switch (GST_MESSAGE_TYPE(msg)) { 34 | case GST_MESSAGE_EOS: 35 | goHandleBusMessage(msg,pipelineId); 36 | break; 37 | case GST_MESSAGE_ERROR: { 38 | gchar *debug; 39 | GError *error; 40 | gst_message_parse_error(msg, &error, &debug); 41 | g_free(debug); 42 | g_error_free(error); 43 | goHandleBusMessage(msg,pipelineId); 44 | break; 45 | } 46 | case GST_MESSAGE_BUFFERING: { 47 | goHandleBusMessage(msg,pipelineId); 48 | break; 49 | } 50 | case GST_MESSAGE_STATE_CHANGED: { 51 | goHandleBusMessage(msg,pipelineId); 52 | break; 53 | } 54 | 55 | default: 56 | break; 57 | } 58 | 59 | return TRUE; 60 | } 61 | 62 | 63 | GstPipeline *gstreamer_create_pipeline(char *pipelinestr) { 64 | GError *error = NULL; 65 | GstPipeline *pipeline = (GstPipeline*)GST_BIN(gst_parse_launch(pipelinestr, &error)); 66 | return pipeline; 67 | } 68 | 69 | 70 | void gstreamer_pipeline_start(GstPipeline *pipeline, int pipelineId) { 71 | gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING); 72 | } 73 | 74 | 75 | void gstreamer_pipeline_but_watch(GstPipeline *pipeline, int pipelineId) { 76 | BusMessageUserData *s = calloc(1, sizeof(BusMessageUserData)); 77 | s->pipelineId = pipelineId; 78 | GstBus *bus = gst_pipeline_get_bus(pipeline); 79 | gst_bus_add_watch(bus, gstreamer_bus_call, s); 80 | gst_object_unref(bus); 81 | } 82 | 83 | void gstreamer_pipeline_pause(GstPipeline *pipeline) { 84 | gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PAUSED); 85 | } 86 | 87 | void gstreamer_pipeline_stop(GstPipeline *pipeline) { 88 | gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL); 89 | } 90 | 91 | void gstreamer_pipeline_sendeos(GstPipeline *pipeline) { 92 | gst_element_send_event(GST_ELEMENT(pipeline), gst_event_new_eos()); 93 | } 94 | 95 | GstElement *gstreamer_pipeline_findelement(GstPipeline *pipeline, char *element) { 96 | GstElement *e = gst_bin_get_by_name(GST_BIN(pipeline), element); 97 | if (e != NULL) { 98 | gst_object_unref(e); 99 | } 100 | return e; 101 | } 102 | 103 | void gstreamer_pipeline_set_auto_flush_bus(GstPipeline *pipeline, gboolean auto_flush) { 104 | gst_pipeline_set_auto_flush_bus(pipeline, auto_flush); 105 | } 106 | 107 | gboolean gstreamer_pipeline_get_auto_flush_bus(GstPipeline *pipeline) { 108 | return gst_pipeline_get_auto_flush_bus(pipeline); 109 | } 110 | 111 | void gstreamer_pipeline_set_delay(GstPipeline *pipeline, GstClockTime delay) { 112 | gst_pipeline_set_delay(pipeline, delay); 113 | } 114 | 115 | GstClockTime gstreamer_pipeline_get_delay(GstPipeline *pipeline) { 116 | return gst_pipeline_get_delay(pipeline); 117 | } 118 | 119 | void gstreamer_pipeline_set_latency(GstPipeline *pipeline, GstClockTime latency) { 120 | gst_pipeline_set_latency(pipeline, latency); 121 | } 122 | 123 | GstClockTime gstreamer_pipeline_get_latency(GstPipeline *pipeline) { 124 | return gst_pipeline_get_latency(pipeline); 125 | } 126 | 127 | 128 | void gstreamer_set_caps(GstElement *element, char *capstr) { 129 | 130 | GObject *obj = G_OBJECT(element); 131 | GstCaps* caps = gst_caps_from_string(capstr); 132 | 133 | if (GST_IS_APP_SRC(obj)) { 134 | gst_app_src_set_caps(GST_APP_SRC(obj), caps); 135 | } else if (GST_IS_APP_SINK(obj)) { 136 | gst_app_sink_set_caps(GST_APP_SINK(obj), caps); 137 | } else { 138 | // we should make soure this obj have caps 139 | GParamSpec *spec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), "caps"); 140 | if(spec) { 141 | g_object_set(obj, "caps", caps, NULL); 142 | } 143 | } 144 | gst_caps_unref(caps); 145 | } 146 | 147 | 148 | void gstreamer_element_push_buffer(GstElement *element, void *buffer,int len) { 149 | gpointer p = g_memdup(buffer, len); 150 | GstBuffer *data = gst_buffer_new_wrapped(p, len); 151 | gst_app_src_push_buffer(GST_APP_SRC(element), data); 152 | } 153 | 154 | 155 | void gstreamer_element_push_buffer_timestamp(GstElement *element, void *buffer,int len, guint64 pts) { 156 | gpointer p = g_memdup(buffer, len); 157 | GstBuffer *data = gst_buffer_new_wrapped(p, len); 158 | GST_BUFFER_PTS(data) = pts; 159 | GST_BUFFER_DTS(data) = pts; 160 | gst_app_src_push_buffer(GST_APP_SRC(element), data); 161 | } 162 | 163 | 164 | typedef struct SampleHandlerUserData { 165 | int elementId; 166 | GstElement *element; 167 | } SampleHandlerUserData; 168 | 169 | 170 | GstFlowReturn gstreamer_new_sample_handler(GstElement *object, gpointer user_data) { 171 | GstSample *sample = NULL; 172 | GstBuffer *buffer = NULL; 173 | gpointer copy = NULL; 174 | gsize copy_size = 0; 175 | SampleHandlerUserData *s = (SampleHandlerUserData *)user_data; 176 | 177 | g_signal_emit_by_name (object, "pull-sample", &sample); 178 | if (sample) { 179 | buffer = gst_sample_get_buffer(sample); 180 | if (buffer) { 181 | gst_buffer_extract_dup(buffer, 0, gst_buffer_get_size(buffer), ©, ©_size); 182 | goHandleSinkBuffer(copy, copy_size, s->elementId); 183 | } 184 | gst_sample_unref (sample); 185 | } 186 | 187 | return GST_FLOW_OK; 188 | } 189 | 190 | 191 | GstFlowReturn gstreamer_sink_eos_handler(GstElement *object, gpointer user_data) { 192 | 193 | SampleHandlerUserData *s = (SampleHandlerUserData *)user_data; 194 | goHandleSinkEOS(s->elementId); 195 | return GST_FLOW_OK; 196 | } 197 | 198 | 199 | void gstreamer_element_pull_buffer(GstElement *element, int elementId) { 200 | 201 | SampleHandlerUserData *s = calloc(1, sizeof(SampleHandlerUserData)); 202 | s->element = element; 203 | s->elementId = elementId; 204 | 205 | g_object_set(element, "emit-signals", TRUE, NULL); 206 | g_signal_connect(element, "new-sample", G_CALLBACK(gstreamer_new_sample_handler), s); 207 | g_signal_connect(element, "eos", G_CALLBACK(gstreamer_sink_eos_handler), s); 208 | } 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /gstreamer.go: -------------------------------------------------------------------------------- 1 | package gstreamer 2 | 3 | /* 4 | #cgo pkg-config: gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-plugins-base-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-plugins-bad-1.0 5 | #include "gstreamer.h" 6 | */ 7 | import "C" 8 | import ( 9 | "errors" 10 | "fmt" 11 | "sync" 12 | "unsafe" 13 | ) 14 | 15 | func init() { 16 | C.gstreamer_init() 17 | } 18 | 19 | type MessageType int 20 | 21 | const ( 22 | MESSAGE_UNKNOWN MessageType = C.GST_MESSAGE_UNKNOWN 23 | MESSAGE_EOS MessageType = C.GST_MESSAGE_EOS 24 | MESSAGE_ERROR MessageType = C.GST_MESSAGE_ERROR 25 | MESSAGE_WARNING MessageType = C.GST_MESSAGE_WARNING 26 | MESSAGE_INFO MessageType = C.GST_MESSAGE_INFO 27 | MESSAGE_TAG MessageType = C.GST_MESSAGE_TAG 28 | MESSAGE_BUFFERING MessageType = C.GST_MESSAGE_BUFFERING 29 | MESSAGE_STATE_CHANGED MessageType = C.GST_MESSAGE_STATE_CHANGED 30 | MESSAGE_ANY MessageType = C.GST_MESSAGE_ANY 31 | ) 32 | 33 | type Message struct { 34 | GstMessage *C.GstMessage 35 | } 36 | 37 | func (v *Message) GetType() MessageType { 38 | c := C.toGstMessageType(unsafe.Pointer(v.native())) 39 | return MessageType(c) 40 | } 41 | 42 | func (v *Message) native() *C.GstMessage { 43 | if v == nil { 44 | return nil 45 | } 46 | return v.GstMessage 47 | } 48 | 49 | func (v *Message) GetTimestamp() uint64 { 50 | c := C.messageTimestamp(unsafe.Pointer(v.native())) 51 | return uint64(c) 52 | } 53 | 54 | func (v *Message) GetTypeName() string { 55 | c := C.messageTypeName(unsafe.Pointer(v.native())) 56 | return C.GoString(c) 57 | } 58 | 59 | func gbool(b bool) C.gboolean { 60 | if b { 61 | return C.gboolean(1) 62 | } 63 | return C.gboolean(0) 64 | } 65 | func gobool(b C.gboolean) bool { 66 | if b != 0 { 67 | return true 68 | } 69 | return false 70 | } 71 | 72 | type Element struct { 73 | element *C.GstElement 74 | out chan []byte 75 | stop bool 76 | id int 77 | } 78 | 79 | type Pipeline struct { 80 | pipeline *C.GstPipeline 81 | messages chan *Message 82 | id int 83 | } 84 | 85 | var pipelines = make(map[int]*Pipeline) 86 | var elements = make(map[int]*Element) 87 | var gstreamerLock sync.Mutex 88 | var gstreamerIdGenerate = 10000 89 | 90 | func New(pipelineStr string) (*Pipeline, error) { 91 | pipelineStrUnsafe := C.CString(pipelineStr) 92 | defer C.free(unsafe.Pointer(pipelineStrUnsafe)) 93 | cpipeline := C.gstreamer_create_pipeline(pipelineStrUnsafe) 94 | if cpipeline == nil { 95 | return nil, errors.New("create pipeline error") 96 | } 97 | 98 | pipeline := &Pipeline{ 99 | pipeline: cpipeline, 100 | } 101 | 102 | gstreamerLock.Lock() 103 | defer gstreamerLock.Unlock() 104 | gstreamerIdGenerate += 1 105 | pipeline.id = gstreamerIdGenerate 106 | pipelines[pipeline.id] = pipeline 107 | return pipeline, nil 108 | } 109 | 110 | func (p *Pipeline) PullMessage() <-chan *Message { 111 | p.messages = make(chan *Message, 5) 112 | C.gstreamer_pipeline_but_watch(p.pipeline, C.int(p.id)) 113 | return p.messages 114 | } 115 | 116 | func (p *Pipeline) Start() { 117 | C.gstreamer_pipeline_start(p.pipeline, C.int(p.id)) 118 | } 119 | 120 | func (p *Pipeline) Pause() { 121 | C.gstreamer_pipeline_pause(p.pipeline) 122 | } 123 | 124 | func (p *Pipeline) Stop() { 125 | gstreamerLock.Lock() 126 | delete(pipelines, p.id) 127 | gstreamerLock.Unlock() 128 | if p.messages != nil { 129 | close(p.messages) 130 | } 131 | C.gstreamer_pipeline_stop(p.pipeline) 132 | } 133 | 134 | func (p *Pipeline) SendEOS() { 135 | C.gstreamer_pipeline_sendeos(p.pipeline) 136 | } 137 | 138 | func (p *Pipeline) SetAutoFlushBus(flush bool) { 139 | gflush := gbool(flush) 140 | C.gstreamer_pipeline_set_auto_flush_bus(p.pipeline, gflush) 141 | } 142 | 143 | func (p *Pipeline) GetAutoFlushBus() bool { 144 | gflush := C.gstreamer_pipeline_get_auto_flush_bus(p.pipeline) 145 | return gobool(gflush) 146 | } 147 | 148 | func (p *Pipeline) GetDelay() uint64 { 149 | 150 | delay := C.gstreamer_pipeline_get_delay(p.pipeline) 151 | return uint64(delay) 152 | } 153 | 154 | func (p *Pipeline) SetDelay(delay uint64) { 155 | C.gstreamer_pipeline_set_delay(p.pipeline, C.guint64(delay)) 156 | } 157 | 158 | func (p *Pipeline) GetLatency() uint64 { 159 | 160 | latency := C.gstreamer_pipeline_get_latency(p.pipeline) 161 | return uint64(latency) 162 | } 163 | 164 | func (p *Pipeline) SetLatency(latency uint64) { 165 | C.gstreamer_pipeline_set_latency(p.pipeline, C.guint64(latency)) 166 | } 167 | 168 | func (p *Pipeline) FindElement(name string) *Element { 169 | elementName := C.CString(name) 170 | defer C.free(unsafe.Pointer(elementName)) 171 | gelement := C.gstreamer_pipeline_findelement(p.pipeline, elementName) 172 | if gelement == nil { 173 | return nil 174 | } 175 | element := &Element{ 176 | element: gelement, 177 | } 178 | 179 | gstreamerLock.Lock() 180 | defer gstreamerLock.Unlock() 181 | gstreamerIdGenerate += 1 182 | element.id = gstreamerIdGenerate 183 | elements[element.id] = element 184 | 185 | return element 186 | } 187 | 188 | func (e *Element) SetCap(cap string) { 189 | capStr := C.CString(cap) 190 | defer C.free(unsafe.Pointer(capStr)) 191 | C.gstreamer_set_caps(e.element, capStr) 192 | } 193 | 194 | func (e *Element) Push(buffer []byte) { 195 | 196 | b := C.CBytes(buffer) 197 | defer C.free(unsafe.Pointer(b)) 198 | C.gstreamer_element_push_buffer(e.element, b, C.int(len(buffer))) 199 | } 200 | 201 | func (e *Element) Poll() <-chan []byte { 202 | if e.out == nil { 203 | e.out = make(chan []byte, 10) 204 | C.gstreamer_element_pull_buffer(e.element, C.int(e.id)) 205 | } 206 | return e.out 207 | } 208 | 209 | func (e *Element) Stop() { 210 | gstreamerLock.Lock() 211 | delete(elements, e.id) 212 | gstreamerLock.Unlock() 213 | if e.stop { 214 | return 215 | } 216 | if e.out != nil { 217 | e.stop = true 218 | close(e.out) 219 | } 220 | 221 | } 222 | 223 | //export goHandleSinkBuffer 224 | func goHandleSinkBuffer(buffer unsafe.Pointer, bufferLen C.int, elementID C.int) { 225 | gstreamerLock.Lock() 226 | defer gstreamerLock.Unlock() 227 | if element, ok := elements[int(elementID)]; ok { 228 | if element.out != nil && !element.stop { 229 | element.out <- C.GoBytes(buffer, bufferLen) 230 | } 231 | } else { 232 | fmt.Printf("discarding buffer, no element with id %d", int(elementID)) 233 | } 234 | C.free(buffer) 235 | } 236 | 237 | //export goHandleSinkEOS 238 | func goHandleSinkEOS(elementID C.int) { 239 | gstreamerLock.Lock() 240 | defer gstreamerLock.Unlock() 241 | if element, ok := elements[int(elementID)]; ok { 242 | if element.out != nil && !element.stop { 243 | element.stop = true 244 | close(element.out) 245 | } 246 | } 247 | } 248 | 249 | //export goHandleBusMessage 250 | func goHandleBusMessage(message *C.GstMessage, pipelineId C.int) { 251 | gstreamerLock.Lock() 252 | defer gstreamerLock.Unlock() 253 | msg := &Message{GstMessage: message} 254 | if pipeline, ok := pipelines[int(pipelineId)]; ok { 255 | if pipeline.messages != nil { 256 | pipeline.messages <- msg 257 | } 258 | } else { 259 | fmt.Printf("discarding message, no pipelie with id %d", int(pipelineId)) 260 | } 261 | 262 | } 263 | 264 | // ScanPathForPlugins : Scans a given path for any gstreamer plugins and adds them to 265 | // the gst_registry 266 | func ScanPathForPlugins(directory string) { 267 | C.gst_registry_scan_path(C.gst_registry_get(), C.CString(directory)) 268 | } 269 | 270 | func CheckPlugins(plugins []string) error { 271 | 272 | var plugin *C.GstPlugin 273 | var registry *C.GstRegistry 274 | 275 | registry = C.gst_registry_get() 276 | 277 | for _, pluginstr := range plugins { 278 | plugincstr := C.CString(pluginstr) 279 | plugin = C.gst_registry_find_plugin(registry, plugincstr) 280 | C.free(unsafe.Pointer(plugincstr)) 281 | if plugin == nil { 282 | return fmt.Errorf("Required gstreamer plugin %s not found", pluginstr) 283 | } 284 | } 285 | 286 | return nil 287 | } 288 | -------------------------------------------------------------------------------- /gstreamer.h: -------------------------------------------------------------------------------- 1 | #ifndef GST_H 2 | #define GST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | extern void goHandleSinkBuffer(void *buffer, int bufferLen, int elementId); 13 | extern void goHandleBusMessage(GstMessage* message, int pipelineId); 14 | extern void goHandleSinkEOS(int elementId); 15 | 16 | 17 | static gint 18 | toGstMessageType(void *p) { 19 | return (GST_MESSAGE_TYPE(p)); 20 | } 21 | 22 | static const char* 23 | messageTypeName(void *p) 24 | { 25 | return (GST_MESSAGE_TYPE_NAME(p)); 26 | } 27 | 28 | static guint64 29 | messageTimestamp(void *p) 30 | { 31 | return (GST_MESSAGE_TIMESTAMP(p)); 32 | } 33 | 34 | void gstreamer_init(); 35 | 36 | GstPipeline *gstreamer_create_pipeline(char *pipeline); 37 | 38 | void gstreamer_pipeline_start(GstPipeline *pipeline, int pipelineId); 39 | 40 | void gstreamer_pipeline_but_watch(GstPipeline *pipeline, int pipelineId); 41 | 42 | void gstreamer_pipeline_pause(GstPipeline *pipeline); 43 | 44 | void gstreamer_pipeline_stop(GstPipeline *pipeline); 45 | 46 | void gstreamer_pipeline_sendeos(GstPipeline *pipeline); 47 | 48 | void gstreamer_pipeline_set_auto_flush_bus(GstPipeline *pipeline, gboolean auto_flush); 49 | 50 | gboolean gstreamer_pipeline_get_auto_flush_bus (GstPipeline *pipeline); 51 | 52 | GstElement *gstreamer_pipeline_findelement(GstPipeline *pipeline, char *element); 53 | 54 | void gstreamer_pipeline_set_delay(GstPipeline *pipeline, GstClockTime delay); 55 | 56 | GstClockTime gstreamer_pipeline_get_delay(GstPipeline *pipeline); 57 | 58 | void gstreamer_pipeline_set_latency(GstPipeline *pipeline, GstClockTime latency); 59 | 60 | GstClockTime gstreamer_pipeline_get_latency(GstPipeline *pipeline); 61 | 62 | void gstreamer_set_caps(GstElement *element, char *caps); 63 | 64 | void gstreamer_element_push_buffer(GstElement *element, void *buffer,int len); 65 | 66 | void gstreamer_element_push_buffer_timestamp(GstElement *element, void *buffer,int len, guint64 pts); 67 | 68 | void gstreamer_element_pull_buffer(GstElement *element, int elementId); 69 | 70 | #endif -------------------------------------------------------------------------------- /gstreamer_test.go: -------------------------------------------------------------------------------- 1 | package gstreamer 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestPipeline(t *testing.T) { 10 | 11 | pipeline, err := New("videotestsrc ! capsfilter name=filter ! autovideosink") 12 | if err != nil { 13 | t.Error("pipeline create error", err) 14 | t.FailNow() 15 | } 16 | 17 | filter := pipeline.FindElement("filter") 18 | 19 | if filter == nil { 20 | t.Error("pipeline find element error ") 21 | } 22 | 23 | filter.SetCap("video/x-raw,width=1280,height=720") 24 | 25 | pipeline.Start() 26 | 27 | select {} 28 | } 29 | 30 | func TestAppsrc(t *testing.T) { 31 | 32 | pipeline, err := New("appsrc name=mysource format=time is-live=true do-timestamp=true ! videoconvert ! autovideosink") 33 | 34 | if err != nil { 35 | t.Error("pipeline create error", err) 36 | t.FailNow() 37 | } 38 | 39 | appsrc := pipeline.FindElement("mysource") 40 | 41 | appsrc.SetCap("video/x-raw,format=RGB,width=320,height=240,bpp=24,depth=24") 42 | 43 | pipeline.Start() 44 | 45 | for { 46 | time.Sleep(1 * time.Second) 47 | appsrc.Push(make([]byte, 320*240*3)) 48 | } 49 | } 50 | 51 | func TestAppsink(t *testing.T) { 52 | 53 | pipeline, err := New("videotestsrc num-buffers=15 ! appsink name=sink") 54 | 55 | if err != nil { 56 | t.Error("pipeline create error", err) 57 | t.FailNow() 58 | } 59 | 60 | appsink := pipeline.FindElement("sink") 61 | 62 | pipeline.Start() 63 | 64 | out := appsink.Poll() 65 | 66 | for { 67 | buffer := <-out 68 | fmt.Println(len(buffer)) 69 | } 70 | } 71 | 72 | func TestAppsink2(t *testing.T) { 73 | 74 | pipeline, err := New("videotestsrc ! video/x-raw,format=I420,framerate=15/1 ! x264enc bframes=0 speed-preset=veryfast key-int-max=60 ! video/x-h264,stream-format=byte-stream ! appsink name=sink") 75 | 76 | if err != nil { 77 | t.Error("pipeline create error", err) 78 | t.FailNow() 79 | } 80 | 81 | appsink := pipeline.FindElement("sink") 82 | 83 | pipeline.Start() 84 | 85 | out := appsink.Poll() 86 | 87 | for { 88 | buffer := <-out 89 | fmt.Println("push ", len(buffer)) 90 | } 91 | } 92 | 93 | func TestCheckPlugins(t *testing.T) { 94 | 95 | plugins := []string{"videotestsrc", "audiotestsrc", "rtp", "curl","x264", "rtmp"} 96 | 97 | err := CheckPlugins(plugins) 98 | 99 | if err != nil { 100 | t.Error("pipeline create error", err) 101 | t.FailNow() 102 | } 103 | } 104 | --------------------------------------------------------------------------------