mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-04 23:52: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.
|
||||
)
|
||||
|
||||
// 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
|
||||
type EventTypeFlags int
|
||||
|
||||
|
@@ -22,6 +22,16 @@ func NewBin(name string) *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.
|
||||
func (b *Bin) Instance() *C.GstBin { return C.toGstBin(b.Unsafe()) }
|
||||
|
||||
@@ -81,6 +91,15 @@ func (b *Bin) GetElementsSorted() ([]*Element, error) {
|
||||
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.
|
||||
func (b *Bin) Add(elem *Element) error {
|
||||
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()))
|
||||
}
|
||||
|
||||
// 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) {
|
||||
elems := make([]*Element, 0)
|
||||
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
|
||||
// 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).
|
||||
//
|
||||
// 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) {
|
||||
// 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.
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
// FALSE, the state of element is undefined.
|
||||
func (e *Element) SyncStateWithParent() bool {
|
||||
|
@@ -47,7 +47,11 @@ func (s *Stream) StreamType() StreamType {
|
||||
|
||||
// Tags returns the tag list for this stream.
|
||||
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.
|
||||
|
Reference in New Issue
Block a user