mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-05 16:06:55 +08:00
Merge plugin experimentation branch - GstBaseSrcs can now be implemented via the bindings but with very limited functionality still
This commit is contained in:
@@ -1,89 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"text/tabwriter"
|
|
||||||
)
|
|
||||||
|
|
||||||
type color string
|
|
||||||
|
|
||||||
var (
|
|
||||||
colorReset color = "\033[0m"
|
|
||||||
colorBlack color = "\033[0;30m"
|
|
||||||
colorRed color = "\033[0;31m"
|
|
||||||
colorGreen color = "\033[0;32m"
|
|
||||||
colorOrange color = "\033[0;33m"
|
|
||||||
colorBlue color = "\033[0;34m"
|
|
||||||
colorPurple color = "\033[0;35m"
|
|
||||||
colorCyan color = "\033[0;36m"
|
|
||||||
colorLightGray color = "\033[0;37m"
|
|
||||||
colorDarkGray color = "\033[1;30m"
|
|
||||||
colorLightRed color = "\033[1;31m"
|
|
||||||
colorLightGreen color = "\033[1;32m"
|
|
||||||
colorYellow color = "\033[1;33m"
|
|
||||||
colorLightBlue color = "\033[1;34m"
|
|
||||||
colorLightPurple color = "\033[1;35m"
|
|
||||||
colorLightCyan color = "\033[1;36m"
|
|
||||||
colorWhite color = "\033[1;37m"
|
|
||||||
)
|
|
||||||
|
|
||||||
func disableColor() {
|
|
||||||
colorReset = ""
|
|
||||||
colorBlack = ""
|
|
||||||
colorRed = ""
|
|
||||||
colorGreen = ""
|
|
||||||
colorOrange = ""
|
|
||||||
colorBlue = ""
|
|
||||||
colorPurple = ""
|
|
||||||
colorCyan = ""
|
|
||||||
colorLightGray = ""
|
|
||||||
colorDarkGray = ""
|
|
||||||
colorLightRed = ""
|
|
||||||
colorLightGreen = ""
|
|
||||||
colorYellow = ""
|
|
||||||
colorLightBlue = ""
|
|
||||||
colorLightPurple = ""
|
|
||||||
colorLightCyan = ""
|
|
||||||
colorWhite = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c color) print(s string) { fmt.Printf("%s%s%s", c, s, colorReset) }
|
|
||||||
func (c color) sprint(s string) string { return fmt.Sprintf("%s%s%s", c, s, colorReset) }
|
|
||||||
func (c color) printIndent(i int, s string) { c.print(fmt.Sprintf("%s%s", strings.Repeat(" ", i), s)) }
|
|
||||||
func (c color) printf(f string, args ...interface{}) { c.print(fmt.Sprintf(f, args...)) }
|
|
||||||
func (c color) printfIndent(i int, f string, args ...interface{}) {
|
|
||||||
c.printf(fmt.Sprintf("%s%s", strings.Repeat(" ", i), fmt.Sprintf(f, args...)))
|
|
||||||
}
|
|
||||||
func (c color) fprint(w io.Writer, s string) { fmt.Fprintf(w, fmt.Sprintf("%s%s%s", c, s, colorReset)) }
|
|
||||||
func (c color) fprintf(w io.Writer, f string, args ...interface{}) {
|
|
||||||
c.fprint(w, fmt.Sprintf(f, args...))
|
|
||||||
}
|
|
||||||
func (c color) fprintIndent(w io.Writer, i int, s string) {
|
|
||||||
c.fprint(w, fmt.Sprintf("%s%s", strings.Repeat(" ", i), s))
|
|
||||||
}
|
|
||||||
func (c color) fprintfIndent(w io.Writer, i int, f string, args ...interface{}) {
|
|
||||||
c.fprint(w, fmt.Sprintf("%s%s", strings.Repeat(" ", i), fmt.Sprintf(f, args...)))
|
|
||||||
}
|
|
||||||
|
|
||||||
var srcRegex = regexp.MustCompile("^\\[.*?\\]")
|
|
||||||
var typeRegex = regexp.MustCompile("[A-Z\\-]+")
|
|
||||||
var msgRegex = regexp.MustCompile("[^\\-]+$")
|
|
||||||
|
|
||||||
// colorify adds color to a string in the format of "[src] TYPE - MESSAGE"
|
|
||||||
func colorify(str string) string {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
w := new(tabwriter.Writer)
|
|
||||||
w.Init(buf, 4, 24, 0, '\t', 0)
|
|
||||||
fmt.Fprintf(w,
|
|
||||||
"%s \t %s \t %s",
|
|
||||||
colorBlue.sprint(srcRegex.FindString(str)),
|
|
||||||
colorGreen.sprint(typeRegex.FindString(str)),
|
|
||||||
colorLightGray.sprint(msgRegex.FindString(str)),
|
|
||||||
)
|
|
||||||
w.Flush()
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
@@ -1,304 +0,0 @@
|
|||||||
// Inspect is a simplified version of gst-inspect-<version>. It parses
|
|
||||||
// the name of a plugin on the command line and dumps the element's properties
|
|
||||||
// to stdout.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"text/tabwriter"
|
|
||||||
|
|
||||||
"github.com/gotk3/gotk3/glib"
|
|
||||||
"github.com/tinyzimmer/go-gst/gst"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) == 1 {
|
|
||||||
fmt.Println("You must provide an element to inspect")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
gst.Init(nil)
|
|
||||||
|
|
||||||
if err := inspect(os.Args[1]); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func inspect(name string) error {
|
|
||||||
// load the registry
|
|
||||||
registry := gst.GetRegistry()
|
|
||||||
// get the factory for the element
|
|
||||||
factory := gst.Find(name)
|
|
||||||
|
|
||||||
if factory == nil {
|
|
||||||
return fmt.Errorf("Could not get details for factory '%s'", name)
|
|
||||||
}
|
|
||||||
defer factory.Unref()
|
|
||||||
|
|
||||||
// assume it's an element for now, can implement more later
|
|
||||||
elem, err := gst.NewElement(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer elem.Unref()
|
|
||||||
|
|
||||||
var maxLevel int
|
|
||||||
|
|
||||||
// dump info about the element
|
|
||||||
|
|
||||||
printFactoryDetails(registry, factory)
|
|
||||||
printPluginDetails(registry, factory)
|
|
||||||
printHierarchy(elem.TypeFromInstance(), 0, &maxLevel)
|
|
||||||
printInterfaces(elem)
|
|
||||||
printPadTemplates(elem)
|
|
||||||
printClockingInfo(elem)
|
|
||||||
printURIHandlerInfo(elem)
|
|
||||||
printPadInfo(elem)
|
|
||||||
printElementPropertiesInfo(elem)
|
|
||||||
printSignalInfo(elem)
|
|
||||||
printChildrenInfo(elem)
|
|
||||||
printPresentList(elem)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func printFactoryDetails(registry *gst.Registry, factory *gst.ElementFactory) {
|
|
||||||
|
|
||||||
// initialize tabwriter
|
|
||||||
w := new(tabwriter.Writer)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
w.Init(
|
|
||||||
buf,
|
|
||||||
40, // minwidth
|
|
||||||
30, // tabwith
|
|
||||||
0, // padding
|
|
||||||
' ', // padchar
|
|
||||||
0, // flags
|
|
||||||
)
|
|
||||||
|
|
||||||
colorOrange.fprint(w, "Factory Details:\n")
|
|
||||||
for _, key := range factory.GetMetadataKeys() {
|
|
||||||
colorBlue.fprintfIndent(w, 2, "%s \t ", strings.Title(key))
|
|
||||||
colorLightGray.fprint(w, factory.GetMetadata(key))
|
|
||||||
colorReset.fprint(w, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Flush()
|
|
||||||
fmt.Print(buf.String())
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printPluginDetails(registry *gst.Registry, factory *gst.ElementFactory) {
|
|
||||||
|
|
||||||
// initialize tabwriter
|
|
||||||
w := new(tabwriter.Writer)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
w.Init(
|
|
||||||
buf,
|
|
||||||
40, // minwidth
|
|
||||||
30, // tabwith
|
|
||||||
0, // padding
|
|
||||||
' ', // padchar
|
|
||||||
0, // flags
|
|
||||||
)
|
|
||||||
|
|
||||||
pluginFeature, err := registry.LookupFeature(factory.Name())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
plugin := pluginFeature.GetPlugin()
|
|
||||||
if plugin == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer pluginFeature.Unref()
|
|
||||||
defer plugin.Unref()
|
|
||||||
|
|
||||||
colorOrange.fprint(w, "Plugin Details:\n")
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "Name \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", pluginFeature.GetPluginName())
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "Description \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", plugin.Description())
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "Filename \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", plugin.Filename())
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "Version \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", plugin.Version())
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "License \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", plugin.License())
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "Source module \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", plugin.Source())
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "Binary package \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", plugin.Package())
|
|
||||||
|
|
||||||
colorBlue.fprintIndent(w, 2, "Origin URLs \t ")
|
|
||||||
colorLightGray.fprintf(w, "%s\n", plugin.Origin())
|
|
||||||
|
|
||||||
w.Flush()
|
|
||||||
fmt.Print(buf.String())
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printHierarchy(gtype glib.Type, level int, maxLevel *int) {
|
|
||||||
parent := gtype.Parent()
|
|
||||||
|
|
||||||
*maxLevel = *maxLevel + 1
|
|
||||||
level++
|
|
||||||
|
|
||||||
if parent > 0 {
|
|
||||||
printHierarchy(parent, level, maxLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 1; i < *maxLevel-level; i++ {
|
|
||||||
colorReset.print(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
if *maxLevel-level > 0 {
|
|
||||||
colorLightPurple.print(" +----")
|
|
||||||
}
|
|
||||||
|
|
||||||
colorGreen.printf("%s\n", gtype.Name())
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func printInterfaces(elem *gst.Element) {
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
if ifaces := elem.Interfaces(); len(ifaces) > 0 {
|
|
||||||
colorOrange.print("Implemented Interfaces:")
|
|
||||||
for _, iface := range ifaces {
|
|
||||||
colorGreen.printfIndent(2, "%s\n", iface)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printPadTemplates(elem *gst.Element) {
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
tmpls := elem.GetPadTemplates()
|
|
||||||
if len(tmpls) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
colorOrange.print("Pad templates:\n")
|
|
||||||
for _, tmpl := range tmpls {
|
|
||||||
colorBlue.printfIndent(2, "%s template", strings.ToUpper(tmpl.Name()))
|
|
||||||
colorReset.print(": ")
|
|
||||||
colorBlue.printf("'%s'\n", strings.ToLower(tmpl.Direction().String()))
|
|
||||||
|
|
||||||
colorBlue.printIndent(4, "Availability")
|
|
||||||
colorReset.print(": ")
|
|
||||||
colorLightGray.print(strings.Title(tmpl.Presence().String()))
|
|
||||||
colorReset.print("\n")
|
|
||||||
|
|
||||||
colorBlue.printIndent(4, "Capabilities")
|
|
||||||
colorReset.print(": ")
|
|
||||||
|
|
||||||
printCaps(tmpl.Caps(), 6)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printClockingInfo(elem *gst.Element) {
|
|
||||||
if !elem.Has(gst.ElementFlagRequireClock) && !elem.Has(gst.ElementFlagProvideClock) {
|
|
||||||
colorLightGray.print("Element has no clocking capabilities.\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("%sClocking Interactions:%s\n", colorOrange, colorReset)
|
|
||||||
|
|
||||||
if elem.Has(gst.ElementFlagRequireClock) {
|
|
||||||
colorLightGray.printIndent(2, "element requires a clock\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if elem.Has(gst.ElementFlagProvideClock) {
|
|
||||||
clock := elem.GetClock()
|
|
||||||
if clock == nil {
|
|
||||||
colorLightGray.printIndent(2, "element is supposed to provide a clock but returned NULL%s\n")
|
|
||||||
} else {
|
|
||||||
defer clock.Unref()
|
|
||||||
colorLightGray.printIndent(2, "element provides a clock: ")
|
|
||||||
colorCyan.printf(clock.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printURIHandlerInfo(elem *gst.Element) {
|
|
||||||
if !elem.IsURIHandler() {
|
|
||||||
colorLightGray.print("Element has no URI handling capabilities.\n")
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
uriHandler := elem.URIHandler()
|
|
||||||
|
|
||||||
colorOrange.print("URI handling capabilities:\n")
|
|
||||||
colorLightGray.printfIndent(2, "Element can act as %s.\n", strings.ToLower(uriHandler.GetURIType().String()))
|
|
||||||
|
|
||||||
protos := uriHandler.GetURIProtocols()
|
|
||||||
|
|
||||||
if len(protos) == 0 {
|
|
||||||
fmt.Println()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
colorLightGray.printIndent(2, "Supported URI protocols:\n")
|
|
||||||
|
|
||||||
for _, proto := range protos {
|
|
||||||
colorCyan.printfIndent(4, "%s\n", proto)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printPadInfo(elem *gst.Element) {
|
|
||||||
|
|
||||||
colorOrange.print("Pads:\n")
|
|
||||||
pads := elem.GetPads()
|
|
||||||
if len(pads) == 0 {
|
|
||||||
colorCyan.printIndent(2, "none\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, pad := range elem.GetPads() {
|
|
||||||
defer pad.Unref()
|
|
||||||
|
|
||||||
colorBlue.printIndent(2, strings.ToUpper(pad.Direction().String()))
|
|
||||||
colorReset.print(": ")
|
|
||||||
colorLightGray.printf("'%s'\n", pad.Name())
|
|
||||||
|
|
||||||
if tmpl := pad.Template(); tmpl != nil {
|
|
||||||
defer tmpl.Unref()
|
|
||||||
colorBlue.printIndent(4, "Pad Template")
|
|
||||||
colorReset.print(": ")
|
|
||||||
colorLightGray.printf("'%s'\n", tmpl.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
if caps := pad.CurrentCaps(); caps != nil {
|
|
||||||
colorBlue.printIndent(2, "Capabilities:\n")
|
|
||||||
printCaps(caps, 4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printElementPropertiesInfo(elem *gst.Element) {
|
|
||||||
printObjectPropertiesInfo(elem.Object, "Element Properties")
|
|
||||||
}
|
|
||||||
|
|
||||||
func printSignalInfo(elem *gst.Element) {}
|
|
||||||
func printChildrenInfo(elem *gst.Element) {}
|
|
||||||
func printPresentList(elem *gst.Element) {}
|
|
@@ -1,349 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"text/tabwriter"
|
|
||||||
|
|
||||||
"github.com/gotk3/gotk3/glib"
|
|
||||||
"github.com/tinyzimmer/go-gst/gst"
|
|
||||||
)
|
|
||||||
|
|
||||||
func printFieldType(s string) {
|
|
||||||
colorGreen.printIndent(24, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printFieldName(s string) {
|
|
||||||
colorOrange.print(s)
|
|
||||||
colorReset.print(": ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func printFieldValue(s string) {
|
|
||||||
colorCyan.printf("%s ", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByName implements sort. Interface based on the Name field.
|
|
||||||
type ByName []*gst.ParameterSpec
|
|
||||||
|
|
||||||
func (a ByName) Len() int { return len(a) }
|
|
||||||
func (a ByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
|
|
||||||
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
||||||
|
|
||||||
// ByValue implements sort. Interface based on the Value field.
|
|
||||||
type ByValue []*gst.FlagsValue
|
|
||||||
|
|
||||||
func (a ByValue) Len() int { return len(a) }
|
|
||||||
func (a ByValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
|
||||||
func (a ByValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
||||||
|
|
||||||
func printObjectPropertiesInfo(obj *gst.Object, description string) {
|
|
||||||
colorOrange.printf("%s:\n", description)
|
|
||||||
|
|
||||||
// for now this function only handles elements
|
|
||||||
|
|
||||||
props := obj.ListProperties()
|
|
||||||
sort.Sort(ByName(props))
|
|
||||||
|
|
||||||
for _, param := range props {
|
|
||||||
defer param.Unref()
|
|
||||||
|
|
||||||
colorBlue.printfIndent(2, "%-20s", param.Name)
|
|
||||||
colorReset.printf(": %s", param.Blurb)
|
|
||||||
|
|
||||||
colorReset.print("\n")
|
|
||||||
|
|
||||||
colorOrange.printIndent(24, "flags")
|
|
||||||
colorReset.print(": ")
|
|
||||||
colorCyan.print(param.Flags.GstFlagsString())
|
|
||||||
|
|
||||||
if !param.Flags.Has(gst.ParameterReadable) {
|
|
||||||
colorReset.print(" | ")
|
|
||||||
colorLightPurple.print("Write only")
|
|
||||||
} else if !param.Flags.Has(gst.ParameterWritable) {
|
|
||||||
colorReset.print(" | ")
|
|
||||||
colorLightPurple.print("Read only")
|
|
||||||
}
|
|
||||||
|
|
||||||
colorReset.print("\n")
|
|
||||||
|
|
||||||
// get the value and continue on any error (very unlikely)
|
|
||||||
|
|
||||||
goval, _ := param.DefaultValue.GoValue()
|
|
||||||
|
|
||||||
// skips deprecated types
|
|
||||||
|
|
||||||
switch param.ValueType {
|
|
||||||
|
|
||||||
case glib.TYPE_STRING:
|
|
||||||
printFieldType("String. ")
|
|
||||||
printFieldName("Default")
|
|
||||||
if goval == nil {
|
|
||||||
printFieldValue("null")
|
|
||||||
} else {
|
|
||||||
str, _ := param.DefaultValue.GetString()
|
|
||||||
printFieldValue(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
case glib.TYPE_BOOLEAN:
|
|
||||||
var valStr string
|
|
||||||
if goval == nil {
|
|
||||||
valStr = "unknown" // edge case
|
|
||||||
} else {
|
|
||||||
b := goval.(bool)
|
|
||||||
valStr = fmt.Sprintf("%t", b)
|
|
||||||
}
|
|
||||||
printFieldType("Boolean. ")
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(valStr)
|
|
||||||
|
|
||||||
case glib.TYPE_UINT:
|
|
||||||
var valStr string
|
|
||||||
if goval == nil {
|
|
||||||
valStr = "0"
|
|
||||||
} else {
|
|
||||||
v := goval.(uint)
|
|
||||||
valStr = fmt.Sprintf("%d", v)
|
|
||||||
}
|
|
||||||
printFieldType("Unsigned Integer. ")
|
|
||||||
printFieldName("Range")
|
|
||||||
min, max := param.UIntRange()
|
|
||||||
printFieldValue(fmt.Sprintf("%d - %d ", min, max))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(valStr)
|
|
||||||
|
|
||||||
case glib.TYPE_INT:
|
|
||||||
var valStr string
|
|
||||||
if goval == nil {
|
|
||||||
valStr = "0"
|
|
||||||
} else {
|
|
||||||
v := goval.(int)
|
|
||||||
valStr = fmt.Sprintf("%d", v)
|
|
||||||
}
|
|
||||||
printFieldType("Integer. ")
|
|
||||||
printFieldName("Range")
|
|
||||||
min, max := param.IntRange()
|
|
||||||
printFieldValue(fmt.Sprintf("%d - %d ", min, max))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(valStr)
|
|
||||||
|
|
||||||
case glib.TYPE_UINT64:
|
|
||||||
var valStr string
|
|
||||||
if goval == nil {
|
|
||||||
valStr = "0"
|
|
||||||
} else {
|
|
||||||
v := goval.(uint64)
|
|
||||||
valStr = fmt.Sprintf("%d", v)
|
|
||||||
}
|
|
||||||
printFieldType("Unsigned Integer64. ")
|
|
||||||
printFieldName("Range")
|
|
||||||
min, max := param.UInt64Range()
|
|
||||||
printFieldValue(fmt.Sprintf("%d - %d ", min, max))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(valStr)
|
|
||||||
|
|
||||||
case glib.TYPE_INT64:
|
|
||||||
var valStr string
|
|
||||||
if goval == nil {
|
|
||||||
valStr = "0"
|
|
||||||
} else {
|
|
||||||
v := goval.(int64)
|
|
||||||
valStr = fmt.Sprintf("%d", v)
|
|
||||||
}
|
|
||||||
printFieldType("Integer64. ")
|
|
||||||
printFieldName("Range")
|
|
||||||
min, max := param.Int64Range()
|
|
||||||
printFieldValue(fmt.Sprintf("%d - %d ", min, max))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(valStr)
|
|
||||||
|
|
||||||
case glib.TYPE_FLOAT:
|
|
||||||
var valStr string
|
|
||||||
if goval == nil {
|
|
||||||
valStr = "0"
|
|
||||||
} else {
|
|
||||||
v := goval.(float64)
|
|
||||||
valStr = fmt.Sprintf("%15.7g", v)
|
|
||||||
}
|
|
||||||
printFieldType("Float. ")
|
|
||||||
printFieldName("Range")
|
|
||||||
min, max := param.FloatRange()
|
|
||||||
printFieldValue(fmt.Sprintf("%15.7g - %15.7g ", min, max))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(valStr)
|
|
||||||
|
|
||||||
case glib.TYPE_DOUBLE:
|
|
||||||
var valStr string
|
|
||||||
if goval == nil {
|
|
||||||
valStr = "0"
|
|
||||||
} else {
|
|
||||||
v := goval.(float64)
|
|
||||||
valStr = fmt.Sprintf("%15.7g", v)
|
|
||||||
}
|
|
||||||
printFieldType("Double. ")
|
|
||||||
printFieldName("Range")
|
|
||||||
min, max := param.DoubleRange()
|
|
||||||
printFieldValue(fmt.Sprintf("%15.7g - %15.7g ", min, max))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(valStr)
|
|
||||||
|
|
||||||
default:
|
|
||||||
if param.IsCaps() {
|
|
||||||
|
|
||||||
if caps := param.GetCaps(); caps != nil {
|
|
||||||
printCaps(caps, 24)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if param.IsEnum() {
|
|
||||||
|
|
||||||
enumValues := param.GetEnumValues()
|
|
||||||
iface, _ := param.DefaultValue.GoValue()
|
|
||||||
var curVal string
|
|
||||||
if iface == nil {
|
|
||||||
curVal = "-1"
|
|
||||||
} else {
|
|
||||||
curVal = fmt.Sprintf("%v", iface)
|
|
||||||
}
|
|
||||||
var defaultStr string
|
|
||||||
for _, val := range enumValues {
|
|
||||||
if curVal == strconv.Itoa(val.Value) {
|
|
||||||
defaultStr = val.ValueNick
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printFieldType(fmt.Sprintf(`Enum "%s" `, param.ValueType.Name()))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(fmt.Sprintf(`%s "%s"`, curVal, defaultStr))
|
|
||||||
colorReset.print("\n")
|
|
||||||
for idx, val := range enumValues {
|
|
||||||
w := new(tabwriter.Writer)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
w.Init(buf, 100, 73, 0, '\t', 0)
|
|
||||||
colorOrange.fprintfIndent(w, 27, "(%d)", val.Value)
|
|
||||||
colorReset.fprint(w, ": ")
|
|
||||||
colorCyan.fprint(w, val.ValueNick)
|
|
||||||
colorReset.fprint(w, "\t - ")
|
|
||||||
colorLightGray.fprint(w, val.ValueName)
|
|
||||||
w.Flush()
|
|
||||||
fmt.Print(buf.String())
|
|
||||||
if idx < len(enumValues)-1 {
|
|
||||||
colorReset.print("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if param.IsFlags() {
|
|
||||||
|
|
||||||
flags := param.GetFlagValues()
|
|
||||||
sort.Sort(ByValue(flags))
|
|
||||||
flagStr := "+"
|
|
||||||
for _, flag := range flags {
|
|
||||||
flagStr += fmt.Sprintf(" %s", flag.ValueNick)
|
|
||||||
}
|
|
||||||
if flagStr == "+" {
|
|
||||||
flagStr = "(none)"
|
|
||||||
}
|
|
||||||
printFieldType(fmt.Sprintf(`Flags "%s" `, param.ValueType.Name()))
|
|
||||||
printFieldName("Default")
|
|
||||||
printFieldValue(fmt.Sprintf(`0x%08x "%s"`, param.GetDefaultFlags(), flagStr))
|
|
||||||
|
|
||||||
for idx, flag := range flags {
|
|
||||||
w := new(tabwriter.Writer)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
w.Init(buf, 100, 73, 0, '\t', 0)
|
|
||||||
colorOrange.fprintfIndent(w, 27, "(%d)", flag.Value)
|
|
||||||
colorReset.fprint(w, ": ")
|
|
||||||
colorCyan.fprint(w, flag.ValueNick)
|
|
||||||
colorReset.fprint(w, "\t - ")
|
|
||||||
colorLightGray.fprint(w, flag.ValueName)
|
|
||||||
w.Flush()
|
|
||||||
fmt.Print(buf.String())
|
|
||||||
if idx < len(flags)-1 {
|
|
||||||
colorReset.print("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if param.IsObject() {
|
|
||||||
|
|
||||||
colorLightGray.printIndent(24, "Object of type ")
|
|
||||||
colorGreen.printf(`"%s"`, param.ValueType.Name())
|
|
||||||
|
|
||||||
} else if param.IsBoxed() {
|
|
||||||
|
|
||||||
colorLightGray.printIndent(24, "Boxed pointer of type ")
|
|
||||||
colorGreen.printf(`"%s"`, param.ValueType.Name())
|
|
||||||
if param.ValueType.Name() == "GstStructure" {
|
|
||||||
structure := gst.StructureFromGValue(param.DefaultValue)
|
|
||||||
if structure != nil {
|
|
||||||
for key, val := range structure.Values() {
|
|
||||||
colorReset.printIndent(26, "(gpointer) ")
|
|
||||||
colorYellow.printf("%15s:", key)
|
|
||||||
colorBlue.printf("%v", val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if param.IsPointer() {
|
|
||||||
|
|
||||||
colorLightGray.printIndent(24, "Pointer of type ")
|
|
||||||
colorGreen.printf(`"%s`, param.ValueType.Name())
|
|
||||||
|
|
||||||
} else if param.IsFraction() {
|
|
||||||
|
|
||||||
colorGreen.printIndent(24, "Fraction.")
|
|
||||||
|
|
||||||
} else if param.IsGstArray() {
|
|
||||||
|
|
||||||
colorGreen.printIndent(24, "GstArray.")
|
|
||||||
|
|
||||||
} else {
|
|
||||||
colorReset.printIndent(24, "Unknown type ")
|
|
||||||
colorGreen.printf(`"%s`, param.ValueType.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
colorReset.print("\n")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printCaps(caps *gst.Caps, indent int) {
|
|
||||||
if caps == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
colorReset.print("\n")
|
|
||||||
defer func() { colorReset.print("\n") }()
|
|
||||||
|
|
||||||
if caps.IsAny() {
|
|
||||||
colorOrange.printIndent(indent, "ANY")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if caps.IsEmpty() {
|
|
||||||
colorOrange.printIndent(indent, "EMPTY")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < caps.GetSize(); i++ {
|
|
||||||
structure := caps.GetStructureAt(i)
|
|
||||||
features := caps.GetFeaturesAt(i)
|
|
||||||
|
|
||||||
if features != nil && features.IsAny() {
|
|
||||||
colorOrange.printIndent(indent+20, structure.Name())
|
|
||||||
colorLightGray.print(" (")
|
|
||||||
colorGreen.print(features.String())
|
|
||||||
colorLightGray.print(")")
|
|
||||||
} else {
|
|
||||||
colorOrange.printIndent(indent+20, structure.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
colorReset.print("\n")
|
|
||||||
for k, v := range structure.Values() {
|
|
||||||
colorCyan.printIndent(indent+10, k)
|
|
||||||
colorReset.print(": ")
|
|
||||||
colorBlue.printf("%v\n", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
325
examples/plugins/filesrc/filesrc.go
Normal file
325
examples/plugins/filesrc/filesrc.go
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
// This example demonstrates a filesrc plugin implemented in Go.
|
||||||
|
//
|
||||||
|
// Every element in a Gstreamer pipeline is provided by plugins. Some are builtin while
|
||||||
|
// others are provided by third-parties or distributed privately. The plugins are built
|
||||||
|
// around the GObject type system.
|
||||||
|
//
|
||||||
|
// Go-gst offers loose bindings around the GObject type system to provide the necessary
|
||||||
|
// functionality to implement these plugins. The example in this code produces an element
|
||||||
|
// that can read from a file on the local system.
|
||||||
|
//
|
||||||
|
// In order to build the plugin for use by GStreamer, you may do the following:
|
||||||
|
//
|
||||||
|
// $ go build -o libgstgofilesrc.so -buildmode c-shared .
|
||||||
|
//
|
||||||
|
//
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
"github.com/tinyzimmer/go-gst/gst"
|
||||||
|
"github.com/tinyzimmer/go-gst/gst/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Here we define a list of ParamSpecs that will make up the properties for our element.
|
||||||
|
// This element only has a single property, the location of the file to read from.
|
||||||
|
// When getting and setting properties later on, you will reference them by their index in
|
||||||
|
// this list.
|
||||||
|
var properties = []*gst.ParameterSpec{
|
||||||
|
gst.NewStringParameter(
|
||||||
|
"location", // The name of the parameter
|
||||||
|
"File Location", // The long name for the parameter
|
||||||
|
"Location of the file to read from", // A blurb about the parameter
|
||||||
|
nil, // A default value for the parameter
|
||||||
|
gst.ParameterReadWrite, // Flags for the parameter
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we declare a private struct to hold our internal state.
|
||||||
|
type state struct {
|
||||||
|
// Whether the element is started or not
|
||||||
|
started bool
|
||||||
|
// The file the element is reading from
|
||||||
|
file *os.File
|
||||||
|
// The current position in the file
|
||||||
|
position uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is another private struct where we hold the parameter values set on our
|
||||||
|
// element.
|
||||||
|
type settings struct {
|
||||||
|
location string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally a structure is defined that implements (at a minimum) the gst.GoElement interface.
|
||||||
|
// It is possible to signal to the bindings to inherit from other classes or implement other
|
||||||
|
// interfaces via the registration and TypeInit processes.
|
||||||
|
type fileSrc struct {
|
||||||
|
// The settings for the element
|
||||||
|
settings *settings
|
||||||
|
// The current state of the element
|
||||||
|
state *state
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private methods only used internally by the plugin
|
||||||
|
|
||||||
|
// setLocation is a simple method to check the validity of a provided file path and set the
|
||||||
|
// local value with it.
|
||||||
|
func (f *fileSrc) setLocation(path string) error {
|
||||||
|
if f.state.started {
|
||||||
|
return errors.New("Changing the `location` property on a started `GoFileSrc` is not supported")
|
||||||
|
}
|
||||||
|
path = strings.TrimPrefix(path, "file://")
|
||||||
|
if path == "" {
|
||||||
|
f.settings.location = ""
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
stat, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("%s does not exist", path)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Could not stat %s, err: %s", path, err.Error())
|
||||||
|
}
|
||||||
|
if stat.IsDir() {
|
||||||
|
return fmt.Errorf("%s is a directory", path)
|
||||||
|
}
|
||||||
|
f.settings.location = path
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ObjectSubclass implementations below are for registering the various aspects of our
|
||||||
|
// element and its capabilities with the type system.
|
||||||
|
|
||||||
|
// Every element needs to provide its own constructor that returns the an initialized
|
||||||
|
// gst.GoElement implementation. Here we simply create a new fileSrc with zeroed settings
|
||||||
|
// and state objects.
|
||||||
|
func (f *fileSrc) New() gst.GoElement {
|
||||||
|
return &fileSrc{
|
||||||
|
settings: &settings{},
|
||||||
|
state: &state{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The TypeInit method should register any additional interfaces provided by the element.
|
||||||
|
// In this example we signal to the type system that we also implement the GstURIHandler interface.
|
||||||
|
func (f *fileSrc) TypeInit(instance *gst.TypeInstance) {
|
||||||
|
instance.AddInterface(gst.InterfaceURIHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ClassInit method should specify the metadata for this element as well as add any pad templates
|
||||||
|
// and properties.
|
||||||
|
func (f *fileSrc) ClassInit(klass *gst.ElementClass) {
|
||||||
|
klass.SetMetadata(
|
||||||
|
"File Source",
|
||||||
|
"Source/File",
|
||||||
|
"Read stream from a file",
|
||||||
|
"Avi Zimmerman <avi.zimmerman@gmail.com>",
|
||||||
|
)
|
||||||
|
caps := gst.NewAnyCaps()
|
||||||
|
srcPadTemplate := gst.NewPadTemplate(
|
||||||
|
"src",
|
||||||
|
gst.PadDirectionSource,
|
||||||
|
gst.PadPresenceAlways,
|
||||||
|
caps,
|
||||||
|
)
|
||||||
|
klass.AddPadTemplate(srcPadTemplate)
|
||||||
|
klass.InstallProperties(properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object implementations are used during the initialization of element. The
|
||||||
|
// methods are called once the obejct is constructed and its properties are read
|
||||||
|
// and written to.
|
||||||
|
|
||||||
|
// SetProperty is called when a `value` is set to the property at index `id` in the
|
||||||
|
// properties slice that we installed during ClassInit. It should attempt to register
|
||||||
|
// the value locally or signal any errors that occur in the process.
|
||||||
|
func (f *fileSrc) SetProperty(self *gst.Object, id uint, value *glib.Value) {
|
||||||
|
param := properties[id]
|
||||||
|
switch param.Name() {
|
||||||
|
case "location":
|
||||||
|
var val string
|
||||||
|
if value == nil {
|
||||||
|
val = ""
|
||||||
|
} else {
|
||||||
|
val, _ = value.GetString()
|
||||||
|
}
|
||||||
|
if err := f.setLocation(val); err != nil {
|
||||||
|
gst.ToElement(self).Error(gst.DomainLibrary, gst.LibraryErrorSettings,
|
||||||
|
"Could not set location on object",
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
gst.ToElement(self).Info(gst.DomainLibrary, fmt.Sprintf("Set location to %s", f.settings.location))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProperty is called to retrieve the value of the property at index `id` in the properties
|
||||||
|
// slice provided at ClassInit.
|
||||||
|
func (f *fileSrc) GetProperty(self *gst.Object, id uint) *glib.Value {
|
||||||
|
param := properties[id]
|
||||||
|
switch param.Name() {
|
||||||
|
case "location":
|
||||||
|
if f.settings.location == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
val, err := glib.GValue(f.settings.location)
|
||||||
|
if err == nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
gst.ToElement(self).Error(gst.DomainLibrary, gst.LibraryErrorSettings,
|
||||||
|
fmt.Sprintf("Could not convert %s to GValue", f.settings.location),
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructed is called when the type system is done constructing the object. Any finalizations required
|
||||||
|
// during the initializatin cycle can be performed here. In this example, we set the format on our
|
||||||
|
// underlying GstBaseSrc to bytes.
|
||||||
|
func (f *fileSrc) Constructed(self *gst.Object) {
|
||||||
|
base.ToGstBaseSrc(self).SetFormat(gst.FormatBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GstBaseSrc implementations are optional methods to implement from the base.GstBaseSrcImpl interface.
|
||||||
|
// If the method is not overridden by the implementing struct, it will be inherited from the parent class.
|
||||||
|
|
||||||
|
// IsSeekable returns that we are, in fact, seekable.
|
||||||
|
func (f *fileSrc) IsSeekable(*base.GstBaseSrc) bool { return true }
|
||||||
|
|
||||||
|
// GetSize will return the total size of the file at the configured location.
|
||||||
|
func (f *fileSrc) GetSize(self *base.GstBaseSrc) (bool, int64) {
|
||||||
|
if !f.state.started {
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
stat, err := f.state.file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
// This should never happen
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorFailed,
|
||||||
|
"Could not retrieve fileinfo on opened file",
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
return true, stat.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start is called to start this element. In this example, the configured file is opened for reading,
|
||||||
|
// and any error encountered in the process is posted to the pipeline.
|
||||||
|
func (f *fileSrc) Start(self *base.GstBaseSrc) bool {
|
||||||
|
if f.state.started {
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorSettings, "FileSrc is already started", "")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.settings.location == "" {
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorSettings, "File location is not defined", "")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
f.state.file, err = os.OpenFile(f.settings.location, syscall.O_RDONLY, 0444)
|
||||||
|
if err != nil {
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorOpenRead,
|
||||||
|
fmt.Sprintf("Could not open file %s for reading", f.settings.location), err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
f.state.position = 0
|
||||||
|
|
||||||
|
f.state.started = true
|
||||||
|
|
||||||
|
self.StartComplete(gst.FlowOK)
|
||||||
|
|
||||||
|
self.Info(gst.DomainResource, "Started")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop is called to stop the element. The file is closed and the local values are zeroed out.
|
||||||
|
func (f *fileSrc) Stop(self *base.GstBaseSrc) bool {
|
||||||
|
if !f.state.started {
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorSettings, "FileSrc is not started", "")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.state.file.Close(); err != nil {
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorClose, "Failed to close the source file", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
f.state.file = nil
|
||||||
|
f.state.position = 0
|
||||||
|
f.state.started = false
|
||||||
|
|
||||||
|
self.Info(gst.DomainResource, "Stopped")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill is called to fill a pre-allocated buffer with the data at offset to the given size.
|
||||||
|
// Since we declared that we are seekable, we need to support the provided offset not neccesarily matching
|
||||||
|
// where we currently are in the file. This is why we store the position in the file locally.
|
||||||
|
func (f *fileSrc) Fill(self *base.GstBaseSrc, offset uint64, size uint, buffer *gst.Buffer) gst.FlowReturn {
|
||||||
|
if !f.state.started || f.state.file == nil {
|
||||||
|
self.Error(gst.DomainCore, gst.CoreErrorFailed, "Not started yet", "")
|
||||||
|
return gst.FlowError
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.state.position != offset {
|
||||||
|
if _, err := f.state.file.Seek(int64(offset), 0); err != nil {
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorSeek,
|
||||||
|
fmt.Sprintf("Failed to seek to %d in file", offset), err.Error())
|
||||||
|
return gst.FlowError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]byte, int(size))
|
||||||
|
if _, err := f.state.file.Read(out); err != nil && err != io.EOF {
|
||||||
|
self.Error(gst.DomainResource, gst.ResourceErrorRead,
|
||||||
|
fmt.Sprintf("Failed to read %d bytes from file at %d", size, offset), err.Error())
|
||||||
|
return gst.FlowError
|
||||||
|
}
|
||||||
|
|
||||||
|
f.state.position = f.state.position + uint64(size)
|
||||||
|
|
||||||
|
bufmap := buffer.Map(gst.MapWrite)
|
||||||
|
if bufmap == nil {
|
||||||
|
self.Error(gst.DomainLibrary, gst.LibraryErrorFailed, "Failed to map buffer", "")
|
||||||
|
return gst.FlowError
|
||||||
|
}
|
||||||
|
defer buffer.Unmap()
|
||||||
|
|
||||||
|
bufmap.WriteData(out)
|
||||||
|
buffer.SetSize(int64(size))
|
||||||
|
|
||||||
|
return gst.FlowOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// URIHandler implementations are the methods required by the GstURIHandler interface.
|
||||||
|
|
||||||
|
// GetURI returns the currently configured URI
|
||||||
|
func (f *fileSrc) GetURI() string { return fmt.Sprintf("file://%s", f.settings.location) }
|
||||||
|
|
||||||
|
// GetURIType returns the types of URI this element supports.
|
||||||
|
func (f *fileSrc) GetURIType() gst.URIType { return gst.URISource }
|
||||||
|
|
||||||
|
// GetProtocols returns the protcols this element supports.
|
||||||
|
func (f *fileSrc) GetProtocols() []string { return []string{"file"} }
|
||||||
|
|
||||||
|
// SetURI should set the URI that this element is working on.
|
||||||
|
func (f *fileSrc) SetURI(uri string) (bool, error) {
|
||||||
|
if uri == "file://" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
err := f.setLocation(uri)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
46
examples/plugins/filesrc/plugin.go
Normal file
46
examples/plugins/filesrc/plugin.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// The contents of this file could be generated from markers placed in filesrc.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/tinyzimmer/go-gst/gst"
|
||||||
|
"github.com/tinyzimmer/go-gst/gst/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The metadata for this plugin
|
||||||
|
var pluginMeta = &gst.PluginMetadata{
|
||||||
|
MajorVersion: gst.VersionMajor,
|
||||||
|
MinorVersion: gst.VersionMinor,
|
||||||
|
Name: "go-file-plugins",
|
||||||
|
Description: "File plugins written in Go",
|
||||||
|
Version: "v0.0.1",
|
||||||
|
License: gst.LicenseLGPL,
|
||||||
|
Source: "go-gst",
|
||||||
|
Package: "examples",
|
||||||
|
Origin: "https://github.com/tinyzimmer/go-gst",
|
||||||
|
ReleaseDate: "2021-01-04",
|
||||||
|
// The init function is called to register elements provided
|
||||||
|
// by the plugin.
|
||||||
|
Init: func(plugin *gst.Plugin) bool {
|
||||||
|
return gst.RegisterElement(
|
||||||
|
plugin,
|
||||||
|
"gofilesrc", // The name of the element
|
||||||
|
gst.RankNone, // The rank of the element
|
||||||
|
&fileSrc{}, // The GoElement implementation for the element
|
||||||
|
base.ExtendsBaseSrc, // The base subclass this element extends
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// A single method must be exported from the compiled library that provides for GStreamer
|
||||||
|
// to fetch the description and init function for this plugin. The name of the method
|
||||||
|
// must match the format gst_plugin_NAME_get_desc, where hyphens are replaced with underscores.
|
||||||
|
|
||||||
|
//export gst_plugin_gofilesrc_get_desc
|
||||||
|
func gst_plugin_gofilesrc_get_desc() unsafe.Pointer { return pluginMeta.Export() }
|
||||||
|
|
||||||
|
// main is left unimplemented since these files are compiled to c-shared.
|
||||||
|
func main() {}
|
1
go.sum
1
go.sum
@@ -1,4 +1,5 @@
|
|||||||
github.com/gotk3/gotk3 v0.4.0 h1:TIuhyQitGeRTxOQIV3AJlYtEWWJpC74JHwAIsxlH8MU=
|
github.com/gotk3/gotk3 v0.4.0 h1:TIuhyQitGeRTxOQIV3AJlYtEWWJpC74JHwAIsxlH8MU=
|
||||||
github.com/gotk3/gotk3 v0.4.0/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo=
|
github.com/gotk3/gotk3 v0.4.0/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo=
|
||||||
|
github.com/gotk3/gotk3 v0.5.2 h1:jbSFvUNMfo3ImM6BWBAkNUxY5piqP3eTc1YFbYy9ecU=
|
||||||
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
|
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
|
||||||
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
|
#ifndef __GST_APP_GO_H__
|
||||||
|
#define __GST_APP_GO_H__
|
||||||
|
|
||||||
#include <gst/app/gstappsink.h>
|
#include <gst/app/gstappsink.h>
|
||||||
#include <gst/app/gstappsrc.h>
|
#include <gst/app/gstappsrc.h>
|
||||||
|
|
||||||
inline GstAppSink * toGstAppSink (void *p) { return (GST_APP_SINK(p)); }
|
inline GstAppSink * toGstAppSink (void *p) { return (GST_APP_SINK(p)); }
|
||||||
inline GstAppSrc * toGstAppSrc (void *p) { return (GST_APP_SRC(p)); }
|
inline GstAppSrc * toGstAppSrc (void *p) { return (GST_APP_SRC(p)); }
|
||||||
|
|
||||||
|
#endif
|
2
gst/base/doc.go
Normal file
2
gst/base/doc.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Package base contains bindings for extendable GStreamer base objects.
|
||||||
|
package base
|
9
gst/base/gst.go.h
Normal file
9
gst/base/gst.go.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef __GST_BASE_GO_H__
|
||||||
|
#define __GST_BASE_GO_H__
|
||||||
|
|
||||||
|
#include <gst/base/gstbasesrc.h>
|
||||||
|
|
||||||
|
inline GstBaseSrc * toGstBaseSrc (void *p) { return GST_BASE_SRC_CAST(p); };
|
||||||
|
inline GstBaseSrcClass * toGstBaseSrcClass (void *p) { return (GstBaseSrcClass *)p; };
|
||||||
|
|
||||||
|
#endif
|
47
gst/base/gst_base_src.go
Normal file
47
gst/base/gst_base_src.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/tinyzimmer/go-gst/gst"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GstBaseSrc represents a GstBaseSrc.
|
||||||
|
type GstBaseSrc struct{ *gst.Element }
|
||||||
|
|
||||||
|
// ToGstBaseSrc returns a GstBaseSrc object for the given object.
|
||||||
|
func ToGstBaseSrc(obj *gst.Object) *GstBaseSrc {
|
||||||
|
return &GstBaseSrc{&gst.Element{Object: obj}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapGstBaseSrc wraps the given unsafe.Pointer in a GstBaseSrc instance.
|
||||||
|
func wrapGstBaseSrc(obj *C.GstBaseSrc) *GstBaseSrc {
|
||||||
|
return &GstBaseSrc{gst.FromGstElementUnsafe(unsafe.Pointer(obj))}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance returns the underlying C GstBaseSrc instance
|
||||||
|
func (g *GstBaseSrc) Instance() *C.GstBaseSrc {
|
||||||
|
return C.toGstBaseSrc(g.Unsafe())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormat sets the default format of the source. This will be the format used for sending
|
||||||
|
// SEGMENT events and for performing seeks.
|
||||||
|
//
|
||||||
|
// If a format of gst.FormatBytes is set, the element will be able to operate in pull mode if the
|
||||||
|
// IsSeekable returns TRUE.
|
||||||
|
//
|
||||||
|
// This function must only be called in when the element is paused.
|
||||||
|
func (g *GstBaseSrc) SetFormat(format gst.Format) {
|
||||||
|
C.gst_base_src_set_format(g.Instance(), C.GstFormat(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartComplete completes an asynchronous start operation. When the subclass overrides the start method,
|
||||||
|
// it should call StartComplete when the start operation completes either from the same thread or from an
|
||||||
|
// asynchronous helper thread.
|
||||||
|
func (g *GstBaseSrc) StartComplete(ret gst.FlowReturn) {
|
||||||
|
C.gst_base_src_start_complete(g.Instance(), C.GstFlowReturn(ret))
|
||||||
|
}
|
198
gst/base/gst_base_src_exports.go
Normal file
198
gst/base/gst_base_src_exports.go
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
//#include "gst.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/tinyzimmer/go-gst/gst"
|
||||||
|
)
|
||||||
|
|
||||||
|
//export goGstBaseSrcGetCaps
|
||||||
|
func goGstBaseSrcGetCaps(src *C.GstBaseSrc, filter *C.GstCaps) *C.GstCaps {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
GetCaps(*GstBaseSrc, *gst.Caps) *gst.Caps
|
||||||
|
})
|
||||||
|
res := caller.GetCaps(wrapGstBaseSrc(src), gst.FromGstCapsUnsafe(unsafe.Pointer(filter)))
|
||||||
|
return (*C.GstCaps)(unsafe.Pointer(res.Instance()))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcNegotiate
|
||||||
|
func goGstBaseSrcNegotiate(src *C.GstBaseSrc) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Negotiate(*GstBaseSrc) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.Negotiate(wrapGstBaseSrc(src)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcFixate
|
||||||
|
func goGstBaseSrcFixate(src *C.GstBaseSrc, caps *C.GstCaps) *C.GstCaps {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Fixate(*GstBaseSrc, *gst.Caps) *gst.Caps
|
||||||
|
})
|
||||||
|
res := caller.Fixate(wrapGstBaseSrc(src), gst.FromGstCapsUnsafe(unsafe.Pointer(caps)))
|
||||||
|
return (*C.GstCaps)(unsafe.Pointer(res.Instance()))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcSetCaps
|
||||||
|
func goGstBaseSrcSetCaps(src *C.GstBaseSrc, filter *C.GstCaps) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
SetCaps(*GstBaseSrc, *gst.Caps) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.SetCaps(wrapGstBaseSrc(src), gst.FromGstCapsUnsafe(unsafe.Pointer(filter))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcDecideAllocation
|
||||||
|
func goGstBaseSrcDecideAllocation(src *C.GstBaseSrc, query *C.GstQuery) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
DecideAllocation(*GstBaseSrc, *gst.Query) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.DecideAllocation(wrapGstBaseSrc(src), gst.FromGstQueryUnsafe(unsafe.Pointer(query))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcStart
|
||||||
|
func goGstBaseSrcStart(src *C.GstBaseSrc) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Start(*GstBaseSrc) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.Start(wrapGstBaseSrc(src)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcStop
|
||||||
|
func goGstBaseSrcStop(src *C.GstBaseSrc) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Stop(*GstBaseSrc) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.Stop(wrapGstBaseSrc(src)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcGetTimes
|
||||||
|
func goGstBaseSrcGetTimes(src *C.GstBaseSrc, buf *C.GstBuffer, start *C.GstClockTime, end *C.GstClockTime) {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration)
|
||||||
|
})
|
||||||
|
gostart, goend := caller.GetTimes(wrapGstBaseSrc(src), gst.FromGstBufferUnsafe(unsafe.Pointer(buf)))
|
||||||
|
*start = C.GstClockTime(gostart.Nanoseconds())
|
||||||
|
*end = C.GstClockTime(goend.Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcGetSize
|
||||||
|
func goGstBaseSrcGetSize(src *C.GstBaseSrc, size *C.guint64) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
GetSize(*GstBaseSrc) (bool, int64)
|
||||||
|
})
|
||||||
|
ok, gosize := caller.GetSize(wrapGstBaseSrc(src))
|
||||||
|
if !ok {
|
||||||
|
return gboolean(ok)
|
||||||
|
}
|
||||||
|
*size = C.guint64(gosize)
|
||||||
|
return gboolean(ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcIsSeekable
|
||||||
|
func goGstBaseSrcIsSeekable(src *C.GstBaseSrc) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
IsSeekable(*GstBaseSrc) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.IsSeekable(wrapGstBaseSrc(src)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcPrepareSeekSegment
|
||||||
|
func goGstBaseSrcPrepareSeekSegment(src *C.GstBaseSrc, seek *C.GstEvent, segment *C.GstSegment) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
PrepareSeekSegment(*GstBaseSrc, *gst.Event, *gst.Segment) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.PrepareSeekSegment(wrapGstBaseSrc(src), gst.FromGstEventUnsafe(unsafe.Pointer(seek)), gst.FromGstSegmentUnsafe(unsafe.Pointer(segment))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcDoSeek
|
||||||
|
func goGstBaseSrcDoSeek(src *C.GstBaseSrc, segment *C.GstSegment) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
DoSeek(*GstBaseSrc, *gst.Segment) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.DoSeek(wrapGstBaseSrc(src), gst.FromGstSegmentUnsafe(unsafe.Pointer(segment))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcUnlock
|
||||||
|
func goGstBaseSrcUnlock(src *C.GstBaseSrc) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Unlock(*GstBaseSrc) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.Unlock(wrapGstBaseSrc(src)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcUnlockStop
|
||||||
|
func goGstBaseSrcUnlockStop(src *C.GstBaseSrc) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
UnlockStop(*GstBaseSrc) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.UnlockStop(wrapGstBaseSrc(src)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcQuery
|
||||||
|
func goGstBaseSrcQuery(src *C.GstBaseSrc, query *C.GstQuery) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Query(*GstBaseSrc, *gst.Query) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.Query(wrapGstBaseSrc(src), gst.FromGstQueryUnsafe(unsafe.Pointer(query))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcEvent
|
||||||
|
func goGstBaseSrcEvent(src *C.GstBaseSrc, event *C.GstEvent) C.gboolean {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Event(*GstBaseSrc, *gst.Event) bool
|
||||||
|
})
|
||||||
|
return gboolean(caller.Event(wrapGstBaseSrc(src), gst.FromGstEventUnsafe(unsafe.Pointer(event))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcCreate
|
||||||
|
func goGstBaseSrcCreate(src *C.GstBaseSrc, offset C.guint64, size C.guint, buf **C.GstBuffer) C.GstFlowReturn {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Create(*GstBaseSrc, uint64, uint) (gst.FlowReturn, *gst.Buffer)
|
||||||
|
})
|
||||||
|
ret, gobuf := caller.Create(wrapGstBaseSrc(src), uint64(offset), uint(size))
|
||||||
|
if ret == gst.FlowOK {
|
||||||
|
C.memcpy(unsafe.Pointer(*buf), unsafe.Pointer(gobuf.Instance()), C.sizeof_GstBuffer)
|
||||||
|
}
|
||||||
|
return C.GstFlowReturn(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcAlloc
|
||||||
|
func goGstBaseSrcAlloc(src *C.GstBaseSrc, offset C.guint64, size C.guint, buf **C.GstBuffer) C.GstFlowReturn {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Alloc(*GstBaseSrc, uint64, uint) (gst.FlowReturn, *gst.Buffer)
|
||||||
|
})
|
||||||
|
ret, gobuf := caller.Alloc(wrapGstBaseSrc(src), uint64(offset), uint(size))
|
||||||
|
if ret == gst.FlowOK {
|
||||||
|
C.memcpy(unsafe.Pointer(*buf), unsafe.Pointer(gobuf.Instance()), C.sizeof_GstBuffer)
|
||||||
|
}
|
||||||
|
return C.GstFlowReturn(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGstBaseSrcFill
|
||||||
|
func goGstBaseSrcFill(src *C.GstBaseSrc, offset C.guint64, size C.guint, buf *C.GstBuffer) C.GstFlowReturn {
|
||||||
|
elem := gst.FromObjectUnsafePrivate(unsafe.Pointer(src))
|
||||||
|
caller := elem.(interface {
|
||||||
|
Fill(*GstBaseSrc, uint64, uint, *gst.Buffer) gst.FlowReturn
|
||||||
|
})
|
||||||
|
return C.GstFlowReturn(caller.Fill(wrapGstBaseSrc(src), uint64(offset), uint(size), gst.FromGstBufferUnsafe(unsafe.Pointer(buf))))
|
||||||
|
}
|
236
gst/base/gst_base_src_impl.go
Normal file
236
gst/base/gst_base_src_impl.go
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
|
||||||
|
extern GstCaps * goGstBaseSrcGetCaps (GstBaseSrc * src, GstCaps * caps);
|
||||||
|
extern gboolean goGstBaseSrcNegotiate (GstBaseSrc * src);
|
||||||
|
extern GstCaps * goGstBaseSrcFixate (GstBaseSrc * src, GstCaps * caps);
|
||||||
|
extern gboolean goGstBaseSrcSetCaps (GstBaseSrc * src, GstCaps * filter);
|
||||||
|
extern gboolean goGstBaseSrcDecideAllocation (GstBaseSrc * src, GstQuery * query);
|
||||||
|
extern gboolean goGstBaseSrcStart (GstBaseSrc * src);
|
||||||
|
extern gboolean goGstBaseSrcStop (GstBaseSrc * src);
|
||||||
|
extern void goGstBaseSrcGetTimes (GstBaseSrc * src, GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
|
||||||
|
extern gboolean goGstBaseSrcGetSize (GstBaseSrc * src, guint64 * size);
|
||||||
|
extern gboolean goGstBaseSrcIsSeekable (GstBaseSrc * src);
|
||||||
|
extern gboolean goGstBaseSrcPrepareSeekSegment (GstBaseSrc * src, GstEvent * seek, GstSegment * segment);
|
||||||
|
extern gboolean goGstBaseSrcDoSeek (GstBaseSrc * src, GstSegment * segment);
|
||||||
|
extern gboolean goGstBaseSrcUnlock (GstBaseSrc * src);
|
||||||
|
extern gboolean goGstBaseSrcUnlockStop (GstBaseSrc * src);
|
||||||
|
extern gboolean goGstBaseSrcQuery (GstBaseSrc * src, GstQuery * query);
|
||||||
|
extern gboolean goGstBaseSrcEvent (GstBaseSrc * src, GstEvent * event);
|
||||||
|
extern GstFlowReturn goGstBaseSrcCreate (GstBaseSrc * src, guint64 offset, guint size, GstBuffer ** buffer);
|
||||||
|
extern GstFlowReturn goGstBaseSrcAlloc (GstBaseSrc * src, guint64 offset, guint size, GstBuffer ** buffer);
|
||||||
|
extern GstFlowReturn goGstBaseSrcFill (GstBaseSrc * src, guint64 offset, guint size, GstBuffer * buffer);
|
||||||
|
|
||||||
|
|
||||||
|
void setGstBaseSrcGetCaps (GstBaseSrcClass * klass) { klass->get_caps = goGstBaseSrcGetCaps; }
|
||||||
|
void setGstBaseSrcNegotiate (GstBaseSrcClass * klass) { klass->negotiate = goGstBaseSrcNegotiate; }
|
||||||
|
void setGstBaseSrcFixate (GstBaseSrcClass * klass) { klass->fixate = goGstBaseSrcFixate; }
|
||||||
|
void setGstBaseSrcSetCaps (GstBaseSrcClass * klass) { klass->set_caps = goGstBaseSrcSetCaps; }
|
||||||
|
void setGstBaseSrcDecideAllocation (GstBaseSrcClass * klass) { klass->decide_allocation = goGstBaseSrcDecideAllocation; }
|
||||||
|
void setGstBaseSrcStart (GstBaseSrcClass * klass) { klass->start = goGstBaseSrcStart; }
|
||||||
|
void setGstBaseSrcStop (GstBaseSrcClass * klass) { klass->stop = goGstBaseSrcStop; }
|
||||||
|
void setGstBaseSrcGetTimes (GstBaseSrcClass * klass) { klass->get_times = goGstBaseSrcGetTimes; }
|
||||||
|
void setGstBaseSrcGetSize (GstBaseSrcClass * klass) { klass->get_size = goGstBaseSrcGetSize; }
|
||||||
|
void setGstBaseSrcIsSeekable (GstBaseSrcClass * klass) { klass->is_seekable = goGstBaseSrcIsSeekable; }
|
||||||
|
void setGstBaseSrcPrepareSeekSegment (GstBaseSrcClass * klass) { klass->prepare_seek_segment = goGstBaseSrcPrepareSeekSegment; }
|
||||||
|
void setGstBaseSrcDoSeek (GstBaseSrcClass * klass) { klass->do_seek = goGstBaseSrcDoSeek; }
|
||||||
|
void setGstBaseSrcUnlock (GstBaseSrcClass * klass) { klass->unlock = goGstBaseSrcUnlock; }
|
||||||
|
void setGstBaseSrcUnlockStop (GstBaseSrcClass * klass) { klass->unlock_stop = goGstBaseSrcUnlockStop; }
|
||||||
|
void setGstBaseSrcQuery (GstBaseSrcClass * klass) { klass->query = goGstBaseSrcQuery; }
|
||||||
|
void setGstBaseSrcEvent (GstBaseSrcClass * klass) { klass->event = goGstBaseSrcEvent; }
|
||||||
|
void setGstBaseSrcCreate (GstBaseSrcClass * klass) { klass->create = goGstBaseSrcCreate; }
|
||||||
|
void setGstBaseSrcAlloc (GstBaseSrcClass * klass) { klass->alloc = goGstBaseSrcAlloc; }
|
||||||
|
void setGstBaseSrcFill (GstBaseSrcClass * klass) { klass->fill = goGstBaseSrcFill; }
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
"github.com/tinyzimmer/go-gst/gst"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ExtendsBaseSrc is an Extendable for extending a GstBaseSrc
|
||||||
|
ExtendsBaseSrc gst.Extendable = &extendsBaseSrc{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GstBaseSrcImpl is the documented interface for an element extending a GstBaseSrc. It does not have to
|
||||||
|
// be implemented in it's entirety. Each of the methods it declares will be checked for their presence
|
||||||
|
// in the initializing object, and if the object declares an override it will replace the default
|
||||||
|
// implementation in the virtual methods.
|
||||||
|
type GstBaseSrcImpl interface {
|
||||||
|
// GetCaps retrieves the caps for this class.
|
||||||
|
GetCaps(*GstBaseSrc, *gst.Caps) *gst.Caps
|
||||||
|
// Negotiate decides on the caps for this source.
|
||||||
|
Negotiate(*GstBaseSrc) bool
|
||||||
|
// Fixate is called if, during negotiation, caps need fixating.
|
||||||
|
Fixate(*GstBaseSrc, *gst.Caps) *gst.Caps
|
||||||
|
// SetCaps is used to notify this class of new caps.
|
||||||
|
SetCaps(*GstBaseSrc, *gst.Caps) bool
|
||||||
|
// DecideAllocation sets up an allocation query.
|
||||||
|
DecideAllocation(*GstBaseSrc, *gst.Query) bool
|
||||||
|
// Start the source, ideal for opening resources.
|
||||||
|
Start(*GstBaseSrc) bool
|
||||||
|
// Stop the source, ideal for closing resources.
|
||||||
|
Stop(*GstBaseSrc) bool
|
||||||
|
// GetTimes should, given a buffer, return start and stop time when it should be pushed.
|
||||||
|
// The base class will sync on the clock using these times.
|
||||||
|
GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration)
|
||||||
|
// GetSize should get the total size of the resource in bytes.
|
||||||
|
GetSize(*GstBaseSrc) (bool, int64)
|
||||||
|
// IsSeekable should check if the resource is seekable.
|
||||||
|
IsSeekable(*GstBaseSrc) bool
|
||||||
|
// PrepareSeekSegment prepares the segment on which to perform DoSeek, converting to the
|
||||||
|
// current basesrc format.
|
||||||
|
PrepareSeekSegment(*GstBaseSrc, *gst.Event, *gst.Segment) bool
|
||||||
|
// DoSeek is used to notify subclasses of a seek.
|
||||||
|
DoSeek(*GstBaseSrc, *gst.Segment) bool
|
||||||
|
// Unlock should unlock any pending access to the resource. Subclasses should perform the unlock
|
||||||
|
// ASAP.
|
||||||
|
Unlock(*GstBaseSrc) bool
|
||||||
|
// UnlockStop should clear any pending unlock request, as we succeeded in unlocking.
|
||||||
|
UnlockStop(*GstBaseSrc) bool
|
||||||
|
// Query is used to notify subclasses of a query.
|
||||||
|
Query(*GstBaseSrc, *gst.Query) bool
|
||||||
|
// Event is used to notify subclasses of an event.
|
||||||
|
Event(*GstBaseSrc, *gst.Event) bool
|
||||||
|
// Create asks the subclass to create a buffer with offset and size. The default implementation
|
||||||
|
// will call alloc and fill.
|
||||||
|
Create(self *GstBaseSrc, offset uint64, size uint) (gst.FlowReturn, *gst.Buffer)
|
||||||
|
// Alloc asks the subclass to allocate an output buffer. The default implementation will use the negotiated
|
||||||
|
// allocator.
|
||||||
|
Alloc(self *GstBaseSrc, offset uint64, size uint) (gst.FlowReturn, *gst.Buffer)
|
||||||
|
// Fill asks the subclass to fill the buffer with data from offset and size.
|
||||||
|
Fill(self *GstBaseSrc, offset uint64, size uint, buffer *gst.Buffer) gst.FlowReturn
|
||||||
|
}
|
||||||
|
|
||||||
|
type extendsBaseSrc struct{}
|
||||||
|
|
||||||
|
func (e *extendsBaseSrc) Type() glib.Type { return glib.Type(C.gst_base_src_get_type()) }
|
||||||
|
func (e *extendsBaseSrc) ClassSize() int64 { return int64(C.sizeof_GstBaseSrcClass) }
|
||||||
|
func (e *extendsBaseSrc) InstanceSize() int64 { return int64(C.sizeof_GstBaseSrc) }
|
||||||
|
|
||||||
|
// InitClass iterates the methods provided by the element and overrides any provided
|
||||||
|
// in the virtual methods.
|
||||||
|
func (e *extendsBaseSrc) InitClass(klass unsafe.Pointer, elem gst.GoElement) {
|
||||||
|
class := C.toGstBaseSrcClass(klass)
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
GetCaps(*GstBaseSrc, *gst.Caps) *gst.Caps
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcGetCaps(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Negotiate(*GstBaseSrc) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcNegotiate(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Fixate(*GstBaseSrc, *gst.Caps) *gst.Caps
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcFixate(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
SetCaps(*GstBaseSrc, *gst.Caps) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcSetCaps(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
DecideAllocation(*GstBaseSrc, *gst.Query) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcDecideAllocation(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Start(*GstBaseSrc) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcStart(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Stop(*GstBaseSrc) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcStop(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
GetTimes(*GstBaseSrc, *gst.Buffer) (start, end time.Duration)
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcGetTimes(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
GetSize(*GstBaseSrc) (bool, int64)
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcGetSize(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
IsSeekable(*GstBaseSrc) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcIsSeekable(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
PrepareSeekSegment(*GstBaseSrc, *gst.Event, *gst.Segment) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcPrepareSeekSegment(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
DoSeek(*GstBaseSrc, *gst.Segment) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcDoSeek(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Unlock(*GstBaseSrc) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcUnlock(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
UnlockStop(*GstBaseSrc) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcUnlockStop(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Query(*GstBaseSrc, *gst.Query) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcQuery(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Event(*GstBaseSrc, *gst.Event) bool
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcEvent(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Create(self *GstBaseSrc, offset uint64, size uint) (gst.FlowReturn, *gst.Buffer)
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcCreate(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Alloc(self *GstBaseSrc, offset uint64, size uint) (gst.FlowReturn, *gst.Buffer)
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcAlloc(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := elem.(interface {
|
||||||
|
Fill(self *GstBaseSrc, offset uint64, size uint, buffer *gst.Buffer) gst.FlowReturn
|
||||||
|
}); ok {
|
||||||
|
C.setGstBaseSrcFill(class)
|
||||||
|
}
|
||||||
|
}
|
7
gst/base/pkg_config.go
Normal file
7
gst/base/pkg_config.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo pkg-config: gstreamer-1.0 gstreamer-base-1.0
|
||||||
|
#cgo CFLAGS: -Wno-deprecated-declarations -g -Wall
|
||||||
|
*/
|
||||||
|
import "C"
|
12
gst/base/util.go
Normal file
12
gst/base/util.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
//#include "gst.go.h"
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// gboolean converts a go bool to a C.gboolean.
|
||||||
|
func gboolean(b bool) C.gboolean {
|
||||||
|
if b {
|
||||||
|
return C.gboolean(1)
|
||||||
|
}
|
||||||
|
return C.gboolean(0)
|
||||||
|
}
|
@@ -111,3 +111,13 @@ func glistToStreamSlice(glist *C.GList) []*Stream {
|
|||||||
})
|
})
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func glistToPadTemplateSlice(glist *C.GList) []*PadTemplate {
|
||||||
|
l := glib.WrapList(uintptr(unsafe.Pointer(&glist)))
|
||||||
|
out := make([]*PadTemplate, 0)
|
||||||
|
l.FreeFull(func(item interface{}) {
|
||||||
|
tmpl := item.(*C.GstPadTemplate)
|
||||||
|
out = append(out, wrapPadTemplate(toGObject(unsafe.Pointer(tmpl))))
|
||||||
|
})
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
@@ -3,10 +3,13 @@ package gst
|
|||||||
// CGO exports have to be defined in a separate file from where they are used or else
|
// CGO exports have to be defined in a separate file from where they are used or else
|
||||||
// there will be double linkage issues.
|
// there will be double linkage issues.
|
||||||
|
|
||||||
// #include <gst/gst.h>
|
/*
|
||||||
|
#include <gst/gst.h>
|
||||||
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/gotk3/gotk3/glib"
|
"github.com/gotk3/gotk3/glib"
|
||||||
@@ -16,6 +19,7 @@ import (
|
|||||||
//export goElementCallAsync
|
//export goElementCallAsync
|
||||||
func goElementCallAsync(element *C.GstElement, userData C.gpointer) {
|
func goElementCallAsync(element *C.GstElement, userData C.gpointer) {
|
||||||
iface := gopointer.Restore(unsafe.Pointer(userData))
|
iface := gopointer.Restore(unsafe.Pointer(userData))
|
||||||
|
defer gopointer.Unref(unsafe.Pointer(userData))
|
||||||
f := iface.(func())
|
f := iface.(func())
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
@@ -221,3 +225,115 @@ func goClockCb(gclock *C.GstClock, clockTime C.GstClockTime, clockID C.GstClockI
|
|||||||
clock := wrapClock(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gclock))})
|
clock := wrapClock(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(gclock))})
|
||||||
return gboolean(cb(clock, ClockTime(clockTime)))
|
return gboolean(cb(clock, ClockTime(clockTime)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export goPluginInit
|
||||||
|
func goPluginInit(plugin *C.GstPlugin, userData C.gpointer) C.gboolean {
|
||||||
|
ptr := unsafe.Pointer(userData)
|
||||||
|
defer gopointer.Unref(ptr)
|
||||||
|
funcIface := gopointer.Restore(ptr)
|
||||||
|
cb, ok := funcIface.(PluginInitFunc)
|
||||||
|
if !ok {
|
||||||
|
return gboolean(false)
|
||||||
|
}
|
||||||
|
return gboolean(cb(wrapPlugin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(plugin))})))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goGlobalPluginInit
|
||||||
|
func goGlobalPluginInit(plugin *C.GstPlugin) C.gboolean {
|
||||||
|
return gboolean(globalPluginInit(wrapPlugin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(plugin))})))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goClassInit
|
||||||
|
func goClassInit(klass C.gpointer, klassData C.gpointer) {
|
||||||
|
registerMutex.Lock()
|
||||||
|
defer registerMutex.Unlock()
|
||||||
|
|
||||||
|
ptr := unsafe.Pointer(klassData)
|
||||||
|
iface := gopointer.Restore(ptr)
|
||||||
|
defer gopointer.Unref(ptr)
|
||||||
|
|
||||||
|
data := iface.(*classData)
|
||||||
|
registeredClasses[klass] = data.elem
|
||||||
|
|
||||||
|
data.ext.InitClass(unsafe.Pointer(klass), data.elem)
|
||||||
|
|
||||||
|
C.g_type_class_add_private(klass, C.gsize(unsafe.Sizeof(uintptr(0))))
|
||||||
|
data.elem.ClassInit(wrapElementClass(klass))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goInstanceInit
|
||||||
|
func goInstanceInit(obj *C.GTypeInstance, klass C.gpointer) {
|
||||||
|
registerMutex.Lock()
|
||||||
|
defer registerMutex.Unlock()
|
||||||
|
|
||||||
|
elem := registeredClasses[klass].New()
|
||||||
|
registeredClasses[klass] = elem
|
||||||
|
|
||||||
|
ptr := gopointer.Save(elem)
|
||||||
|
private := C.g_type_instance_get_private(obj, registeredTypes[reflect.TypeOf(registeredClasses[klass]).String()])
|
||||||
|
C.memcpy(unsafe.Pointer(private), unsafe.Pointer(&ptr), C.gulong(unsafe.Sizeof(uintptr(0))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goURIHdlrGetURIType
|
||||||
|
func goURIHdlrGetURIType(gtype C.GType) C.GstURIType {
|
||||||
|
return C.GstURIType(globalURIHdlr.GetURIType())
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goURIHdlrGetProtocols
|
||||||
|
func goURIHdlrGetProtocols(gtype C.GType) **C.gchar {
|
||||||
|
protocols := globalURIHdlr.GetProtocols()
|
||||||
|
size := C.size_t(unsafe.Sizeof((*C.gchar)(nil)))
|
||||||
|
length := C.size_t(len(protocols))
|
||||||
|
arr := (**C.gchar)(C.malloc(length * size))
|
||||||
|
view := (*[1 << 30]*C.gchar)(unsafe.Pointer(arr))[0:len(protocols):len(protocols)]
|
||||||
|
for i, proto := range protocols {
|
||||||
|
view[i] = (*C.gchar)(C.CString(proto))
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goURIHdlrGetURI
|
||||||
|
func goURIHdlrGetURI(hdlr *C.GstURIHandler) *C.gchar {
|
||||||
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(hdlr))
|
||||||
|
return (*C.gchar)(unsafe.Pointer(C.CString(iface.(URIHandler).GetURI())))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goURIHdlrSetURI
|
||||||
|
func goURIHdlrSetURI(hdlr *C.GstURIHandler, uri *C.gchar, gerr **C.GError) C.gboolean {
|
||||||
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(hdlr))
|
||||||
|
ok, err := iface.(URIHandler).SetURI(C.GoString(uri))
|
||||||
|
if err != nil {
|
||||||
|
C.g_set_error_literal(gerr, newQuarkFromString(string(DomainLibrary)), C.gint(LibraryErrorSettings), C.CString(err.Error()))
|
||||||
|
}
|
||||||
|
return gboolean(ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goObjectSetProperty
|
||||||
|
func goObjectSetProperty(obj *C.GObject, propID C.guint, val *C.GValue, param *C.GParamSpec) {
|
||||||
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(obj))
|
||||||
|
iface.SetProperty(wrapObject(toGObject(unsafe.Pointer(obj))), uint(propID-1), glib.ValueFromNative(unsafe.Pointer(val)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goObjectGetProperty
|
||||||
|
func goObjectGetProperty(obj *C.GObject, propID C.guint, value *C.GValue, param *C.GParamSpec) {
|
||||||
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(obj))
|
||||||
|
val := iface.GetProperty(wrapObject(toGObject(unsafe.Pointer(obj))), uint(propID-1))
|
||||||
|
if val == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
C.g_value_copy((*C.GValue)(unsafe.Pointer(val.GValue)), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goObjectConstructed
|
||||||
|
func goObjectConstructed(obj *C.GObject) {
|
||||||
|
iface := FromObjectUnsafePrivate(unsafe.Pointer(obj))
|
||||||
|
iface.Constructed(wrapObject(toGObject(unsafe.Pointer(obj))))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goObjectFinalize
|
||||||
|
func goObjectFinalize(obj *C.GObject, klass C.gpointer) {
|
||||||
|
registerMutex.Lock()
|
||||||
|
defer registerMutex.Unlock()
|
||||||
|
delete(registeredClasses, klass)
|
||||||
|
gopointer.Unref(privateFromObj(unsafe.Pointer(obj)))
|
||||||
|
}
|
||||||
|
@@ -5,6 +5,32 @@ import "C"
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
// Version represents information about the current GST version.
|
||||||
|
type Version int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// VersionMajor is the major version number of the GStreamer core.
|
||||||
|
VersionMajor Version = C.GST_VERSION_MAJOR
|
||||||
|
// VersionMinor is the minor version number of the GStreamer core.
|
||||||
|
VersionMinor Version = C.GST_VERSION_MINOR
|
||||||
|
)
|
||||||
|
|
||||||
|
// License represents a type of license used on a plugin.
|
||||||
|
type License string
|
||||||
|
|
||||||
|
// Types of licenses
|
||||||
|
const (
|
||||||
|
LicenseLGPL License = "LGPL"
|
||||||
|
LicenseGPL License = "GPL"
|
||||||
|
LicenseQPL License = "QPL"
|
||||||
|
LicenseGPLQPL License = "GPL/QPL"
|
||||||
|
LicenseMPL License = "MPL"
|
||||||
|
LicenseBSD License = "BSD"
|
||||||
|
LicenseMIT License = "MIT/X11"
|
||||||
|
LicenseProprietary License = "Proprietary"
|
||||||
|
LicenseUnknown License = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
// GFraction is a helper structure for building fractions for functions that require them.
|
// GFraction is a helper structure for building fractions for functions that require them.
|
||||||
type GFraction struct {
|
type GFraction struct {
|
||||||
num, denom int
|
num, denom int
|
||||||
@@ -382,20 +408,20 @@ type PadDirection int
|
|||||||
|
|
||||||
// Type casting of pad directions
|
// Type casting of pad directions
|
||||||
const (
|
const (
|
||||||
PadUnknown PadDirection = C.GST_PAD_UNKNOWN // (0) - the direction is unknown
|
PadDirectionUnknown PadDirection = C.GST_PAD_UNKNOWN // (0) - the direction is unknown
|
||||||
PadSource PadDirection = C.GST_PAD_SRC // (1) - the pad is a source pad
|
PadDirectionSource PadDirection = C.GST_PAD_SRC // (1) - the pad is a source pad
|
||||||
PadSink PadDirection = C.GST_PAD_SINK // (2) - the pad is a sink pad
|
PadDirectionSink PadDirection = C.GST_PAD_SINK // (2) - the pad is a sink pad
|
||||||
)
|
)
|
||||||
|
|
||||||
// String implements a Stringer on PadDirection.
|
// String implements a Stringer on PadDirection.
|
||||||
func (p PadDirection) String() string {
|
func (p PadDirection) String() string {
|
||||||
switch p {
|
switch p {
|
||||||
case PadUnknown:
|
case PadDirectionUnknown:
|
||||||
return "Unknown"
|
return "unknown"
|
||||||
case PadSource:
|
case PadDirectionSource:
|
||||||
return "Src"
|
return "src"
|
||||||
case PadSink:
|
case PadDirectionSink:
|
||||||
return "Sink"
|
return "sink"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -424,20 +450,20 @@ type PadPresence int
|
|||||||
|
|
||||||
// Type casting of pad presences
|
// Type casting of pad presences
|
||||||
const (
|
const (
|
||||||
PadAlways PadPresence = C.GST_PAD_ALWAYS // (0) - the pad is always available
|
PadPresenceAlways PadPresence = C.GST_PAD_ALWAYS // (0) - the pad is always available
|
||||||
PadSometimes PadPresence = C.GST_PAD_SOMETIMES // (1) - the pad will become available depending on the media stream
|
PadPresenceSometimes PadPresence = C.GST_PAD_SOMETIMES // (1) - the pad will become available depending on the media stream
|
||||||
PadRequest PadPresence = C.GST_PAD_REQUEST // (2) - the pad is only available on request with gst_element_request_pad.
|
PadPresenceRequest PadPresence = C.GST_PAD_REQUEST // (2) - the pad is only available on request with gst_element_request_pad.
|
||||||
)
|
)
|
||||||
|
|
||||||
// String implements a stringer on PadPresence.
|
// String implements a stringer on PadPresence.
|
||||||
func (p PadPresence) String() string {
|
func (p PadPresence) String() string {
|
||||||
switch p {
|
switch p {
|
||||||
case PadAlways:
|
case PadPresenceAlways:
|
||||||
return "Always"
|
return "always"
|
||||||
case PadSometimes:
|
case PadPresenceSometimes:
|
||||||
return "Sometimes"
|
return "sometimes"
|
||||||
case PadRequest:
|
case PadPresenceRequest:
|
||||||
return "Request"
|
return "request"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ type GError struct {
|
|||||||
structure *Structure
|
structure *Structure
|
||||||
|
|
||||||
// used for message constructors
|
// used for message constructors
|
||||||
code int
|
code ErrorCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is an alias to `Error()`. It's for clarity when this object
|
// Message is an alias to `Error()`. It's for clarity when this object
|
||||||
@@ -23,9 +23,11 @@ func (e *GError) DebugString() string { return e.debugStr }
|
|||||||
// Structure returns the structure of the error message which may contain additional metadata.
|
// Structure returns the structure of the error message which may contain additional metadata.
|
||||||
func (e *GError) Structure() *Structure { return e.structure }
|
func (e *GError) Structure() *Structure { return e.structure }
|
||||||
|
|
||||||
// NewGError wraps the given error inside a GError (to be used with message constructors). The code
|
// Code returns the error code of the error message.
|
||||||
// is optional and allows for adding additional "types" to the error.
|
func (e *GError) Code() ErrorCode { return e.code }
|
||||||
func NewGError(code int, err error) *GError {
|
|
||||||
|
// NewGError wraps the given error inside a GError (to be used with message constructors).
|
||||||
|
func NewGError(code ErrorCode, err error) *GError {
|
||||||
return &GError{
|
return &GError{
|
||||||
errMsg: err.Error(),
|
errMsg: err.Error(),
|
||||||
code: code,
|
code: code,
|
||||||
|
75
gst/g_object_class.go
Normal file
75
gst/g_object_class.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package gst
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
|
||||||
|
extern GstURIType goURIHdlrGetURIType (GType type);
|
||||||
|
extern const gchar * const * goURIHdlrGetProtocols (GType type);
|
||||||
|
extern gchar * goURIHdlrGetURI (GstURIHandler * handler);
|
||||||
|
extern gboolean goURIHdlrSetURI (GstURIHandler * handler,
|
||||||
|
const gchar * uri,
|
||||||
|
GError ** error);
|
||||||
|
|
||||||
|
void uriHandlerInit (gpointer iface, gpointer iface_data)
|
||||||
|
{
|
||||||
|
((GstURIHandlerInterface*)iface)->get_type = goURIHdlrGetURIType;
|
||||||
|
((GstURIHandlerInterface*)iface)->get_protocols = goURIHdlrGetProtocols;
|
||||||
|
((GstURIHandlerInterface*)iface)->get_uri = goURIHdlrGetURI;
|
||||||
|
((GstURIHandlerInterface*)iface)->set_uri = goURIHdlrSetURI;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ObjectClass is a loose binding around the glib GObjectClass.
|
||||||
|
// It forms the base of a GstElementClass.
|
||||||
|
type ObjectClass struct {
|
||||||
|
ptr *C.GObjectClass
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsafe is a convenience wrapper to return the unsafe.Pointer of the underlying C instance.
|
||||||
|
func (o *ObjectClass) Unsafe() unsafe.Pointer { return unsafe.Pointer(o.ptr) }
|
||||||
|
|
||||||
|
// Instance returns the underlying C GObjectClass pointer
|
||||||
|
func (o *ObjectClass) Instance() *C.GObjectClass { return o.ptr }
|
||||||
|
|
||||||
|
// InstallProperties will install the given ParameterSpecs to the object class.
|
||||||
|
// They will be IDed in the order they are provided.
|
||||||
|
func (o *ObjectClass) InstallProperties(params []*ParameterSpec) {
|
||||||
|
for idx, prop := range params {
|
||||||
|
C.g_object_class_install_property(
|
||||||
|
o.Instance(),
|
||||||
|
C.guint(idx+1),
|
||||||
|
prop.paramSpec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeInstance is a loose binding around the glib GTypeInstance. It exposes methods required
|
||||||
|
// to register the various capabilities of an element.
|
||||||
|
type TypeInstance struct {
|
||||||
|
gtype C.GType
|
||||||
|
gotype GoElement
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInterface will add an interface implementation for the type referenced by this object.
|
||||||
|
func (t *TypeInstance) AddInterface(iface glib.Type) {
|
||||||
|
ifaceInfo := C.GInterfaceInfo{
|
||||||
|
interface_data: nil,
|
||||||
|
interface_finalize: nil,
|
||||||
|
}
|
||||||
|
switch iface {
|
||||||
|
case InterfaceURIHandler:
|
||||||
|
globalURIHdlr = t.gotype.(URIHandler)
|
||||||
|
ifaceInfo.interface_init = C.GInterfaceInitFunc(C.uriHandlerInit)
|
||||||
|
}
|
||||||
|
C.g_type_add_interface_static(
|
||||||
|
(C.GType)(t.gtype),
|
||||||
|
(C.GType)(iface),
|
||||||
|
&ifaceInfo,
|
||||||
|
)
|
||||||
|
}
|
@@ -13,12 +13,61 @@ import (
|
|||||||
// ParameterSpec is a go representation of a C GParamSpec
|
// ParameterSpec is a go representation of a C GParamSpec
|
||||||
type ParameterSpec struct {
|
type ParameterSpec struct {
|
||||||
paramSpec *C.GParamSpec
|
paramSpec *C.GParamSpec
|
||||||
Name string
|
defaultValue *glib.Value
|
||||||
Blurb string
|
}
|
||||||
Flags ParameterFlags
|
|
||||||
ValueType glib.Type
|
// NewStringParameter returns a new ParameterSpec that will hold a string value.
|
||||||
OwnerType glib.Type
|
func NewStringParameter(name, nick, blurb string, defaultValue *string, flags ParameterFlags) *ParameterSpec {
|
||||||
DefaultValue *glib.Value
|
var cdefault *C.gchar
|
||||||
|
var paramDefault *glib.Value
|
||||||
|
if defaultValue != nil {
|
||||||
|
cdefault = C.CString(*defaultValue)
|
||||||
|
var err error
|
||||||
|
paramDefault, err = glib.ValueInit(glib.TYPE_STRING)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
paramDefault.SetString(*defaultValue)
|
||||||
|
}
|
||||||
|
paramSpec := C.g_param_spec_string(
|
||||||
|
(*C.gchar)(C.CString(name)),
|
||||||
|
(*C.gchar)(C.CString(nick)),
|
||||||
|
(*C.gchar)(C.CString(blurb)),
|
||||||
|
(*C.gchar)(cdefault),
|
||||||
|
C.GParamFlags(flags),
|
||||||
|
)
|
||||||
|
return &ParameterSpec{paramSpec: paramSpec, defaultValue: paramDefault}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of this parameter.
|
||||||
|
func (p *ParameterSpec) Name() string {
|
||||||
|
return C.GoString(C.g_param_spec_get_name(p.paramSpec))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blurb returns the blurb for this parameter.
|
||||||
|
func (p *ParameterSpec) Blurb() string {
|
||||||
|
return C.GoString(C.g_param_spec_get_blurb(p.paramSpec))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags returns the flags for this parameter.
|
||||||
|
func (p *ParameterSpec) Flags() ParameterFlags {
|
||||||
|
return ParameterFlags(p.paramSpec.flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueType returns the GType for the value inside this parameter.
|
||||||
|
func (p *ParameterSpec) ValueType() glib.Type {
|
||||||
|
return glib.Type(p.paramSpec.value_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OwnerType returns the Gtype for the owner of this parameter.
|
||||||
|
func (p *ParameterSpec) OwnerType() glib.Type {
|
||||||
|
return glib.Type(p.paramSpec.owner_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultValue returns the default value for the parameter if it was included when the object
|
||||||
|
// was instantiated. Otherwise it returns nil.
|
||||||
|
func (p *ParameterSpec) DefaultValue() *glib.Value {
|
||||||
|
return p.defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unref the underlying paramater spec.
|
// Unref the underlying paramater spec.
|
||||||
@@ -114,7 +163,10 @@ type FlagsValue struct {
|
|||||||
|
|
||||||
// GetDefaultFlags returns the default flags for this parameter spec.
|
// GetDefaultFlags returns the default flags for this parameter spec.
|
||||||
func (p *ParameterSpec) GetDefaultFlags() int {
|
func (p *ParameterSpec) GetDefaultFlags() int {
|
||||||
return int(C.g_value_get_flags((*C.GValue)(p.DefaultValue.Native())))
|
if p.DefaultValue() == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return int(C.g_value_get_flags((*C.GValue)(p.DefaultValue().Native())))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFlagValues returns the possible flags for this parameter.
|
// GetFlagValues returns the possible flags for this parameter.
|
||||||
@@ -135,7 +187,10 @@ func (p *ParameterSpec) GetFlagValues() []*FlagsValue {
|
|||||||
|
|
||||||
// GetCaps returns the caps in this parameter if it is of type GST_TYPE_CAPS.
|
// GetCaps returns the caps in this parameter if it is of type GST_TYPE_CAPS.
|
||||||
func (p *ParameterSpec) GetCaps() *Caps {
|
func (p *ParameterSpec) GetCaps() *Caps {
|
||||||
caps := C.gst_value_get_caps((*C.GValue)(unsafe.Pointer(p.DefaultValue.Native())))
|
if p.DefaultValue() == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
caps := C.gst_value_get_caps((*C.GValue)(unsafe.Pointer(p.DefaultValue().Native())))
|
||||||
if caps == nil {
|
if caps == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -152,6 +207,7 @@ func (p ParameterFlags) Has(b ParameterFlags) bool { return p&b != 0 }
|
|||||||
const (
|
const (
|
||||||
ParameterReadable ParameterFlags = C.G_PARAM_READABLE // the parameter is readable
|
ParameterReadable ParameterFlags = C.G_PARAM_READABLE // the parameter is readable
|
||||||
ParameterWritable = C.G_PARAM_WRITABLE // the parameter is writable
|
ParameterWritable = C.G_PARAM_WRITABLE // the parameter is writable
|
||||||
|
ParameterReadWrite = ParameterReadable | ParameterWritable
|
||||||
ParameterConstruct = C.G_PARAM_CONSTRUCT // the parameter will be set upon object construction
|
ParameterConstruct = C.G_PARAM_CONSTRUCT // the parameter will be set upon object construction
|
||||||
ParameterConstructOnly = C.G_PARAM_CONSTRUCT_ONLY // the parameter can only be set upon object construction
|
ParameterConstructOnly = C.G_PARAM_CONSTRUCT_ONLY // the parameter can only be set upon object construction
|
||||||
ParameterLaxValidation = C.G_PARAM_LAX_VALIDATION // upon parameter conversion (see g_param_value_convert()) strict validation is not required
|
ParameterLaxValidation = C.G_PARAM_LAX_VALIDATION // upon parameter conversion (see g_param_value_convert()) strict validation is not required
|
@@ -3,11 +3,15 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/base/gstbasesrc.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Type Castings
|
Type Castings
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
inline GType objectGType (GObject *obj) { return G_OBJECT_TYPE(obj); };
|
||||||
|
inline GObjectClass * toGObjectClass (void *p) { return (G_OBJECT_CLASS(p)); }
|
||||||
|
|
||||||
inline GstAllocator * toGstAllocator (void *p) { return (GST_ALLOCATOR_CAST(p)); }
|
inline GstAllocator * toGstAllocator (void *p) { return (GST_ALLOCATOR_CAST(p)); }
|
||||||
inline GstBin * toGstBin (void *p) { return (GST_BIN(p)); }
|
inline GstBin * toGstBin (void *p) { return (GST_BIN(p)); }
|
||||||
inline GstBufferList * toGstBufferList (void *p) { return (GST_BUFFER_LIST(p)); }
|
inline GstBufferList * toGstBufferList (void *p) { return (GST_BUFFER_LIST(p)); }
|
||||||
@@ -20,6 +24,7 @@ inline GstClock * toGstClock (void *p) { return (GST_CLO
|
|||||||
inline GstContext * toGstContext (void *p) { return (GST_CONTEXT_CAST(p)); }
|
inline GstContext * toGstContext (void *p) { return (GST_CONTEXT_CAST(p)); }
|
||||||
inline GstDevice * toGstDevice (void *p) { return (GST_DEVICE_CAST(p)); }
|
inline GstDevice * toGstDevice (void *p) { return (GST_DEVICE_CAST(p)); }
|
||||||
inline GstElementFactory * toGstElementFactory (void *p) { return (GST_ELEMENT_FACTORY(p)); }
|
inline GstElementFactory * toGstElementFactory (void *p) { return (GST_ELEMENT_FACTORY(p)); }
|
||||||
|
inline GstElementClass * toGstElementClass (void *p) { return (GST_ELEMENT_CLASS(p)); }
|
||||||
inline GstElement * toGstElement (void *p) { return (GST_ELEMENT(p)); }
|
inline GstElement * toGstElement (void *p) { return (GST_ELEMENT(p)); }
|
||||||
inline GstEvent * toGstEvent (void *p) { return (GST_EVENT(p)); }
|
inline GstEvent * toGstEvent (void *p) { return (GST_EVENT(p)); }
|
||||||
inline GstGhostPad * toGstGhostPad (void *p) { return (GST_GHOST_PAD(p)); }
|
inline GstGhostPad * toGstGhostPad (void *p) { return (GST_GHOST_PAD(p)); }
|
||||||
|
@@ -39,6 +39,12 @@ type Buffer struct {
|
|||||||
mapInfo *MapInfo
|
mapInfo *MapInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromGstBufferUnsafe wraps the given C GstBuffer in the go type. It is meant for internal usage
|
||||||
|
// and exported for visibility to other packages.
|
||||||
|
func FromGstBufferUnsafe(buf unsafe.Pointer) *Buffer {
|
||||||
|
return wrapBuffer((*C.GstBuffer)(buf))
|
||||||
|
}
|
||||||
|
|
||||||
// NewEmptyBuffer returns a new empty buffer.
|
// NewEmptyBuffer returns a new empty buffer.
|
||||||
func NewEmptyBuffer() *Buffer {
|
func NewEmptyBuffer() *Buffer {
|
||||||
return wrapBuffer(C.gst_buffer_new())
|
return wrapBuffer(C.gst_buffer_new())
|
||||||
|
@@ -21,6 +21,8 @@ import "C"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/gotk3/gotk3/glib"
|
"github.com/gotk3/gotk3/glib"
|
||||||
@@ -30,6 +32,9 @@ import (
|
|||||||
// Element is a Go wrapper around a GstElement.
|
// Element is a Go wrapper around a GstElement.
|
||||||
type Element struct{ *Object }
|
type Element struct{ *Object }
|
||||||
|
|
||||||
|
// ToElement returns an Element object for the given Object.
|
||||||
|
func ToElement(obj *Object) *Element { return &Element{Object: obj} }
|
||||||
|
|
||||||
// ElementLinkMany is a go implementation of `gst_element_link_many` to compensate for
|
// ElementLinkMany is a go implementation of `gst_element_link_many` to compensate for
|
||||||
// no variadic functions in cgo.
|
// no variadic functions in cgo.
|
||||||
func ElementLinkMany(elems ...*Element) error {
|
func ElementLinkMany(elems ...*Element) error {
|
||||||
@@ -45,24 +50,145 @@ func ElementLinkMany(elems ...*Element) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rank represents a level of importance when autoplugging elements.
|
||||||
|
type Rank uint
|
||||||
|
|
||||||
|
// For now just a single RankNone is provided
|
||||||
|
const (
|
||||||
|
RankNone Rank = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterElement creates a new elementfactory capable of instantiating objects of the given GoElement
|
||||||
|
// and adds the factory to the plugin. A higher rank means more importance when autoplugging.
|
||||||
|
func RegisterElement(plugin *Plugin, name string, rank Rank, elem GoElement, extends Extendable) bool {
|
||||||
|
return gobool(C.gst_element_register(
|
||||||
|
plugin.Instance(),
|
||||||
|
C.CString(name),
|
||||||
|
C.guint(rank),
|
||||||
|
gtypeForGoElement(name, elem, extends),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
// Instance returns the underlying GstElement instance.
|
// Instance returns the underlying GstElement instance.
|
||||||
func (e *Element) Instance() *C.GstElement { return C.toGstElement(e.Unsafe()) }
|
func (e *Element) Instance() *C.GstElement { return C.toGstElement(e.Unsafe()) }
|
||||||
|
|
||||||
// Link wraps gst_element_link and links this element to the given one.
|
// AbortState aborts the state change of the element. This function is used by elements that do asynchronous state changes
|
||||||
func (e *Element) Link(elem *Element) error {
|
// and find out something is wrong.
|
||||||
if ok := C.gst_element_link((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
|
func (e *Element) AbortState() { C.gst_element_abort_state(e.Instance()) }
|
||||||
return fmt.Errorf("Failed to link %s to %s", e.Name(), elem.Name())
|
|
||||||
|
// AddPad adds a pad (link point) to element. pad's parent will be set to element
|
||||||
|
//
|
||||||
|
// Pads are automatically activated when added in the PAUSED or PLAYING state.
|
||||||
|
//
|
||||||
|
// The pad and the element should be unlocked when calling this function.
|
||||||
|
//
|
||||||
|
// This function will emit the pad-added signal on the element.
|
||||||
|
func (e *Element) AddPad(pad *Pad) bool {
|
||||||
|
return gobool(C.gst_element_add_pad(e.Instance(), pad.Instance()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockSetState is like SetState except it will block until the transition
|
||||||
|
// is complete.
|
||||||
|
func (e *Element) BlockSetState(state State) error {
|
||||||
|
if err := e.SetState(state); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cState := C.GstState(state)
|
||||||
|
var curState C.GstState
|
||||||
|
C.gst_element_get_state(
|
||||||
|
(*C.GstElement)(e.Instance()),
|
||||||
|
(*C.GstState)(unsafe.Pointer(&curState)),
|
||||||
|
(*C.GstState)(unsafe.Pointer(&cState)),
|
||||||
|
C.GstClockTime(ClockTimeNone),
|
||||||
|
)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinkFiltered wraps gst_element_link_filtered and link this element to the given one
|
// CallAsync calls f from another thread. This is to be used for cases when a state change has to be performed from a streaming
|
||||||
// using the provided sink caps.
|
// thread, directly via SetState or indirectly e.g. via SEEK events.
|
||||||
func (e *Element) LinkFiltered(elem *Element, caps *Caps) error {
|
//
|
||||||
if ok := C.gst_element_link_filtered((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance()), (*C.GstCaps)(caps.Instance())); !gobool(ok) {
|
// Calling those functions directly from the streaming thread will cause deadlocks in many situations, as they might involve waiting
|
||||||
return fmt.Errorf("Failed to link %s to %s with provider caps", e.Name(), elem.Name())
|
// for the streaming thread to shut down from this very streaming thread.
|
||||||
|
func (e *Element) CallAsync(f func()) {
|
||||||
|
ptr := gopointer.Save(f)
|
||||||
|
C.gst_element_call_async(
|
||||||
|
e.Instance(),
|
||||||
|
C.GstElementCallAsyncFunc(C.cgoElementCallAsync),
|
||||||
|
(C.gpointer)(unsafe.Pointer(ptr)),
|
||||||
|
C.GDestroyNotify(C.cgoElementAsyncDestroyNotify),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
// 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.
|
||||||
|
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...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info is a convenience wrapper for posting an info message from inside an element. Only to be used from
|
||||||
|
// plugins.
|
||||||
|
func (e *Element) Info(domain Domain, text string) {
|
||||||
|
function, file, line, _ := runtime.Caller(1)
|
||||||
|
e.MessageFull(MessageInfo, domain, ErrorCode(0), "", text, path.Base(file), runtime.FuncForPC(function).Name(), line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning is a convenience wrapper for posting a warning message from inside an element. Only to be used from
|
||||||
|
// plugins.
|
||||||
|
func (e *Element) Warning(domain Domain, text string) {
|
||||||
|
function, file, line, _ := runtime.Caller(1)
|
||||||
|
e.MessageFull(MessageWarning, domain, ErrorCode(0), "", text, path.Base(file), runtime.FuncForPC(function).Name(), line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error is a convenience wrapper for posting an error message from inside an element. Only to be used from
|
||||||
|
// plugins.
|
||||||
|
func (e *Element) Error(domain Domain, code ErrorCode, text, debug string) {
|
||||||
|
function, file, line, _ := runtime.Caller(1)
|
||||||
|
e.MessageFull(MessageError, domain, code, text, debug, path.Base(file), runtime.FuncForPC(function).Name(), line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageFull will post an error, warning, or info message on the bus from inside an element. Only to be used
|
||||||
|
// from plugins.
|
||||||
|
func (e *Element) MessageFull(msgType MessageType, domain Domain, code ErrorCode, text, debug, file, function string, line int) {
|
||||||
|
var cTxt, cDbg unsafe.Pointer
|
||||||
|
if text != "" {
|
||||||
|
cTxt = unsafe.Pointer(C.CString(text))
|
||||||
|
}
|
||||||
|
if debug != "" {
|
||||||
|
cDbg = unsafe.Pointer(C.CString(debug))
|
||||||
|
}
|
||||||
|
C.gst_element_message_full(
|
||||||
|
e.Instance(),
|
||||||
|
C.GstMessageType(msgType),
|
||||||
|
newQuarkFromString(string(domain)),
|
||||||
|
C.gint(code),
|
||||||
|
(*C.gchar)(cTxt),
|
||||||
|
(*C.gchar)(cDbg),
|
||||||
|
C.CString(file),
|
||||||
|
C.CString(function),
|
||||||
|
C.gint(line),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBus returns the GstBus for retrieving messages from this element. This function returns
|
// GetBus returns the GstBus for retrieving messages from this element. This function returns
|
||||||
@@ -85,37 +211,6 @@ func (e *Element) GetClock() *Clock {
|
|||||||
return wrapClock(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(cClock))})
|
return wrapClock(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(cClock))})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetState returns the current state of this element.
|
|
||||||
func (e *Element) GetState() State {
|
|
||||||
return State(e.Instance().current_state)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetState sets the target state for this element.
|
|
||||||
func (e *Element) SetState(state State) error {
|
|
||||||
stateRet := C.gst_element_set_state((*C.GstElement)(e.Instance()), C.GstState(state))
|
|
||||||
if stateRet == C.GST_STATE_CHANGE_FAILURE {
|
|
||||||
return fmt.Errorf("Failed to change state to %s", state.String())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockSetState is like SetState except it will block until the transition
|
|
||||||
// is complete.
|
|
||||||
func (e *Element) BlockSetState(state State) error {
|
|
||||||
if err := e.SetState(state); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cState := C.GstState(state)
|
|
||||||
var curState C.GstState
|
|
||||||
C.gst_element_get_state(
|
|
||||||
(*C.GstElement)(e.Instance()),
|
|
||||||
(*C.GstState)(unsafe.Pointer(&curState)),
|
|
||||||
(*C.GstState)(unsafe.Pointer(&cState)),
|
|
||||||
C.GstClockTime(ClockTimeNone),
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFactory returns the factory that created this element. No refcounting is needed.
|
// GetFactory returns the factory that created this element. No refcounting is needed.
|
||||||
func (e *Element) GetFactory() *ElementFactory {
|
func (e *Element) GetFactory() *ElementFactory {
|
||||||
factory := C.gst_element_get_factory((*C.GstElement)(e.Instance()))
|
factory := C.gst_element_get_factory((*C.GstElement)(e.Instance()))
|
||||||
@@ -136,18 +231,6 @@ func (e *Element) GetPads() []*Pad {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStaticPad retrieves a pad from element by name. This version only retrieves
|
|
||||||
// already-existing (i.e. 'static') pads.
|
|
||||||
func (e *Element) GetStaticPad(name string) *Pad {
|
|
||||||
cname := C.CString(name)
|
|
||||||
defer C.free(unsafe.Pointer(cname))
|
|
||||||
pad := C.gst_element_get_static_pad(e.Instance(), (*C.gchar)(unsafe.Pointer(cname)))
|
|
||||||
if pad == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return wrapPad(toGObject(unsafe.Pointer(pad)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPadTemplates retrieves a list of the pad templates associated with this element.
|
// GetPadTemplates retrieves a list of the pad templates associated with this element.
|
||||||
// The list must not be modified by the calling code.
|
// The list must not be modified by the calling code.
|
||||||
func (e *Element) GetPadTemplates() []*PadTemplate {
|
func (e *Element) GetPadTemplates() []*PadTemplate {
|
||||||
@@ -164,6 +247,23 @@ func (e *Element) GetPadTemplates() []*PadTemplate {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetState returns the current state of this element.
|
||||||
|
func (e *Element) GetState() State {
|
||||||
|
return State(e.Instance().current_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStaticPad retrieves a pad from element by name. This version only retrieves
|
||||||
|
// already-existing (i.e. 'static') pads.
|
||||||
|
func (e *Element) GetStaticPad(name string) *Pad {
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
pad := C.gst_element_get_static_pad(e.Instance(), (*C.gchar)(unsafe.Pointer(cname)))
|
||||||
|
if pad == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapPad(toGObject(unsafe.Pointer(pad)))
|
||||||
|
}
|
||||||
|
|
||||||
// Has returns true if this element has the given flags.
|
// Has returns true if this element has the given flags.
|
||||||
func (e *Element) Has(flags ElementFlags) bool {
|
func (e *Element) Has(flags ElementFlags) bool {
|
||||||
return gobool(C.gstObjectFlagIsSet(C.toGstObject(e.Unsafe()), C.GstElementFlags(flags)))
|
return gobool(C.gstObjectFlagIsSet(C.toGstObject(e.Unsafe()), C.GstElementFlags(flags)))
|
||||||
@@ -174,35 +274,22 @@ func (e *Element) IsURIHandler() bool {
|
|||||||
return gobool(C.gstElementIsURIHandler(e.Instance()))
|
return gobool(C.gstElementIsURIHandler(e.Instance()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// URIHandler returns a URIHandler interface if implemented by this element. Otherwise it
|
// Link wraps gst_element_link and links this element to the given one.
|
||||||
// returns nil. Currently this only supports elements built through this package, however,
|
func (e *Element) Link(elem *Element) error {
|
||||||
// inner application elements could still use the interface as a reference implementation.
|
if ok := C.gst_element_link((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
|
||||||
func (e *Element) URIHandler() URIHandler {
|
return fmt.Errorf("Failed to link %s to %s", e.Name(), elem.Name())
|
||||||
if C.toGstURIHandler(e.Unsafe()) == nil {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return &gstURIHandler{ptr: e.Instance()}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOCSetter returns a TOCSetter interface if implemented by this element. Otherwise it
|
// LinkFiltered wraps gst_element_link_filtered and link this element to the given one
|
||||||
// returns nil. Currently this only supports elements built through this package, however,
|
// using the provided sink caps.
|
||||||
// inner application elements could still use the interface as a reference implementation.
|
func (e *Element) LinkFiltered(elem *Element, caps *Caps) error {
|
||||||
func (e *Element) TOCSetter() TOCSetter {
|
if ok := C.gst_element_link_filtered((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance()), (*C.GstCaps)(caps.Instance())); !gobool(ok) {
|
||||||
if C.toTocSetter(e.Instance()) == nil {
|
return fmt.Errorf("Failed to link %s to %s with provider caps", e.Name(), elem.Name())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &gstTOCSetter{ptr: e.Instance()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TagSetter returns a TagSetter interface if implemented by this element. Otherwise it returns nil.
|
|
||||||
// This currently only supports elements built through this package's bindings, however, inner application
|
|
||||||
// elements can still implement the interface themselves if they want.
|
|
||||||
func (e *Element) TagSetter() TagSetter {
|
|
||||||
if C.toTagSetter(e.Instance()) == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &gstTagSetter{ptr: e.Instance()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query performs a query on the given element.
|
// Query performs a query on the given element.
|
||||||
//
|
//
|
||||||
@@ -253,32 +340,13 @@ func (e *Element) SendEvent(ev *Event) bool {
|
|||||||
return gobool(C.gst_element_send_event(e.Instance(), ev.Instance()))
|
return gobool(C.gst_element_send_event(e.Instance(), ev.Instance()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect connects to the given signal on this element, and applies f as the callback. The callback must
|
// SetState sets the target state for this element.
|
||||||
// match the signature of the expected callback from the documentation. However, instead of specifying C types
|
func (e *Element) SetState(state State) error {
|
||||||
// for arguments specify the go-gst equivalent (e.g. *gst.Element for almost all GstElement derivitives).
|
stateRet := C.gst_element_set_state((*C.GstElement)(e.Instance()), C.GstState(state))
|
||||||
//
|
if stateRet == C.GST_STATE_CHANGE_FAILURE {
|
||||||
// This and the Emit() method may get moved down the hierarchy to the Object level at some point, since
|
return fmt.Errorf("Failed to change state to %s", state.String())
|
||||||
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.
|
|
||||||
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 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
|
||||||
@@ -287,32 +355,32 @@ func (e *Element) SyncStateWithParent() bool {
|
|||||||
return gobool(C.gst_element_sync_state_with_parent(e.Instance()))
|
return gobool(C.gst_element_sync_state_with_parent(e.Instance()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbortState aborts the state change of the element. This function is used by elements that do asynchronous state changes
|
// TOCSetter returns a TOCSetter interface if implemented by this element. Otherwise it
|
||||||
// and find out something is wrong.
|
// returns nil. Currently this only supports elements built through this package, however,
|
||||||
func (e *Element) AbortState() { C.gst_element_abort_state(e.Instance()) }
|
// inner application elements could still use the interface as a reference implementation.
|
||||||
|
func (e *Element) TOCSetter() TOCSetter {
|
||||||
// AddPad adds a pad (link point) to element. pad's parent will be set to element
|
if C.toTocSetter(e.Instance()) == nil {
|
||||||
//
|
return nil
|
||||||
// Pads are automatically activated when added in the PAUSED or PLAYING state.
|
}
|
||||||
//
|
return &gstTOCSetter{ptr: e.Instance()}
|
||||||
// The pad and the element should be unlocked when calling this function.
|
|
||||||
//
|
|
||||||
// This function will emit the pad-added signal on the element.
|
|
||||||
func (e *Element) AddPad(pad *Pad) bool {
|
|
||||||
return gobool(C.gst_element_add_pad(e.Instance(), pad.Instance()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallAsync calls f from another thread. This is to be used for cases when a state change has to be performed from a streaming
|
// TagSetter returns a TagSetter interface if implemented by this element. Otherwise it returns nil.
|
||||||
// thread, directly via SetState or indirectly e.g. via SEEK events.
|
// This currently only supports elements built through this package's bindings, however, inner application
|
||||||
//
|
// elements can still implement the interface themselves if they want.
|
||||||
// Calling those functions directly from the streaming thread will cause deadlocks in many situations, as they might involve waiting
|
func (e *Element) TagSetter() TagSetter {
|
||||||
// for the streaming thread to shut down from this very streaming thread.
|
if C.toTagSetter(e.Instance()) == nil {
|
||||||
func (e *Element) CallAsync(f func()) {
|
return nil
|
||||||
ptr := gopointer.Save(f)
|
}
|
||||||
C.gst_element_call_async(
|
return &gstTagSetter{ptr: e.Instance()}
|
||||||
e.Instance(),
|
}
|
||||||
C.GstElementCallAsyncFunc(C.cgoElementCallAsync),
|
|
||||||
(C.gpointer)(unsafe.Pointer(ptr)),
|
// URIHandler returns a URIHandler interface if implemented by this element. Otherwise it
|
||||||
C.GDestroyNotify(C.cgoElementAsyncDestroyNotify),
|
// returns nil. Currently this only supports elements built through this package, however,
|
||||||
)
|
// inner application elements could still use the interface as a reference implementation.
|
||||||
|
func (e *Element) URIHandler() URIHandler {
|
||||||
|
if C.toGstURIHandler(e.Unsafe()) == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &gstURIHandler{ptr: e.Instance()}
|
||||||
}
|
}
|
||||||
|
102
gst/gst_element_class.go
Normal file
102
gst/gst_element_class.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package gst
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// ElementClass represents the subclass of an element provided by a plugin.
|
||||||
|
type ElementClass struct{ *ObjectClass }
|
||||||
|
|
||||||
|
// Instance returns the underlying GstElementClass instance.
|
||||||
|
func (e *ElementClass) Instance() *C.GstElementClass {
|
||||||
|
return C.toGstElementClass(e.Unsafe())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMetadata sets key with the given value in the metadata of the class.
|
||||||
|
func (e *ElementClass) AddMetadata(key, value string) {
|
||||||
|
C.gst_element_class_add_static_metadata(
|
||||||
|
e.Instance(),
|
||||||
|
(*C.gchar)(C.CString(key)),
|
||||||
|
(*C.gchar)(C.CString(value)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPadTemplate adds a padtemplate to an element class. This is mainly used in the
|
||||||
|
// ClassInit functions of ObjectSubclasses. If a pad template with the same name as an
|
||||||
|
// already existing one is added the old one is replaced by the new one.
|
||||||
|
//
|
||||||
|
// templ's reference count will be incremented, and any floating reference will be removed
|
||||||
|
func (e *ElementClass) AddPadTemplate(templ *PadTemplate) {
|
||||||
|
C.gst_element_class_add_pad_template(
|
||||||
|
e.Instance(),
|
||||||
|
templ.Instance(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddStaticPadTemplate adds a pad template to an element class based on the pad template templ. The template
|
||||||
|
// is first converted to a static pad template.
|
||||||
|
//
|
||||||
|
// This is mainly used in the ClassInit functions of element implementations. If a pad template with the
|
||||||
|
// same name already exists, the old one is replaced by the new one.
|
||||||
|
func (e *ElementClass) AddStaticPadTemplate(templ *PadTemplate) {
|
||||||
|
staticTmpl := C.GstStaticPadTemplate{
|
||||||
|
name_template: templ.Instance().name_template,
|
||||||
|
direction: templ.Instance().direction,
|
||||||
|
presence: templ.Instance().presence,
|
||||||
|
static_caps: C.GstStaticCaps{
|
||||||
|
caps: templ.Caps().Instance(),
|
||||||
|
string: C.CString(templ.Name()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
C.gst_element_class_add_static_pad_template(
|
||||||
|
e.Instance(),
|
||||||
|
&staticTmpl,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadata retrieves the metadata associated with key in the class.
|
||||||
|
func (e *ElementClass) GetMetadata(key string) string {
|
||||||
|
ckey := C.CString(key)
|
||||||
|
defer C.free(unsafe.Pointer(ckey))
|
||||||
|
return C.GoString(C.gst_element_class_get_metadata(e.Instance(), (*C.gchar)(ckey)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPadTemplate retrieves the padtemplate with the given name. No unrefing is necessary.
|
||||||
|
// If no pad template exists with the given name, nil is returned.
|
||||||
|
func (e *ElementClass) GetPadTemplate(name string) *PadTemplate {
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
tmpl := C.gst_element_class_get_pad_template(e.Instance(), (*C.gchar)(cname))
|
||||||
|
if tmpl == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapPadTemplate(toGObject(unsafe.Pointer(tmpl)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllPadTemplates retrieves a slice of all the pad templates associated with this class.
|
||||||
|
// The list must not be modified.
|
||||||
|
func (e *ElementClass) GetAllPadTemplates() []*PadTemplate {
|
||||||
|
glist := C.gst_element_class_get_pad_template_list(e.Instance())
|
||||||
|
return glistToPadTemplateSlice(glist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMetadata sets the detailed information for this class.
|
||||||
|
//
|
||||||
|
// `longname` - The english long name of the element. E.g "File Sink"
|
||||||
|
//
|
||||||
|
// `classification` - A string describing the type of element, as an unordered list separated with slashes ('/'). E.g: "Sink/File"
|
||||||
|
//
|
||||||
|
// `description` - Sentence describing the purpose of the element. E.g: "Write stream to a file"
|
||||||
|
//
|
||||||
|
// `author` - Name and contact details of the author(s). Use \n to separate multiple author metadata. E.g: "Joe Bloggs <joe.blogs at foo.com>"
|
||||||
|
func (e *ElementClass) SetMetadata(longname, classification, description, author string) {
|
||||||
|
C.gst_element_class_set_static_metadata(
|
||||||
|
e.Instance(),
|
||||||
|
(*C.gchar)(C.CString(longname)),
|
||||||
|
(*C.gchar)(C.CString(classification)),
|
||||||
|
(*C.gchar)(C.CString(description)),
|
||||||
|
(*C.gchar)(C.CString(author)),
|
||||||
|
)
|
||||||
|
}
|
84
gst/gst_errors.go
Normal file
84
gst/gst_errors.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package gst
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// Domain represents the different types of error domains.
|
||||||
|
type Domain string
|
||||||
|
|
||||||
|
// ErrorDomain castings
|
||||||
|
const (
|
||||||
|
DomainCore Domain = "CORE"
|
||||||
|
DomainLibrary Domain = "LIBRARY"
|
||||||
|
DomainResource Domain = "RESOURCE"
|
||||||
|
DomainStream Domain = "STREAM"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrorCode represents GstGError codes.
|
||||||
|
type ErrorCode int
|
||||||
|
|
||||||
|
// Type castings of CoreErrors
|
||||||
|
const (
|
||||||
|
CoreErrorFailed ErrorCode = C.GST_CORE_ERROR_FAILED // (1) – a general error which doesn't fit in any other category. Make sure you add a custom message to the error call.
|
||||||
|
CoreErrorTooLazy ErrorCode = C.GST_CORE_ERROR_TOO_LAZY // (2) – do not use this except as a placeholder for deciding where to go while developing code.
|
||||||
|
CoreErrorNotImplemented ErrorCode = C.GST_CORE_ERROR_NOT_IMPLEMENTED // (3) – use this when you do not want to implement this functionality yet.
|
||||||
|
CoreErrorStateChange ErrorCode = C.GST_CORE_ERROR_STATE_CHANGE // (4) – used for state change errors.
|
||||||
|
CoreErrorPad ErrorCode = C.GST_CORE_ERROR_PAD // (5) – used for pad-related errors.
|
||||||
|
CoreErrorThread ErrorCode = C.GST_CORE_ERROR_THREAD // (6) – used for thread-related errors.
|
||||||
|
CoreErrorNegotiation ErrorCode = C.GST_CORE_ERROR_NEGOTIATION // (7) – used for negotiation-related errors.
|
||||||
|
CoreErrorEvent ErrorCode = C.GST_CORE_ERROR_EVENT // (8) – used for event-related errors.
|
||||||
|
CoreErrorSeek ErrorCode = C.GST_CORE_ERROR_SEEK // (9) – used for seek-related errors.
|
||||||
|
CoreErrorCaps ErrorCode = C.GST_CORE_ERROR_CAPS // (10) – used for caps-related errors.
|
||||||
|
CoreErrorTag ErrorCode = C.GST_CORE_ERROR_TAG // (11) – used for negotiation-related errors.
|
||||||
|
CoreErrorMissingPlugin ErrorCode = C.GST_CORE_ERROR_MISSING_PLUGIN // (12) – used if a plugin is missing.
|
||||||
|
CoreErrorClock ErrorCode = C.GST_CORE_ERROR_CLOCK // (13) – used for clock related errors.
|
||||||
|
CoreErrorDisabled ErrorCode = C.GST_CORE_ERROR_DISABLED // (14) – used if functionality has been disabled at compile time.
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type castings for LibraryErrors
|
||||||
|
const (
|
||||||
|
LibraryErrorFailed ErrorCode = C.GST_LIBRARY_ERROR_FAILED // (1) – a general error which doesn't fit in any other category. Make sure you add a custom message to the error call.
|
||||||
|
LibraryErrorTooLazy ErrorCode = C.GST_LIBRARY_ERROR_TOO_LAZY // (2) – do not use this except as a placeholder for deciding where to go while developing code.
|
||||||
|
LibraryErrorInit ErrorCode = C.GST_LIBRARY_ERROR_INIT // (3) – used when the library could not be opened.
|
||||||
|
LibraryErrorShutdown ErrorCode = C.GST_LIBRARY_ERROR_SHUTDOWN // (4) – used when the library could not be closed.
|
||||||
|
LibraryErrorSettings ErrorCode = C.GST_LIBRARY_ERROR_SETTINGS // (5) – used when the library doesn't accept settings.
|
||||||
|
LibraryErrorEncode ErrorCode = C.GST_LIBRARY_ERROR_ENCODE // (6) – used when the library generated an encoding error.
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type castings for ResourceErrors
|
||||||
|
const (
|
||||||
|
ResourceErrorFailed ErrorCode = C.GST_RESOURCE_ERROR_FAILED // (1) – a general error which doesn't fit in any other category. Make sure you add a custom message to the error call.
|
||||||
|
ResourceErrorTooLazy ErrorCode = C.GST_RESOURCE_ERROR_TOO_LAZY // (2) – do not use this except as a placeholder for deciding where to go while developing code.
|
||||||
|
ResourceErrorNotFound ErrorCode = C.GST_RESOURCE_ERROR_NOT_FOUND // (3) – used when the resource could not be found.
|
||||||
|
ResourceErrorBusy ErrorCode = C.GST_RESOURCE_ERROR_BUSY // (4) – used when resource is busy.
|
||||||
|
ResourceErrorOpenRead ErrorCode = C.GST_RESOURCE_ERROR_OPEN_READ // (5) – used when resource fails to open for reading.
|
||||||
|
ResourceErrorOpenWrite ErrorCode = C.GST_RESOURCE_ERROR_OPEN_WRITE // (6) – used when resource fails to open for writing.
|
||||||
|
ResourceErrorOpenReadWrite ErrorCode = C.GST_RESOURCE_ERROR_OPEN_READ_WRITE // (7) – used when resource cannot be opened for both reading and writing, or either (but unspecified which).
|
||||||
|
ResourceErrorClose ErrorCode = C.GST_RESOURCE_ERROR_CLOSE // (8) – used when the resource can't be closed.
|
||||||
|
ResourceErrorRead ErrorCode = C.GST_RESOURCE_ERROR_READ // (9) – used when the resource can't be read from.
|
||||||
|
ResourceErrorWrite ErrorCode = C.GST_RESOURCE_ERROR_WRITE // (10) – used when the resource can't be written to.
|
||||||
|
ResourceErrorSeek ErrorCode = C.GST_RESOURCE_ERROR_SEEK // (11) – used when a seek on the resource fails.
|
||||||
|
ResourceErrorSync ErrorCode = C.GST_RESOURCE_ERROR_SYNC // (12) – used when a synchronize on the resource fails.
|
||||||
|
ResourceErrorSettings ErrorCode = C.GST_RESOURCE_ERROR_SETTINGS // (13) – used when settings can't be manipulated on.
|
||||||
|
ResourceErrorNoSpaceLeft ErrorCode = C.GST_RESOURCE_ERROR_NO_SPACE_LEFT // (14) – used when the resource has no space left.
|
||||||
|
ResourceErrorNotAuthorized ErrorCode = C.GST_RESOURCE_ERROR_NOT_AUTHORIZED // (15) – used when the resource can't be opened due to missing authorization. (Since: 1.2.4)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type castings for StreamErrors
|
||||||
|
const (
|
||||||
|
StreamErrorFailed ErrorCode = C.GST_STREAM_ERROR_FAILED // (1) – a general error which doesn't fit in any other category. Make sure you add a custom message to the error call.
|
||||||
|
StreamErrorTooLazy ErrorCode = C.GST_STREAM_ERROR_TOO_LAZY // (2) – do not use this except as a placeholder for deciding where to go while developing code.
|
||||||
|
StreamErrorNotImplemented ErrorCode = C.GST_STREAM_ERROR_NOT_IMPLEMENTED // (3) – use this when you do not want to implement this functionality yet.
|
||||||
|
StreamErrorTypeNotFound ErrorCode = C.GST_STREAM_ERROR_TYPE_NOT_FOUND // (4) – used when the element doesn't know the stream's type.
|
||||||
|
StreamErrorWrongType ErrorCode = C.GST_STREAM_ERROR_WRONG_TYPE // (5) – used when the element doesn't handle this type of stream.
|
||||||
|
StreamErrorCodecNotFound ErrorCode = C.GST_STREAM_ERROR_CODEC_NOT_FOUND // (6) – used when there's no codec to handle the stream's type.
|
||||||
|
StreamErrorDecode ErrorCode = C.GST_STREAM_ERROR_DECODE // (7) – used when decoding fails.
|
||||||
|
StreamErrorEncode ErrorCode = C.GST_STREAM_ERROR_ENCODE // (8) – used when encoding fails.
|
||||||
|
StreamErrorDemux ErrorCode = C.GST_STREAM_ERROR_DEMUX // (9) – used when demuxing fails.
|
||||||
|
StreamErrorMux ErrorCode = C.GST_STREAM_ERROR_MUX // (10) – used when muxing fails.
|
||||||
|
StreamErrorFormat ErrorCode = C.GST_STREAM_ERROR_FORMAT // (11) – used when the stream is of the wrong format (for example, wrong caps).
|
||||||
|
StreamErrorDecrypt ErrorCode = C.GST_STREAM_ERROR_DECRYPT // (12) – used when the stream is encrypted and can't be decrypted because this is not supported by the element.
|
||||||
|
StreamErrorDecryptNoKey ErrorCode = C.GST_STREAM_ERROR_DECRYPT_NOKEY // (13) – used when the stream is encrypted and can't be decrypted because no suitable key is available.
|
||||||
|
)
|
@@ -15,6 +15,10 @@ type Event struct {
|
|||||||
ptr *C.GstEvent
|
ptr *C.GstEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromGstEventUnsafe wraps the pointer to the given C GstEvent with the go type.
|
||||||
|
// This is meant for internal usage and is exported for visibility to other packages.
|
||||||
|
func FromGstEventUnsafe(ev unsafe.Pointer) *Event { return wrapEvent((*C.GstEvent)(ev)) }
|
||||||
|
|
||||||
// Instance returns the underlying GstEvent instance.
|
// Instance returns the underlying GstEvent instance.
|
||||||
func (e *Event) Instance() *C.GstEvent { return C.toGstEvent(unsafe.Pointer(e.ptr)) }
|
func (e *Event) Instance() *C.GstEvent { return C.toGstEvent(unsafe.Pointer(e.ptr)) }
|
||||||
|
|
||||||
|
@@ -79,12 +79,7 @@ func (o *Object) ListProperties() []*ParameterSpec {
|
|||||||
C.g_param_spec_sink(prop) // steal the ref on the property
|
C.g_param_spec_sink(prop) // steal the ref on the property
|
||||||
out = append(out, &ParameterSpec{
|
out = append(out, &ParameterSpec{
|
||||||
paramSpec: prop,
|
paramSpec: prop,
|
||||||
Name: C.GoString(C.g_param_spec_get_name(prop)),
|
defaultValue: glib.ValueFromNative(unsafe.Pointer(&gval)),
|
||||||
Blurb: C.GoString(C.g_param_spec_get_blurb(prop)),
|
|
||||||
Flags: flags,
|
|
||||||
ValueType: glib.Type(prop.value_type),
|
|
||||||
OwnerType: glib.Type(prop.owner_type),
|
|
||||||
DefaultValue: glib.ValueFromNative(unsafe.Pointer(&gval)),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
@@ -1,11 +1,160 @@
|
|||||||
package gst
|
package gst
|
||||||
|
|
||||||
// #include "gst.go.h"
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
|
||||||
|
extern gboolean goPluginInit (GstPlugin * plugin, gpointer user_data);
|
||||||
|
extern gboolean goGlobalPluginInit (GstPlugin * plugin);
|
||||||
|
|
||||||
|
gboolean cgoPluginInit (GstPlugin * plugin, gpointer user_data)
|
||||||
|
{
|
||||||
|
return goPluginInit(plugin, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean cgoGlobalPluginInit(GstPlugin * plugin)
|
||||||
|
{
|
||||||
|
return goGlobalPluginInit(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
GstPluginDesc * exportPluginMeta (gint major, gint minor, gchar * name, gchar * description, GstPluginInitFunc init, gchar * version, gchar * license, gchar * source, gchar * package, gchar * origin, gchar * release_datetime)
|
||||||
|
{
|
||||||
|
GstPluginDesc * desc = malloc ( sizeof(GstPluginDesc) );
|
||||||
|
|
||||||
|
desc->major_version = major;
|
||||||
|
desc->minor_version = minor;
|
||||||
|
desc->name = name;
|
||||||
|
desc->description = description;
|
||||||
|
desc->plugin_init = init;
|
||||||
|
desc->version = version;
|
||||||
|
desc->license = license;
|
||||||
|
desc->source = source;
|
||||||
|
desc->package = package;
|
||||||
|
desc->origin = origin;
|
||||||
|
desc->release_datetime = release_datetime;
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
gopointer "github.com/mattn/go-pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PluginMetadata represents the information to include when registering a new plugin
|
||||||
|
// with gstreamer.
|
||||||
|
type PluginMetadata struct {
|
||||||
|
// The major version number of the GStreamer core that the plugin was compiled for, you can just use VersionMajor here
|
||||||
|
MajorVersion Version
|
||||||
|
// The minor version number of the GStreamer core that the plugin was compiled for, you can just use VersionMinor here
|
||||||
|
MinorVersion Version
|
||||||
|
// A unique name of the plugin (ideally prefixed with an application- or library-specific namespace prefix in order to
|
||||||
|
// avoid name conflicts in case a similar plugin with the same name ever gets added to GStreamer)
|
||||||
|
Name string
|
||||||
|
// A description of the plugin
|
||||||
|
Description string
|
||||||
|
// The function to call when initiliazing the plugin
|
||||||
|
Init PluginInitFunc
|
||||||
|
// The version of the plugin
|
||||||
|
Version string
|
||||||
|
// The license for the plugin, must match one of the license constants in this package
|
||||||
|
License License
|
||||||
|
// The source module the plugin belongs to
|
||||||
|
Source string
|
||||||
|
// The shipped package the plugin belongs to
|
||||||
|
Package string
|
||||||
|
// The URL to the provider of the plugin
|
||||||
|
Origin string
|
||||||
|
// The date of release in ISO 8601 format.
|
||||||
|
// See https://gstreamer.freedesktop.org/documentation/gstreamer/gstplugin.html?gi-language=c#GstPluginDesc for more details.
|
||||||
|
ReleaseDate string
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalPluginInit PluginInitFunc
|
||||||
|
|
||||||
|
// Export will export the PluginMetadata to an unsafe pointer to a GstPluginDesc.
|
||||||
|
func (p *PluginMetadata) Export() unsafe.Pointer {
|
||||||
|
globalPluginInit = p.Init
|
||||||
|
desc := C.exportPluginMeta(
|
||||||
|
C.gint(p.MajorVersion),
|
||||||
|
C.gint(p.MinorVersion),
|
||||||
|
(*C.gchar)(C.CString(p.Name)),
|
||||||
|
(*C.gchar)(C.CString(p.Description)),
|
||||||
|
(C.GstPluginInitFunc(C.cgoGlobalPluginInit)),
|
||||||
|
(*C.gchar)(C.CString(p.Version)),
|
||||||
|
(*C.gchar)(C.CString(string(p.License))),
|
||||||
|
(*C.gchar)(C.CString(p.Source)),
|
||||||
|
(*C.gchar)(C.CString(p.Package)),
|
||||||
|
(*C.gchar)(C.CString(p.Origin)),
|
||||||
|
(*C.gchar)(C.CString(p.ReleaseDate)),
|
||||||
|
)
|
||||||
|
return unsafe.Pointer(desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginInitFunc is a function called by the plugin loader at startup. This function should register
|
||||||
|
// all the features of the plugin. The function should return true if the plugin is initialized successfully.
|
||||||
|
type PluginInitFunc func(*Plugin) bool
|
||||||
|
|
||||||
// Plugin is a go representation of a GstPlugin.
|
// Plugin is a go representation of a GstPlugin.
|
||||||
type Plugin struct{ *Object }
|
type Plugin struct{ *Object }
|
||||||
|
|
||||||
|
// RegisterPlugin will register a static plugin, i.e. a plugin which is private to an application
|
||||||
|
// or library and contained within the application or library (as opposed to being shipped as a
|
||||||
|
// separate module file).
|
||||||
|
func RegisterPlugin(desc *PluginMetadata, initFunc PluginInitFunc) bool {
|
||||||
|
cName := C.CString(desc.Name)
|
||||||
|
cDesc := C.CString(desc.Description)
|
||||||
|
cVers := C.CString(desc.Version)
|
||||||
|
cLics := C.CString(string(desc.License))
|
||||||
|
cSrc := C.CString(desc.Source)
|
||||||
|
cPkg := C.CString(desc.Package)
|
||||||
|
cOrg := C.CString(desc.Origin)
|
||||||
|
defer func() {
|
||||||
|
for _, ptr := range []*C.char{cName, cDesc, cVers, cLics, cSrc, cPkg, cOrg} {
|
||||||
|
C.free(unsafe.Pointer(ptr))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fPtr := gopointer.Save(initFunc)
|
||||||
|
return gobool(C.gst_plugin_register_static_full(
|
||||||
|
C.gint(desc.MajorVersion), C.gint(desc.MinorVersion),
|
||||||
|
(*C.gchar)(cName), (*C.gchar)(cDesc),
|
||||||
|
C.GstPluginInitFullFunc(C.cgoPluginInit),
|
||||||
|
(*C.gchar)(cVers), (*C.gchar)(cLics),
|
||||||
|
(*C.gchar)(cSrc), (*C.gchar)(cPkg),
|
||||||
|
(*C.gchar)(cOrg), (C.gpointer)(unsafe.Pointer(fPtr)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPluginByName loads the named plugin and places a ref count on it. The function
|
||||||
|
// returns nil if the plugin could not be loaded.
|
||||||
|
func LoadPluginByName(name string) *Plugin {
|
||||||
|
cstr := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
plugin := C.gst_plugin_load_by_name((*C.gchar)(unsafe.Pointer(cstr)))
|
||||||
|
if plugin == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapPlugin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(plugin))})
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPluginFile loads the given plugin and refs it. If an error is returned Plugin will be nil.
|
||||||
|
func LoadPluginFile(fpath string) (*Plugin, error) {
|
||||||
|
cstr := C.CString(fpath)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
var gerr *C.GError
|
||||||
|
plugin := C.gst_plugin_load_file((*C.gchar)(unsafe.Pointer(cstr)), (**C.GError)(&gerr))
|
||||||
|
if gerr != nil {
|
||||||
|
defer C.g_free((C.gpointer)(gerr))
|
||||||
|
return nil, errors.New(C.GoString(gerr.message))
|
||||||
|
}
|
||||||
|
return wrapPlugin(&glib.Object{GObject: glib.ToGObject(unsafe.Pointer(plugin))}), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Instance returns the underlying GstPlugin instance.
|
// Instance returns the underlying GstPlugin instance.
|
||||||
func (p *Plugin) Instance() *C.GstPlugin { return C.toGstPlugin(p.Unsafe()) }
|
func (p *Plugin) Instance() *C.GstPlugin { return C.toGstPlugin(p.Unsafe()) }
|
||||||
|
|
||||||
@@ -37,12 +186,12 @@ func (p *Plugin) Version() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// License returns the license for this plugin.
|
// License returns the license for this plugin.
|
||||||
func (p *Plugin) License() string {
|
func (p *Plugin) License() License {
|
||||||
ret := C.gst_plugin_get_license((*C.GstPlugin)(p.Instance()))
|
ret := C.gst_plugin_get_license((*C.GstPlugin)(p.Instance()))
|
||||||
if ret == nil {
|
if ret == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return C.GoString(ret)
|
return License(C.GoString(ret))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source returns the source module for this plugin.
|
// Source returns the source module for this plugin.
|
||||||
|
@@ -14,6 +14,10 @@ type Query struct {
|
|||||||
ptr *C.GstQuery
|
ptr *C.GstQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromGstQueryUnsafe wraps the pointer to the given C GstQuery with the go type.
|
||||||
|
// This is meant for internal usage and is exported for visibility to other packages.
|
||||||
|
func FromGstQueryUnsafe(query unsafe.Pointer) *Query { return wrapQuery((*C.GstQuery)(query)) }
|
||||||
|
|
||||||
// NewAcceptCapsQuery constructs a new query object for querying if caps are accepted.
|
// NewAcceptCapsQuery constructs a new query object for querying if caps are accepted.
|
||||||
func NewAcceptCapsQuery(caps *Caps) *Query {
|
func NewAcceptCapsQuery(caps *Caps) *Query {
|
||||||
return wrapQuery(C.gst_query_new_accept_caps(caps.Instance()))
|
return wrapQuery(C.gst_query_new_accept_caps(caps.Instance()))
|
||||||
|
@@ -2,6 +2,7 @@ package gst
|
|||||||
|
|
||||||
// #include "gst.go.h"
|
// #include "gst.go.h"
|
||||||
import "C"
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
// Segment is a go wrapper around a GstSegment.
|
// Segment is a go wrapper around a GstSegment.
|
||||||
// See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstsegment.html?gi-language=c#GstSegment
|
// See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstsegment.html?gi-language=c#GstSegment
|
||||||
@@ -9,6 +10,12 @@ type Segment struct {
|
|||||||
ptr *C.GstSegment
|
ptr *C.GstSegment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromGstSegmentUnsafe wraps the given C GstSegment in the go type. It is meant for internal usage
|
||||||
|
// and exported for visibilty to other packages.
|
||||||
|
func FromGstSegmentUnsafe(segment unsafe.Pointer) *Segment {
|
||||||
|
return wrapSegment((*C.GstSegment)(segment))
|
||||||
|
}
|
||||||
|
|
||||||
// NewSegment allocates and initializes a new Segment.
|
// NewSegment allocates and initializes a new Segment.
|
||||||
func NewSegment() *Segment {
|
func NewSegment() *Segment {
|
||||||
return wrapSegment(C.gst_segment_new())
|
return wrapSegment(C.gst_segment_new())
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package gst
|
package gst
|
||||||
|
|
||||||
// #include "gst.go.h"
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -10,7 +12,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// InterfaceURIHandler represents the GstURIHandler interface GType. Use this when querying bins
|
// InterfaceURIHandler represents the GstURIHandler interface GType. Use this when querying bins
|
||||||
// for elements that implement a URIHandler.
|
// for elements that implement a URIHandler, or when signaling that a GoElement provides this
|
||||||
|
// interface.
|
||||||
var InterfaceURIHandler = glib.Type(C.GST_TYPE_URI_HANDLER)
|
var InterfaceURIHandler = glib.Type(C.GST_TYPE_URI_HANDLER)
|
||||||
|
|
||||||
// URIHandler represents an interface that elements can implement to provide URI handling
|
// URIHandler represents an interface that elements can implement to provide URI handling
|
||||||
@@ -20,13 +23,13 @@ type URIHandler interface {
|
|||||||
GetURI() string
|
GetURI() string
|
||||||
// GetURIType returns the type of URI this element can handle.
|
// GetURIType returns the type of URI this element can handle.
|
||||||
GetURIType() URIType
|
GetURIType() URIType
|
||||||
// GetURIProtocols returns the protocols this element can handle.
|
// GetProtocols returns the protocols this element can handle.
|
||||||
GetURIProtocols() []string
|
GetProtocols() []string
|
||||||
// SetURI tries to set the URI of the given handler.
|
// SetURI tries to set the URI of the given handler.
|
||||||
SetURI(string) (bool, error)
|
SetURI(string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gstURIHandler implements a URIHandler that is backed by an Element from the C runtime.
|
// gstURIHandler implements a URIHandler that is backed by an Element from the C API.
|
||||||
type gstURIHandler struct {
|
type gstURIHandler struct {
|
||||||
ptr *C.GstElement
|
ptr *C.GstElement
|
||||||
}
|
}
|
||||||
@@ -48,8 +51,8 @@ func (g *gstURIHandler) GetURIType() URIType {
|
|||||||
return URIType(ty)
|
return URIType(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetURIProtocols returns the protocols this element can handle.
|
// GetProtocols returns the protocols this element can handle.
|
||||||
func (g *gstURIHandler) GetURIProtocols() []string {
|
func (g *gstURIHandler) GetProtocols() []string {
|
||||||
protocols := C.gst_uri_handler_get_protocols((*C.GstURIHandler)(g.Instance()))
|
protocols := C.gst_uri_handler_get_protocols((*C.GstURIHandler)(g.Instance()))
|
||||||
if protocols == nil {
|
if protocols == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@@ -209,6 +209,10 @@ func wrapAllocationParams(obj *C.GstAllocationParams) *AllocationParams {
|
|||||||
return &AllocationParams{ptr: obj}
|
return &AllocationParams{ptr: obj}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wrapElementClass(klass C.gpointer) *ElementClass {
|
||||||
|
return &ElementClass{&ObjectClass{ptr: C.toGObjectClass(unsafe.Pointer(klass))}}
|
||||||
|
}
|
||||||
|
|
||||||
// Clock wrappers
|
// Clock wrappers
|
||||||
|
|
||||||
func clockTimeToDuration(n ClockTime) time.Duration {
|
func clockTimeToDuration(n ClockTime) time.Duration {
|
||||||
|
158
gst/interfaces.go
Normal file
158
gst/interfaces.go
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
package gst
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "gst.go.h"
|
||||||
|
|
||||||
|
extern void goClassInit (gpointer g_class, gpointer class_data);
|
||||||
|
extern void goInstanceInit (GTypeInstance * instance, gpointer g_class);
|
||||||
|
|
||||||
|
extern void goObjectSetProperty (GObject * object, guint property_id, const GValue * value, GParamSpec *pspec);
|
||||||
|
extern void goObjectGetProperty (GObject * object, guint property_id, GValue * value, GParamSpec * pspec);
|
||||||
|
extern void goObjectConstructed (GObject * object);
|
||||||
|
extern void goObjectFinalize (GObject * object, gpointer klass);
|
||||||
|
|
||||||
|
void objectFinalize (GObject * object)
|
||||||
|
{
|
||||||
|
GObjectClass *parent = g_type_class_peek_parent((G_OBJECT_GET_CLASS(object)));
|
||||||
|
goObjectFinalize(object, G_OBJECT_GET_CLASS(object));
|
||||||
|
parent->finalize(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void objectConstructed (GObject * object)
|
||||||
|
{
|
||||||
|
GObjectClass *parent = g_type_class_peek_parent((G_OBJECT_GET_CLASS(object)));
|
||||||
|
goObjectConstructed(object);
|
||||||
|
parent->constructed(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgoClassInit (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
((GObjectClass *)g_class)->set_property = goObjectSetProperty;
|
||||||
|
((GObjectClass *)g_class)->get_property = goObjectGetProperty;
|
||||||
|
((GObjectClass *)g_class)->constructed = objectConstructed;
|
||||||
|
((GObjectClass *)g_class)->finalize = objectFinalize;
|
||||||
|
|
||||||
|
goClassInit(g_class, class_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgoInstanceInit (GTypeInstance * instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
goInstanceInit(instance, g_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
gopointer "github.com/mattn/go-pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extendable is an interface implemented by extendable classes. It provides
|
||||||
|
// the methods necessary to setup the vmethods on the object it represents.
|
||||||
|
type Extendable interface {
|
||||||
|
Type() glib.Type
|
||||||
|
ClassSize() int64
|
||||||
|
InstanceSize() int64
|
||||||
|
InitClass(unsafe.Pointer, GoElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
type extendElement struct{}
|
||||||
|
|
||||||
|
func (e *extendElement) Type() glib.Type { return glib.Type(C.gst_element_get_type()) }
|
||||||
|
func (e *extendElement) ClassSize() int64 { return int64(C.sizeof_GstElementClass) }
|
||||||
|
func (e *extendElement) InstanceSize() int64 { return int64(C.sizeof_GstElement) }
|
||||||
|
func (e *extendElement) InitClass(klass unsafe.Pointer, elem GoElement) {}
|
||||||
|
|
||||||
|
// ExtendsElement signifies a GoElement that extends a GstElement.
|
||||||
|
var ExtendsElement Extendable = &extendElement{}
|
||||||
|
|
||||||
|
// GoElement is an interface to be implemented by GStreamer elements built using the
|
||||||
|
// go bindings. The various methods are called throughout the lifecycle of the plugin.
|
||||||
|
type GoElement interface {
|
||||||
|
GoObjectSubclass
|
||||||
|
GoObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// privateFromObj returns the actual value of the address we stored in the object's private data.
|
||||||
|
func privateFromObj(obj unsafe.Pointer) unsafe.Pointer {
|
||||||
|
private := C.g_type_instance_get_private((*C.GTypeInstance)(obj), C.objectGType((*C.GObject)(obj)))
|
||||||
|
privAddr := (*unsafe.Pointer)(unsafe.Pointer(private))
|
||||||
|
return *privAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromObjectUnsafePrivate will return the GoElement addressed in the private data of the given GObject.
|
||||||
|
func FromObjectUnsafePrivate(obj unsafe.Pointer) GoElement {
|
||||||
|
ptr := gopointer.Restore(privateFromObj(obj))
|
||||||
|
return ptr.(GoElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoObjectSubclass is an interface that abstracts on the GObjectClass. It should be implemented
|
||||||
|
// by plugins using the go bindings.
|
||||||
|
type GoObjectSubclass interface {
|
||||||
|
// New should return a new instantiated GoElement ready to be used.
|
||||||
|
New() GoElement
|
||||||
|
// TypeInit is called after the GType is registered and right before ClassInit. It is when the
|
||||||
|
// element should add any interfaces it plans to implement.
|
||||||
|
TypeInit(*TypeInstance)
|
||||||
|
// ClassInit is called on the element after registering it with GStreamer. This is when the element
|
||||||
|
// should install any properties and pad templates it has.
|
||||||
|
ClassInit(*ElementClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoObject is an interface that abstracts on the GObject. It should be implemented by plugins using
|
||||||
|
// the gobindings.
|
||||||
|
type GoObject interface {
|
||||||
|
// SetProperty should set the value of the property with the given id. ID is the index+1 of the parameter
|
||||||
|
// in the order it was registered.
|
||||||
|
SetProperty(obj *Object, id uint, value *glib.Value)
|
||||||
|
// GetProperty should retrieve the value of the property with the given id. ID is the index+1 of the parameter
|
||||||
|
// in the order it was registered.
|
||||||
|
GetProperty(obj *Object, id uint) *glib.Value
|
||||||
|
// Constructed is called when the Object has finished setting up.
|
||||||
|
Constructed(*Object)
|
||||||
|
}
|
||||||
|
|
||||||
|
type classData struct {
|
||||||
|
elem GoElement
|
||||||
|
ext Extendable
|
||||||
|
}
|
||||||
|
|
||||||
|
func gtypeForGoElement(name string, elem GoElement, extendable Extendable) C.GType {
|
||||||
|
registerMutex.Lock()
|
||||||
|
defer registerMutex.Unlock()
|
||||||
|
// fmt.Printf("Checking registration of %v\n", reflect.TypeOf(elem).String())
|
||||||
|
if registered, ok := registeredTypes[reflect.TypeOf(elem).String()]; ok {
|
||||||
|
return registered
|
||||||
|
}
|
||||||
|
classData := &classData{
|
||||||
|
elem: elem,
|
||||||
|
ext: extendable,
|
||||||
|
}
|
||||||
|
ptr := gopointer.Save(classData)
|
||||||
|
typeInfo := C.GTypeInfo{
|
||||||
|
class_size: C.gushort(extendable.ClassSize()),
|
||||||
|
base_init: nil,
|
||||||
|
base_finalize: nil,
|
||||||
|
class_init: C.GClassInitFunc(C.cgoClassInit),
|
||||||
|
class_finalize: nil,
|
||||||
|
class_data: (C.gconstpointer)(ptr),
|
||||||
|
instance_size: C.gushort(extendable.InstanceSize()),
|
||||||
|
n_preallocs: 0,
|
||||||
|
instance_init: C.GInstanceInitFunc(C.cgoInstanceInit),
|
||||||
|
value_table: nil,
|
||||||
|
}
|
||||||
|
gtype := C.g_type_register_static(
|
||||||
|
C.GType(extendable.Type()),
|
||||||
|
(*C.gchar)(C.CString(name)),
|
||||||
|
&typeInfo,
|
||||||
|
C.GTypeFlags(0),
|
||||||
|
)
|
||||||
|
elem.TypeInit(&TypeInstance{gtype: gtype, gotype: elem})
|
||||||
|
// fmt.Printf("Registering %v to type %v\n", reflect.TypeOf(elem).String(), gtype)
|
||||||
|
registeredTypes[reflect.TypeOf(elem).String()] = gtype
|
||||||
|
return gtype
|
||||||
|
}
|
11
gst/register.go
Normal file
11
gst/register.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package gst
|
||||||
|
|
||||||
|
// #include "gst.go.h"
|
||||||
|
import "C"
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
var registerMutex sync.RWMutex
|
||||||
|
|
||||||
|
var registeredTypes = make(map[string]C.GType)
|
||||||
|
var registeredClasses = make(map[C.gpointer]GoElement)
|
||||||
|
var globalURIHdlr URIHandler
|
Reference in New Issue
Block a user