mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-28 10:11:54 +08:00
148 lines
3.9 KiB
Go
148 lines
3.9 KiB
Go
// This example demonstrates the use of custom events in a pipeline.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/diamondburned/gotk4/pkg/glib/v2"
|
|
"github.com/go-gst/go-gst/pkg/gst"
|
|
)
|
|
|
|
// ExampleCustomEvent demonstrates a custom event structue. Currerntly nested structs
|
|
// are not supported.
|
|
type ExampleCustomEvent struct {
|
|
Count int
|
|
SendEOS bool
|
|
}
|
|
|
|
func createPipeline() (*gst.Pipeline, error) {
|
|
gst.Init()
|
|
|
|
// Create a new pipeline from a launch string
|
|
ret, err := gst.ParseLaunch(
|
|
"audiotestsrc name=src ! queue max-size-time=2000000000 ! fakesink name=sink sync=true",
|
|
)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pipeline := ret.(*gst.Pipeline)
|
|
|
|
var sink *gst.Element
|
|
var sinkpad *gst.Pad
|
|
|
|
// Retrieve the sink pad
|
|
for v := range pipeline.IterateSinks().Values() {
|
|
sink = v.(*gst.Element)
|
|
sinkpad = sink.StaticPad("sink")
|
|
break
|
|
}
|
|
|
|
if sink == nil || sinkpad == nil {
|
|
return nil, fmt.Errorf("could not find sink")
|
|
}
|
|
|
|
// Add a probe for out custom event
|
|
sinkpad.AddProbe(gst.PadProbeTypeEventDownstream, func(self *gst.Pad, info *gst.PadProbeInfo) gst.PadProbeReturn {
|
|
// Retrieve the event from the probe
|
|
ev := info.Event()
|
|
|
|
// Extra check to make sure it is the right type.
|
|
if ev.Type() != gst.EventCustomDownstream {
|
|
return gst.PadProbeHandled
|
|
}
|
|
|
|
// Unmarshal the event into our custom one
|
|
var customEvent ExampleCustomEvent
|
|
if err := ev.Structure().UnmarshalInto(&customEvent); err != nil {
|
|
fmt.Println("Could not parse the custom event!")
|
|
return gst.PadProbeHandled
|
|
}
|
|
|
|
// Log and act accordingly
|
|
fmt.Printf("Received custom event with count=%d send_eos=%v\n", customEvent.Count, customEvent.SendEOS)
|
|
if customEvent.SendEOS {
|
|
// We need to use the CallAsync method to send the signal.
|
|
// This is becaues the SendEvent method blocks and this could cause a dead lock sending the
|
|
// event directly from the probe. This is the near equivalent of using go func() { ... }(),
|
|
// however displayed this way for demonstration purposes.
|
|
sink.CallAsync(func(el gst.Elementer) {
|
|
fmt.Println("Send EOS is true, sending eos")
|
|
if !pipeline.SendEvent(gst.NewEventEos()) {
|
|
fmt.Println("WARNING: Failed to send EOS to pipeline")
|
|
}
|
|
fmt.Println("Sent EOS")
|
|
})
|
|
return gst.PadProbeRemove
|
|
}
|
|
fmt.Println("Send EOS is false ignoring")
|
|
return gst.PadProbeOK
|
|
})
|
|
|
|
return pipeline, nil
|
|
}
|
|
|
|
func runPipeline(loop *glib.MainLoop, pipeline *gst.Pipeline) {
|
|
// Create a watch on the pipeline to kill the main loop when EOS is received
|
|
pipeline.Bus().AddWatch(0, func(bus *gst.Bus, msg *gst.Message) bool {
|
|
switch msg.Type() {
|
|
case gst.MessageEos:
|
|
fmt.Println("Got EOS message")
|
|
loop.Quit()
|
|
default:
|
|
fmt.Println(msg)
|
|
}
|
|
return true
|
|
})
|
|
|
|
// Start the pipeline
|
|
pipeline.SetState(gst.StatePlaying)
|
|
|
|
go func() {
|
|
// Loop and on the third iteration send the custom event.
|
|
ticker := time.NewTicker(time.Second * 2)
|
|
count := 0
|
|
for range ticker.C {
|
|
ev := ExampleCustomEvent{Count: count}
|
|
if count == 3 {
|
|
ev.SendEOS = true
|
|
}
|
|
st := gst.MarshalStructure(ev)
|
|
|
|
if !pipeline.SendEvent(gst.NewEventCustom(gst.EventCustomDownstream, st)) {
|
|
fmt.Println("Warning: failed to send custom event")
|
|
}
|
|
if count == 3 {
|
|
break
|
|
}
|
|
count++
|
|
}
|
|
}()
|
|
|
|
// When passing an object created by the bindings between scopes, there is a posibility
|
|
// the finalizer will leak and destroy your object before you are done with it. One way
|
|
// of dealing with this is by taking an additional Ref and disposing of it when you are
|
|
// done with the new scope. An alternative is to declare Keep() *after* where you know
|
|
// you will be done with the object. This instructs the runtime to defer the finalizer
|
|
// until after this point is passed in the code execution.
|
|
|
|
loop.Run()
|
|
|
|
runtime.KeepAlive(pipeline)
|
|
}
|
|
|
|
func main() {
|
|
pipeline, err := createPipeline()
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
mainloop := glib.NewMainLoop(glib.MainContextDefault(), false)
|
|
|
|
runPipeline(mainloop, pipeline)
|
|
}
|