mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-05 16:06:55 +08:00
playbin example
This commit is contained in:
92
examples/playbin/main.go
Normal file
92
examples/playbin/main.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// This example demonstrates GStreamer's playbin element.
|
||||||
|
//
|
||||||
|
// This element takes an arbitrary URI as parameter, and if there is a source
|
||||||
|
// element within gstreamer, that supports this uri, the playbin will try
|
||||||
|
// to automatically create a pipeline that properly plays this media source.
|
||||||
|
// For this, the playbin internally relies on more bin elements, like the
|
||||||
|
// autovideosink and the decodebin.
|
||||||
|
// Essentially, this element is a single-element pipeline able to play
|
||||||
|
// any format from any uri-addressable source that gstreamer supports.
|
||||||
|
// Much of the playbin's behavior can be controlled by so-called flags, as well
|
||||||
|
// as the playbin's properties and signals.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/tinyzimmer/go-gst/examples"
|
||||||
|
"github.com/tinyzimmer/go-gst/gst"
|
||||||
|
)
|
||||||
|
|
||||||
|
var srcURI string
|
||||||
|
|
||||||
|
func playbin(mainLoop *gst.MainLoop) error {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
return errors.New("Usage: playbin <uri>")
|
||||||
|
}
|
||||||
|
|
||||||
|
gst.Init(nil)
|
||||||
|
|
||||||
|
// Create a new playbin and set the URI on it
|
||||||
|
playbin, err := gst.NewElement("playbin")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
playbin.Set("uri", os.Args[1])
|
||||||
|
|
||||||
|
// The playbin element itself is a pipeline, so it can be used as one, despite being
|
||||||
|
// created from an element factory.
|
||||||
|
bus := playbin.GetBus()
|
||||||
|
|
||||||
|
playbin.SetState(gst.StatePlaying)
|
||||||
|
|
||||||
|
bus.AddWatch(func(msg *gst.Message) bool {
|
||||||
|
switch msg.Type() {
|
||||||
|
case gst.MessageEOS:
|
||||||
|
mainLoop.Quit()
|
||||||
|
return false
|
||||||
|
case gst.MessageError:
|
||||||
|
err := msg.ParseError()
|
||||||
|
fmt.Println("ERROR:", err.Error())
|
||||||
|
if debug := err.DebugString(); debug != "" {
|
||||||
|
fmt.Println("DEBUG")
|
||||||
|
fmt.Println(debug)
|
||||||
|
}
|
||||||
|
mainLoop.Quit()
|
||||||
|
return false
|
||||||
|
// Watch state change events
|
||||||
|
case gst.MessageStateChanged:
|
||||||
|
if _, newState := msg.ParseStateChanged(); newState == gst.StatePlaying {
|
||||||
|
bin := gst.BinFromElement(playbin)
|
||||||
|
// Generate a dot graph of the pipeline to GST_DEBUG_DUMP_DOT_DIR if defined
|
||||||
|
bin.DebugBinToDotFile(gst.DebugGraphShowAll, "PLAYING")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag messages contain changes to tags on the stream. This can include metadata about
|
||||||
|
// the stream such as codecs, artists, albums, etc.
|
||||||
|
case gst.MessageTag:
|
||||||
|
tags := msg.ParseTags()
|
||||||
|
fmt.Println("Tags:")
|
||||||
|
if artist, ok := tags.GetString(gst.TagArtist); ok {
|
||||||
|
fmt.Println(" Artist:", artist)
|
||||||
|
}
|
||||||
|
if album, ok := tags.GetString(gst.TagAlbum); ok {
|
||||||
|
fmt.Println(" Album:", album)
|
||||||
|
}
|
||||||
|
if title, ok := tags.GetString(gst.TagTitle); ok {
|
||||||
|
fmt.Println(" Title:", title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
mainLoop.Run()
|
||||||
|
|
||||||
|
return playbin.SetState(gst.StateNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
examples.RunLoop(playbin)
|
||||||
|
}
|
@@ -196,6 +196,9 @@ const (
|
|||||||
EventTypeCustomBothOOB EventType = C.GST_EVENT_CUSTOM_BOTH_OOB // (81923) – Custom upstream or downstream out-of-band event.
|
EventTypeCustomBothOOB EventType = C.GST_EVENT_CUSTOM_BOTH_OOB // (81923) – Custom upstream or downstream out-of-band event.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// String implements a stringer on event types
|
||||||
|
func (e EventType) String() string { return C.GoString(C.gst_event_type_get_name(C.GstEventType(e))) }
|
||||||
|
|
||||||
// EventTypeFlags casts GstEventTypeFlags
|
// EventTypeFlags casts GstEventTypeFlags
|
||||||
type EventTypeFlags int
|
type EventTypeFlags int
|
||||||
|
|
||||||
|
@@ -22,6 +22,16 @@ func NewBin(name string) *Bin {
|
|||||||
return wrapBin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(bin))})
|
return wrapBin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(bin))})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BinFromElement wraps the given Element in a Bin reference. This only works for elements
|
||||||
|
// that implement their own Bin, such as playbin. If the provided element does not implement
|
||||||
|
// a Bin then nil is returned.
|
||||||
|
func BinFromElement(elem *Element) *Bin {
|
||||||
|
if C.toGstBin(elem.Unsafe()) == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Bin{elem}
|
||||||
|
}
|
||||||
|
|
||||||
// Instance returns the underlying GstBin instance.
|
// Instance returns the underlying GstBin instance.
|
||||||
func (b *Bin) Instance() *C.GstBin { return C.toGstBin(b.Unsafe()) }
|
func (b *Bin) Instance() *C.GstBin { return C.toGstBin(b.Unsafe()) }
|
||||||
|
|
||||||
@@ -81,6 +91,15 @@ func (b *Bin) GetElementsSorted() ([]*Element, error) {
|
|||||||
return iteratorToElementSlice(iterator)
|
return iteratorToElementSlice(iterator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetElementsByFactoryName returns a list of the elements in this bin created from the given factory
|
||||||
|
// name.
|
||||||
|
func (b *Bin) GetElementsByFactoryName(name string) ([]*Element, error) {
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
iterator := C.gst_bin_iterate_all_by_element_factory_name(b.Instance(), (*C.gchar)(unsafe.Pointer(cname)))
|
||||||
|
return iteratorToElementSlice(iterator)
|
||||||
|
}
|
||||||
|
|
||||||
// Add adds an element to the bin.
|
// Add adds an element to the bin.
|
||||||
func (b *Bin) Add(elem *Element) error {
|
func (b *Bin) Add(elem *Element) error {
|
||||||
if ok := C.gst_bin_add((*C.GstBin)(b.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
|
if ok := C.gst_bin_add((*C.GstBin)(b.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
|
||||||
@@ -157,6 +176,46 @@ func (b *Bin) SyncChildrenStates() bool {
|
|||||||
return gobool(C.gst_bin_sync_children_states(b.Instance()))
|
return gobool(C.gst_bin_sync_children_states(b.Instance()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG OPERATIONS //
|
||||||
|
|
||||||
|
// DebugGraphDetails casts GstDebugGraphDetails
|
||||||
|
type DebugGraphDetails int
|
||||||
|
|
||||||
|
// Type castings
|
||||||
|
const (
|
||||||
|
DebugGraphShowMediaType DebugGraphDetails = C.GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE // (1) – show caps-name on edges
|
||||||
|
DebugGraphShowCapsDetails DebugGraphDetails = C.GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS // (2) – show caps-details on edges
|
||||||
|
DebugGraphShowNonDefaultParams DebugGraphDetails = C.GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS // (4) – show modified parameters on elements
|
||||||
|
DebugGraphShowStates DebugGraphDetails = C.GST_DEBUG_GRAPH_SHOW_STATES // (8) – show element states
|
||||||
|
DebugGraphShowPullParams DebugGraphDetails = C.GST_DEBUG_GRAPH_SHOW_FULL_PARAMS // (16) – show full element parameter values even if they are very long
|
||||||
|
DebugGraphShowAll DebugGraphDetails = C.GST_DEBUG_GRAPH_SHOW_ALL // (15) – show all the typical details that one might want
|
||||||
|
DebugGraphShowVerbose DebugGraphDetails = C.GST_DEBUG_GRAPH_SHOW_VERBOSE // (4294967295) – show all details regardless of how large or verbose they make the resulting output
|
||||||
|
)
|
||||||
|
|
||||||
|
// DebugBinToDotData will obtain the whole network of gstreamer elements that form the pipeline into a dot file.
|
||||||
|
// This data can be processed with graphviz to get an image.
|
||||||
|
func (b *Bin) DebugBinToDotData(details DebugGraphDetails) string {
|
||||||
|
ret := C.gst_debug_bin_to_dot_data(b.Instance(), C.GstDebugGraphDetails(details))
|
||||||
|
defer C.g_free((C.gpointer)(unsafe.Pointer(ret)))
|
||||||
|
return C.GoString(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebugBinToDotFile is like DebugBinToDotData except it will write the dot data to the filename
|
||||||
|
// specified.
|
||||||
|
func (b *Bin) DebugBinToDotFile(details DebugGraphDetails, filename string) {
|
||||||
|
cname := C.CString(filename)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
C.gst_debug_bin_to_dot_file(b.Instance(), C.GstDebugGraphDetails(details), (*C.gchar)(unsafe.Pointer(cname)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebugBinToDotFileWithTs is like DebugBinToDotFile except it will write the dot data to the filename
|
||||||
|
// specified, except it will append the current timestamp to the filename.
|
||||||
|
func (b *Bin) DebugBinToDotFileWithTs(details DebugGraphDetails, filename string) {
|
||||||
|
cname := C.CString(filename)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
C.gst_debug_bin_to_dot_file_with_ts(b.Instance(), C.GstDebugGraphDetails(details), (*C.gchar)(unsafe.Pointer(cname)))
|
||||||
|
}
|
||||||
|
|
||||||
func iteratorToElementSlice(iterator *C.GstIterator) ([]*Element, error) {
|
func iteratorToElementSlice(iterator *C.GstIterator) ([]*Element, error) {
|
||||||
elems := make([]*Element, 0)
|
elems := make([]*Element, 0)
|
||||||
gval := new(C.GValue)
|
gval := new(C.GValue)
|
||||||
|
@@ -255,13 +255,31 @@ func (e *Element) SendEvent(ev *Event) bool {
|
|||||||
// Connect connects to the given signal on this element, and applies f as the callback. The callback must
|
// Connect connects to the given signal on this element, and applies f as the callback. The callback must
|
||||||
// match the signature of the expected callback from the documentation. However, instead of specifying C types
|
// match the signature of the expected callback from the documentation. However, instead of specifying C types
|
||||||
// for arguments specify the go-gst equivalent (e.g. *gst.Element for almost all GstElement derivitives).
|
// for arguments specify the go-gst equivalent (e.g. *gst.Element for almost all GstElement derivitives).
|
||||||
|
//
|
||||||
|
// This and the Emit() method may get moved down the hierarchy to the Object level at some point, since
|
||||||
func (e *Element) Connect(signal string, f interface{}) (glib.SignalHandle, error) {
|
func (e *Element) Connect(signal string, f interface{}) (glib.SignalHandle, error) {
|
||||||
// Elements are sometimes their own type unique from TYPE_ELEMENT. So make sure a type marshaler
|
// Elements are sometimes their own type unique from TYPE_ELEMENT. So make sure a type marshaler
|
||||||
// is registered for whatever this type is. Use the built-in element marshaler.
|
// is registered for whatever this type is. Use the built-in element marshaler.
|
||||||
glib.RegisterGValueMarshalers([]glib.TypeMarshaler{{T: e.TypeFromInstance(), F: marshalElement}})
|
if e.TypeFromInstance() != glib.Type(C.GST_TYPE_ELEMENT) {
|
||||||
|
glib.RegisterGValueMarshalers([]glib.TypeMarshaler{{T: e.TypeFromInstance(), F: marshalElement}})
|
||||||
|
}
|
||||||
return e.Object.Connect(signal, f, nil)
|
return e.Object.Connect(signal, f, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit is a wrapper around g_signal_emitv() and emits the signal specified by the string s to an Object. Arguments to
|
||||||
|
// callback functions connected to this signal must be specified in args. Emit() returns an interface{} which must be
|
||||||
|
// type asserted as the Go equivalent type to the return value for native C callback.
|
||||||
|
//
|
||||||
|
// Note that this code is unsafe in that the types of values in args are not checked against whether they are suitable
|
||||||
|
// for the callback.
|
||||||
|
func (e *Element) Emit(signal string, args ...interface{}) (interface{}, error) {
|
||||||
|
// We are wrapping this for the same reason as Connect.
|
||||||
|
if e.TypeFromInstance() != glib.Type(C.GST_TYPE_ELEMENT) {
|
||||||
|
glib.RegisterGValueMarshalers([]glib.TypeMarshaler{{T: e.TypeFromInstance(), F: marshalElement}})
|
||||||
|
}
|
||||||
|
return e.Object.Emit(signal, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// SyncStateWithParent tries to change the state of the element to the same as its parent. If this function returns
|
// SyncStateWithParent tries to change the state of the element to the same as its parent. If this function returns
|
||||||
// FALSE, the state of element is undefined.
|
// FALSE, the state of element is undefined.
|
||||||
func (e *Element) SyncStateWithParent() bool {
|
func (e *Element) SyncStateWithParent() bool {
|
||||||
|
@@ -47,7 +47,11 @@ func (s *Stream) StreamType() StreamType {
|
|||||||
|
|
||||||
// Tags returns the tag list for this stream.
|
// Tags returns the tag list for this stream.
|
||||||
func (s *Stream) Tags() *TagList {
|
func (s *Stream) Tags() *TagList {
|
||||||
return wrapTagList(C.gst_stream_get_tags(s.Instance()))
|
tags := C.gst_stream_get_tags(s.Instance())
|
||||||
|
if tags == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapTagList(tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCaps sets the caps for this stream.
|
// SetCaps sets the caps for this stream.
|
||||||
|
Reference in New Issue
Block a user