mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-05 07:56:51 +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/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/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/gstappsrc.h>
|
||||
|
||||
inline GstAppSink * toGstAppSink (void *p) { return (GST_APP_SINK(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
|
||||
}
|
||||
|
||||
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
|
||||
// there will be double linkage issues.
|
||||
|
||||
// #include <gst/gst.h>
|
||||
/*
|
||||
#include <gst/gst.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/gotk3/gotk3/glib"
|
||||
@@ -16,6 +19,7 @@ import (
|
||||
//export goElementCallAsync
|
||||
func goElementCallAsync(element *C.GstElement, userData C.gpointer) {
|
||||
iface := gopointer.Restore(unsafe.Pointer(userData))
|
||||
defer gopointer.Unref(unsafe.Pointer(userData))
|
||||
f := iface.(func())
|
||||
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))})
|
||||
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"
|
||||
|
||||
// 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.
|
||||
type GFraction struct {
|
||||
num, denom int
|
||||
@@ -382,20 +408,20 @@ type PadDirection int
|
||||
|
||||
// Type casting of pad directions
|
||||
const (
|
||||
PadUnknown PadDirection = C.GST_PAD_UNKNOWN // (0) - the direction is unknown
|
||||
PadSource 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
|
||||
PadDirectionUnknown PadDirection = C.GST_PAD_UNKNOWN // (0) - the direction is unknown
|
||||
PadDirectionSource PadDirection = C.GST_PAD_SRC // (1) - the pad is a source pad
|
||||
PadDirectionSink PadDirection = C.GST_PAD_SINK // (2) - the pad is a sink pad
|
||||
)
|
||||
|
||||
// String implements a Stringer on PadDirection.
|
||||
func (p PadDirection) String() string {
|
||||
switch p {
|
||||
case PadUnknown:
|
||||
return "Unknown"
|
||||
case PadSource:
|
||||
return "Src"
|
||||
case PadSink:
|
||||
return "Sink"
|
||||
case PadDirectionUnknown:
|
||||
return "unknown"
|
||||
case PadDirectionSource:
|
||||
return "src"
|
||||
case PadDirectionSink:
|
||||
return "sink"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -424,20 +450,20 @@ type PadPresence int
|
||||
|
||||
// Type casting of pad presences
|
||||
const (
|
||||
PadAlways 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
|
||||
PadRequest PadPresence = C.GST_PAD_REQUEST // (2) - the pad is only available on request with gst_element_request_pad.
|
||||
PadPresenceAlways PadPresence = C.GST_PAD_ALWAYS // (0) - the pad is always available
|
||||
PadPresenceSometimes PadPresence = C.GST_PAD_SOMETIMES // (1) - the pad will become available depending on the media stream
|
||||
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.
|
||||
func (p PadPresence) String() string {
|
||||
switch p {
|
||||
case PadAlways:
|
||||
return "Always"
|
||||
case PadSometimes:
|
||||
return "Sometimes"
|
||||
case PadRequest:
|
||||
return "Request"
|
||||
case PadPresenceAlways:
|
||||
return "always"
|
||||
case PadPresenceSometimes:
|
||||
return "sometimes"
|
||||
case PadPresenceRequest:
|
||||
return "request"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ type GError struct {
|
||||
structure *Structure
|
||||
|
||||
// used for message constructors
|
||||
code int
|
||||
code ErrorCode
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (e *GError) Structure() *Structure { return e.structure }
|
||||
|
||||
// NewGError wraps the given error inside a GError (to be used with message constructors). The code
|
||||
// is optional and allows for adding additional "types" to the error.
|
||||
func NewGError(code int, err error) *GError {
|
||||
// Code returns the error code of the error message.
|
||||
func (e *GError) Code() ErrorCode { return e.code }
|
||||
|
||||
// NewGError wraps the given error inside a GError (to be used with message constructors).
|
||||
func NewGError(code ErrorCode, err error) *GError {
|
||||
return &GError{
|
||||
errMsg: err.Error(),
|
||||
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
|
||||
type ParameterSpec struct {
|
||||
paramSpec *C.GParamSpec
|
||||
Name string
|
||||
Blurb string
|
||||
Flags ParameterFlags
|
||||
ValueType glib.Type
|
||||
OwnerType glib.Type
|
||||
DefaultValue *glib.Value
|
||||
defaultValue *glib.Value
|
||||
}
|
||||
|
||||
// NewStringParameter returns a new ParameterSpec that will hold a string value.
|
||||
func NewStringParameter(name, nick, blurb string, defaultValue *string, flags ParameterFlags) *ParameterSpec {
|
||||
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.
|
||||
@@ -114,7 +163,10 @@ type FlagsValue struct {
|
||||
|
||||
// GetDefaultFlags returns the default flags for this parameter spec.
|
||||
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.
|
||||
@@ -135,7 +187,10 @@ func (p *ParameterSpec) GetFlagValues() []*FlagsValue {
|
||||
|
||||
// GetCaps returns the caps in this parameter if it is of type GST_TYPE_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 {
|
||||
return nil
|
||||
}
|
||||
@@ -152,6 +207,7 @@ func (p ParameterFlags) Has(b ParameterFlags) bool { return p&b != 0 }
|
||||
const (
|
||||
ParameterReadable ParameterFlags = C.G_PARAM_READABLE // the parameter is readable
|
||||
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
|
||||
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
|
@@ -3,11 +3,15 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesrc.h>
|
||||
|
||||
/*
|
||||
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 GstBin * toGstBin (void *p) { return (GST_BIN(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 GstDevice * toGstDevice (void *p) { return (GST_DEVICE_CAST(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 GstEvent * toGstEvent (void *p) { return (GST_EVENT(p)); }
|
||||
inline GstGhostPad * toGstGhostPad (void *p) { return (GST_GHOST_PAD(p)); }
|
||||
|
@@ -39,6 +39,12 @@ type Buffer struct {
|
||||
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.
|
||||
func NewEmptyBuffer() *Buffer {
|
||||
return wrapBuffer(C.gst_buffer_new())
|
||||
|
@@ -21,6 +21,8 @@ import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/gotk3/gotk3/glib"
|
||||
@@ -30,6 +32,9 @@ import (
|
||||
// Element is a Go wrapper around a GstElement.
|
||||
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
|
||||
// no variadic functions in cgo.
|
||||
func ElementLinkMany(elems ...*Element) error {
|
||||
@@ -45,24 +50,145 @@ func ElementLinkMany(elems ...*Element) error {
|
||||
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.
|
||||
func (e *Element) Instance() *C.GstElement { return C.toGstElement(e.Unsafe()) }
|
||||
|
||||
// Link wraps gst_element_link and links this element to the given one.
|
||||
func (e *Element) Link(elem *Element) error {
|
||||
if ok := C.gst_element_link((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
|
||||
return fmt.Errorf("Failed to link %s to %s", e.Name(), elem.Name())
|
||||
// AbortState aborts the state change of the element. This function is used by elements that do asynchronous state changes
|
||||
// and find out something is wrong.
|
||||
func (e *Element) AbortState() { C.gst_element_abort_state(e.Instance()) }
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// LinkFiltered wraps gst_element_link_filtered and link this element to the given one
|
||||
// using the provided sink caps.
|
||||
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) {
|
||||
return fmt.Errorf("Failed to link %s to %s with provider caps", e.Name(), elem.Name())
|
||||
// CallAsync calls f from another thread. This is to be used for cases when a state change has to be performed from a streaming
|
||||
// thread, directly via SetState or indirectly e.g. via SEEK events.
|
||||
//
|
||||
// Calling those functions directly from the streaming thread will cause deadlocks in many situations, as they might involve waiting
|
||||
// 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
|
||||
@@ -85,37 +211,6 @@ func (e *Element) GetClock() *Clock {
|
||||
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.
|
||||
func (e *Element) GetFactory() *ElementFactory {
|
||||
factory := C.gst_element_get_factory((*C.GstElement)(e.Instance()))
|
||||
@@ -136,18 +231,6 @@ func (e *Element) GetPads() []*Pad {
|
||||
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.
|
||||
// The list must not be modified by the calling code.
|
||||
func (e *Element) GetPadTemplates() []*PadTemplate {
|
||||
@@ -164,6 +247,23 @@ func (e *Element) GetPadTemplates() []*PadTemplate {
|
||||
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.
|
||||
func (e *Element) Has(flags ElementFlags) bool {
|
||||
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()))
|
||||
}
|
||||
|
||||
// URIHandler returns a URIHandler interface if implemented by this element. Otherwise it
|
||||
// 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
|
||||
// Link wraps gst_element_link and links this element to the given one.
|
||||
func (e *Element) Link(elem *Element) error {
|
||||
if ok := C.gst_element_link((*C.GstElement)(e.Instance()), (*C.GstElement)(elem.Instance())); !gobool(ok) {
|
||||
return fmt.Errorf("Failed to link %s to %s", e.Name(), elem.Name())
|
||||
}
|
||||
return &gstURIHandler{ptr: e.Instance()}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TOCSetter returns a TOCSetter interface if implemented by this element. Otherwise it
|
||||
// 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) TOCSetter() TOCSetter {
|
||||
if C.toTocSetter(e.Instance()) == nil {
|
||||
// LinkFiltered wraps gst_element_link_filtered and link this element to the given one
|
||||
// using the provided sink caps.
|
||||
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) {
|
||||
return fmt.Errorf("Failed to link %s to %s with provider caps", e.Name(), elem.Name())
|
||||
}
|
||||
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.
|
||||
//
|
||||
@@ -253,32 +340,13 @@ func (e *Element) SendEvent(ev *Event) bool {
|
||||
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
|
||||
// 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}})
|
||||
// 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 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...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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()))
|
||||
}
|
||||
|
||||
// AbortState aborts the state change of the element. This function is used by elements that do asynchronous state changes
|
||||
// and find out something is wrong.
|
||||
func (e *Element) AbortState() { C.gst_element_abort_state(e.Instance()) }
|
||||
|
||||
// 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()))
|
||||
// TOCSetter returns a TOCSetter interface if implemented by this element. Otherwise it
|
||||
// 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) TOCSetter() TOCSetter {
|
||||
if C.toTocSetter(e.Instance()) == nil {
|
||||
return nil
|
||||
}
|
||||
return &gstTOCSetter{ptr: e.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
|
||||
// thread, directly via SetState or indirectly e.g. via SEEK events.
|
||||
//
|
||||
// Calling those functions directly from the streaming thread will cause deadlocks in many situations, as they might involve waiting
|
||||
// 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),
|
||||
)
|
||||
// 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()}
|
||||
}
|
||||
|
||||
// URIHandler returns a URIHandler interface if implemented by this element. Otherwise it
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
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
|
||||
out = append(out, &ParameterSpec{
|
||||
paramSpec: prop,
|
||||
Name: C.GoString(C.g_param_spec_get_name(prop)),
|
||||
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)),
|
||||
defaultValue: glib.ValueFromNative(unsafe.Pointer(&gval)),
|
||||
})
|
||||
}
|
||||
return out
|
||||
|
@@ -1,11 +1,160 @@
|
||||
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 (
|
||||
"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.
|
||||
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.
|
||||
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.
|
||||
func (p *Plugin) License() string {
|
||||
func (p *Plugin) License() License {
|
||||
ret := C.gst_plugin_get_license((*C.GstPlugin)(p.Instance()))
|
||||
if ret == nil {
|
||||
return ""
|
||||
}
|
||||
return C.GoString(ret)
|
||||
return License(C.GoString(ret))
|
||||
}
|
||||
|
||||
// Source returns the source module for this plugin.
|
||||
|
@@ -14,6 +14,10 @@ type Query struct {
|
||||
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.
|
||||
func NewAcceptCapsQuery(caps *Caps) *Query {
|
||||
return wrapQuery(C.gst_query_new_accept_caps(caps.Instance()))
|
||||
|
@@ -2,6 +2,7 @@ package gst
|
||||
|
||||
// #include "gst.go.h"
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
// Segment is a go wrapper around a GstSegment.
|
||||
// See: https://gstreamer.freedesktop.org/documentation/gstreamer/gstsegment.html?gi-language=c#GstSegment
|
||||
@@ -9,6 +10,12 @@ type Segment struct {
|
||||
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.
|
||||
func NewSegment() *Segment {
|
||||
return wrapSegment(C.gst_segment_new())
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package gst
|
||||
|
||||
// #include "gst.go.h"
|
||||
/*
|
||||
#include "gst.go.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
@@ -10,7 +12,8 @@ import (
|
||||
)
|
||||
|
||||
// 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)
|
||||
|
||||
// URIHandler represents an interface that elements can implement to provide URI handling
|
||||
@@ -20,13 +23,13 @@ type URIHandler interface {
|
||||
GetURI() string
|
||||
// GetURIType returns the type of URI this element can handle.
|
||||
GetURIType() URIType
|
||||
// GetURIProtocols returns the protocols this element can handle.
|
||||
GetURIProtocols() []string
|
||||
// GetProtocols returns the protocols this element can handle.
|
||||
GetProtocols() []string
|
||||
// SetURI tries to set the URI of the given handler.
|
||||
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 {
|
||||
ptr *C.GstElement
|
||||
}
|
||||
@@ -48,8 +51,8 @@ func (g *gstURIHandler) GetURIType() URIType {
|
||||
return URIType(ty)
|
||||
}
|
||||
|
||||
// GetURIProtocols returns the protocols this element can handle.
|
||||
func (g *gstURIHandler) GetURIProtocols() []string {
|
||||
// GetProtocols returns the protocols this element can handle.
|
||||
func (g *gstURIHandler) GetProtocols() []string {
|
||||
protocols := C.gst_uri_handler_get_protocols((*C.GstURIHandler)(g.Instance()))
|
||||
if protocols == nil {
|
||||
return nil
|
||||
|
@@ -209,6 +209,10 @@ func wrapAllocationParams(obj *C.GstAllocationParams) *AllocationParams {
|
||||
return &AllocationParams{ptr: obj}
|
||||
}
|
||||
|
||||
func wrapElementClass(klass C.gpointer) *ElementClass {
|
||||
return &ElementClass{&ObjectClass{ptr: C.toGObjectClass(unsafe.Pointer(klass))}}
|
||||
}
|
||||
|
||||
// Clock wrappers
|
||||
|
||||
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