package gst /* #cgo pkg-config: gstreamer-1.0 #cgo CFLAGS: -Wno-deprecated-declarations -Wno-incompatible-pointer-types -g #include #include "gst.go.h" */ import "C" import ( "errors" "fmt" "strings" "unsafe" "github.com/gotk3/gotk3/glib" ) // Pipeline is a go implementation of a GstPipeline. Helper methods are provided for constructing // pipelines either using file descriptors or the Appsrc/Appsink APIs. The struct itself implements // a ReadWriteCloser. type Pipeline struct { *Bin // a local reference to the bus so duplicates aren't created // when retrieved by the user bus *Bus } // NewPipeline allocates and returns a new empty pipeline. If name is empty, one // is generated by gstreamer. func NewPipeline(name string) (*Pipeline, error) { var cChar *C.char if name != "" { cChar = C.CString(name) defer C.free(unsafe.Pointer(cChar)) } pipeline := C.gst_pipeline_new((*C.gchar)(cChar)) if pipeline == nil { return nil, errors.New("Could not create new pipeline") } return wrapPipeline(glib.Take(unsafe.Pointer(pipeline))), nil } // NewPipelineFromString creates a new gstreamer pipeline from the given launch string. func NewPipelineFromString(launchv string) (*Pipeline, error) { if len(strings.Split(launchv, "!")) < 2 { return nil, fmt.Errorf("Given string is too short for a pipeline: %s", launchv) } cLaunchv := C.CString(launchv) defer C.free(unsafe.Pointer(cLaunchv)) var gerr *C.GError pipeline := C.gst_parse_launch((*C.gchar)(cLaunchv), (**C.GError)(&gerr)) if gerr != nil { defer C.g_error_free((*C.GError)(gerr)) errMsg := C.GoString(gerr.message) return nil, errors.New(errMsg) } return wrapPipeline(glib.Take(unsafe.Pointer(pipeline))), nil } // Instance returns the native GstPipeline instance. func (p *Pipeline) Instance() *C.GstPipeline { return C.toGstPipeline(p.unsafe()) } // GetBus returns the message bus for this pipeline. func (p *Pipeline) GetBus() *Bus { if p.bus == nil { cBus := C.gst_pipeline_get_bus((*C.GstPipeline)(p.Instance())) p.bus = wrapBus(glib.Take(unsafe.Pointer(cBus))) } return p.bus } // Start will start the GstPipeline. It is asynchronous so it does not need to be // called within a goroutine, however, it is still safe to do so. func (p *Pipeline) Start() error { return p.SetState(StatePlaying) } // Destroy will attempt to stop the pipeline and then unref once the stream has // fully completed. func (p *Pipeline) Destroy() error { if err := p.BlockSetState(StateNull); err != nil { return err } p.Unref() return nil } // Wait waits for the given pipeline to reach end of stream or be stopped. func Wait(p *Pipeline) { if p.Instance() == nil { return } msgCh := p.GetBus().MessageChan() for { select { default: if p.Instance() == nil || p.GetState() == StateNull { return } case msg := <-msgCh: defer msg.Unref() switch msg.Type() { case MessageEOS: return } } } }