Files
go-gst/cmd/gst-plugin-gen/main.go
2023-09-01 19:14:37 +02:00

184 lines
4.5 KiB
Go

package main
import (
"bufio"
"io"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"text/template"
)
func main() {
var wd string
var err error
if len(os.Args) == 1 {
wd, err = os.Getwd()
if err != nil {
panic(err)
}
} else {
wd = os.Args[1]
}
cfg := buildCfgFromDir(wd)
outfile := path.Join(wd, "zzgenerated_plugin.go")
out, err := os.Create(outfile)
if err != nil {
panic(err)
}
defer out.Close()
pluginTmpl.Execute(out, map[string]interface{}{
"Config": cfg,
})
}
type libraryConfig struct {
Plugin *pluginConfig
Element *elementConfig
}
type pluginConfig struct {
Name, Description, Version, License, Source, Package, Origin, ReleaseDate string
}
type elementConfig struct {
Name, Rank, Impl, Subclass, Interfaces string
}
func buildCfgFromDir(dir string) *libraryConfig {
cfg := &libraryConfig{
Plugin: &pluginConfig{},
Element: &elementConfig{},
}
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if !strings.HasSuffix(path, ".go") {
return nil
}
parseFileIntoCfg(path, cfg)
return nil
})
if err != nil {
panic(err)
}
return cfg
}
func parseFileIntoCfg(path string, cfg *libraryConfig) {
f, err := os.Open(path)
if err != nil {
panic(err)
}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "// +") {
continue
}
line = strings.TrimPrefix(line, "// +")
if strings.HasPrefix(line, "plugin:") {
parseLineToConfig("plugin", line, cfg.Plugin)
continue
}
if strings.HasPrefix(line, "element:") {
parseLineToConfig("element", line, cfg.Element)
}
}
if err := scanner.Err(); err != nil && err != io.EOF {
panic(err)
}
}
func parseLineToConfig(prefix, line string, cfg interface{}) {
trimmed := strings.TrimPrefix(line, prefix+":")
arg, val := parseArgAndValue(trimmed)
v := reflect.ValueOf(cfg).Elem()
for i := 0; i < v.NumField(); i++ {
if v.Type().Field(i).Name == arg {
v.FieldByName(arg).SetString(val)
}
}
}
func parseArgAndValue(line string) (arg, val string) {
spl := strings.Split(line, "=")
return spl[0], spl[1]
}
var pluginTmpl = template.Must(template.New("").Funcs(template.FuncMap{
"adjustedName": func(name string) string {
return strings.ToLower(strings.Replace(name, "-", "_", -1))
},
"splitInterfaces": func(ifacesString string) []string {
return strings.Split(ifacesString, ",")
},
"extendsFromBase": func(subclass string) bool {
return strings.HasPrefix(subclass, "base.")
},
}).Parse(`// !WARNING! THIS FILE WAS GENERATED BY GST-PLUGIN-GEN !WARNING! //
package main
import "C"
import (
"unsafe"
"github.com/go-gst/go-gst/gst"
{{- if (.Config.Element.Subclass | extendsFromBase) }}
"github.com/go-gst/go-gst/gst/base"
{{- end }}
)
// The metadata for this plugin
var pluginMeta = &gst.PluginMetadata{
MajorVersion: gst.VersionMajor,
MinorVersion: gst.VersionMinor,
Name: "{{ .Config.Plugin.Name }}",
Description: "{{ .Config.Plugin.Description }}",
Version: "{{ .Config.Plugin.Version }}",
License: {{ .Config.Plugin.License }},
Source: "{{ .Config.Plugin.Source }}",
Package: "{{ .Config.Plugin.Package }}",
Origin: "{{ .Config.Plugin.Origin }}",
ReleaseDate: "{{ .Config.Plugin.ReleaseDate }}",
// The init function is called to register elements provided by the plugin.
Init: func(plugin *gst.Plugin) bool {
return gst.RegisterElement(
plugin,
// The name of the element
"{{ .Config.Element.Name }}",
// The rank of the element
{{ .Config.Element.Rank }},
// The GoElement implementation for the element
&{{ .Config.Element.Impl }}{},
// The base subclass this element extends
{{ .Config.Element.Subclass }},
{{- if .Config.Element.Interfaces }}
// The interfaces this element implements
{{- range $index, $interface := .Config.Element.Interfaces | splitInterfaces }}
{{ $interface }},
{{- end }}
{{- end }}
)
},
}
// 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 NAME is the name of the compiled
// artifact with or without the "libgst" prefix and hyphens are replaced with underscores.
//export gst_plugin_{{ .Config.Plugin.Name | adjustedName }}_get_desc
func gst_plugin_{{ .Config.Plugin.Name | adjustedName }}_get_desc() unsafe.Pointer { return pluginMeta.Export() }
`))