Closed Garionion closed 3 years ago
I'm not surprised about the fraction, and I'll have to think on that. One thing you could do though is see if it just takes a string of "50/1". It's probably a similar issue with the video format (which is an Enum).
The SetProperty
is actually something provided by the glib bindings and it is really only meant to handle go types from my understanding. It remains mostly in-tact from when I originally forked it from gotk3, but I've made small changes.
The fraction makes sense because that's just a GoType helper that is also not fully implemented. I kinda hoped the enum would work since well...it's just an integer.
What this tells me is SetProperty
over in the glib stuff needs to be smarter. And I'll have to think on the cleanest way to accomplish that. Off the top of my head I'm wondering if the wrapped Go objects should export some internal method for handling type conversation in that context.
One thing you could do though is see if it just takes a string of "50/1".
Invalid type gchararray for property framerate
… nope -.-
I'll hack on it tonight and post here if I come up with anything
Alright, I have it fixed at least for these use cases (and a few others I came across, e.g. caps, audioformats) on v0.2.14
. There are other GstValues
I don't have this implemented for yet (i.e. ranges), but I'll tackle those either tonight or over the weekend.
package main
import (
"fmt"
"github.com/tinyzimmer/go-gst/gst"
"github.com/tinyzimmer/go-gst/gst/video"
)
func main() {
gst.Init(nil)
videoparse, err := gst.NewElement("rawvideoparse")
if err != nil {
panic(err)
}
videoparse.SetProperty("format", video.FormatBGRA)
videoparse.SetProperty("framerate", gst.Fraction(50, 1))
format, err := videoparse.GetProperty("format")
if err != nil {
panic(err)
}
framerate, err := videoparse.GetProperty("framerate")
if err != nil {
panic(err)
}
fmt.Println("format:", format)
fmt.Println("framerate:", framerate)
// format: BGRA
// framerate: 50/1
}
Example of it working the same for caps if you are interested
package main
import (
"fmt"
"github.com/tinyzimmer/go-gst/gst"
)
func main() {
gst.Init(nil)
capsfilter, err := gst.NewElement("capsfilter")
if err != nil {
panic(err)
}
capsfilter.SetProperty("caps", gst.NewCapsFromString("video/x-raw,framerate=50/1"))
caps, err := capsfilter.GetProperty("caps")
if err != nil {
panic(err)
}
fmt.Println("caps:", caps)
// caps: video/x-raw, framerate=(fraction)50/1
}
Thank you very much, works like a charm :)
Glad to hear 😄. I'll keep the issue open to remind myself about the other values.
so … i also need some more types e.g. from GstBaseTextOverlay but those aren't present in this library (yet), at least i did not find those. I would like to help, but I have no idea how or even where exactly to put them.
Which ones do you need. Those base-text-overlay-*
ones? I am equally at a loss at where the hell those would even go...
Can you provide some more context? I have ideas but I want to understand the use case better.
Sure. We have (soon-ish) a ski-jumping contest which we live stream. We want to overlay graphics (current jumper, his evaluation …) on our Stream. Last Year I already used some gstreamer, but only to play graphic clips and overlay my python-generated images. As I get some values later than others, it would be nice to be able to start a graphic playout and update some text on-the-fly. therefore i decided to go full in on gstreamer and because of hacking in gstreamer in my python code it wasn't a nice codebase anymore, i decided to rewrite it (again), but this time in go ^^
I only need to overlay text and images.
I could also use gst.NewPipelineFromString()
since the types/fields/values i need to change are plain boolean and strings
to your question before that: as of now, i would (for the text overlay) only use Base-text-overlay-halign
and Base-text-overlay-valign
and (for the image) Gdk-pixbuf-positioning-mode
.
Could you give me an example of code producing an error? I'm not able to play just this moment, but it looks like it could be a similar fix to the enums. It would probably end up in a new pango
package, just a very small package.
Yes, sure
package main
import (
"fmt"
"github.com/tinyzimmer/go-gst/gst"
)
func main() {
gst.Init(nil)
text, err := gst.NewElement("textoverlay")
if err != nil {
fmt.Println(err)
}
setPropertyWrapper(text,"halignment", 0) //left
setPropertyWrapper(text,"valignment", 2) //top
setPropertyWrapper(text,"text", "hello world")
image, err := gst.NewElement("gdkpixbufoverlay")
if err != nil {
fmt.Println(err)
}
setPropertyWrapper(image,"positioning-mode", 1) // pixels-absolute
}
func setPropertyWrapper(element *gst.Element, name string, value interface{}) {
err := element.SetProperty(name, value)
if err != nil {
fmt.Printf("Failed to set Property: %v\n", err)
}
}
with exception of the property text
all SetProperty
produce an error:
go run ./main.go
Failed to set Property: Invalid type gint for property halignment
Failed to set Property: Invalid type gint for property valignment
Failed to set Property: Invalid type gint for property positioning-mode
Thanks for the examples. I ended up having to reset my PC last night from some update hell, but I'll try to take a swing at it some time today.
So what I kinda expected is that the headers related to specific plugins are not included in packages. So even if there was a good place to bind them here, you'd have a hard time finding the headers you need.
What's happening here is you are trying to set enums. The workarounds I did for fractions and caps and stuff are a separate matter, but here is the issue with the glib bindings trying to allocate them as integers instead of enums. You can get around this explicitly in your code like this:
package main
import (
"fmt"
"github.com/tinyzimmer/go-glib/glib"
"github.com/tinyzimmer/go-gst/gst"
)
func main() {
gst.Init(nil)
text, err := gst.NewElement("textoverlay")
if err != nil {
fmt.Println(err)
}
setPropertyWrapper(text, "halignment", 0) //left
setPropertyWrapper(text, "valignment", 2) //top
setPropertyWrapper(text, "text", "hello world")
image, err := gst.NewElement("gdkpixbufoverlay")
if err != nil {
fmt.Println(err)
}
setPropertyWrapper(image, "positioning-mode", 1) // pixels-absolute
}
func setPropertyWrapper(element *gst.Element, name string, value interface{}) {
var err error
switch x := value.(type) {
case int:
// Obviously not every integer you work with would be an enum, but this
// is an example of allocating the GValue manually instead of letting the
// bindings guess.
//
// SetProperty is basically just doing a switch statement like this and guessing
// on go types, while the gstreamer bindings implement the conversion for objects
// like fractions, ranges, caps, etc. that the glib bindings defer to instead in those cases
val, err := glib.ValueInit(glib.TYPE_ENUM)
if err != nil {
fmt.Printf("Failed to allocate GValue")
return
}
val.SetEnum(x)
err = element.SetPropertyValue(name, val)
default:
err = element.SetProperty(name, x)
}
if err != nil {
fmt.Printf("Failed to set Property: %v\n", err)
}
}
But over in IRC land I find out now there is a gst_util_set_object_arg()
that I should absolutely be binding. It can take a string and will handle the conversion and stuff internally if I am understanding correctly. I'll export a method for it a new tag soon. Probably as a method on the Object
like Object.SetArg(name, value string)
(and everything that gets promoted from it - elements, pipelines, etc.).
But....what's important for now, and probably all future issues like this. Is as of v0.2.17
you can now do this:
package main
import (
"fmt"
"github.com/tinyzimmer/go-gst/gst"
)
func main() {
gst.Init(nil)
text, err := gst.NewElement("textoverlay")
if err != nil {
fmt.Println(err)
}
text.SetArg("halignment", "0")
text.SetArg("valignment", "2")
text.SetArg("text", "hello world")
fmt.Println(text.GetProperty("halignment"))
fmt.Println(text.GetProperty("valignment"))
fmt.Println(text.GetProperty("text"))
image, err := gst.NewElement("gdkpixbufoverlay")
if err != nil {
fmt.Println(err)
}
image.SetArg("positioning-mode", "1")
fmt.Println(image.GetProperty("positioning-mode"))
}
Which produces:
0 <nil>
2 <nil>
hello world <nil>
1 <nil>
The caveat with SetArg
is you don't get an error if anything didn't work. You'd either just want to trust it, or do an extra retrieval to make sure it got set correctly.
ok, wow, this is great :smile:
SetArg()
solves all my problems
Great! Will probably close this issue then since I've implemented the rest of the custom GstValues, and SetArg
should handle all high level use cases.
Hey, I am using rawvideoparse and one thing, I have to do, is setting the property
format
. However, when i try to set this, all i get isInvalid type gint for property format
i set this with:(i have to set this as a property, not as capability)
I also have a similar problem with the framerate. it needs to be a
GstFraction
, so i usedand all i get is
Unable to perform type conversion
Am I doing something wrong?