-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Question] GST: getting the source's name from Message #195
Comments
As you may know, I do know absolutely nothing about the gstreamer library. And I would generally recommend not to use it with gintro. GStreamer is a very low level library, so it is really hard to use it with wrappers or bindings. It may be possible, but I guess using C or Rust is much easier. For your question, using Google and grep gives
So there seems to exist a function which can give you a Structure type from a Message, and there is a function getName() which seems to return a string from a Structure. So that may be what you need, but of course that is fully untested, and maybe I misunderstand you. |
Thanks Stefan for your answer, but I explained myself poorly. Your response is in order to get Message's name. But I am aiming to get source's name:
If there were a What I did as a way around was making the following function public: proc gst_object_get_name*(self: ptr Object00): cstring |
I think your explanation was fine, the problem is that I do know nothing about gst and that gst is so difficult. Indeed gst is nearly the only GTK related lib where we have to export the fields of some objects. GTK2 did that for a few types, but with GTK3 we have generally getter and setter functions for the field content. So your idea of using gst_object_get_name() is a solution indeed. There may exist better solutions, we would have to discuss that with a gst expert, maybe with Mr. Droege. But for that we would need a complete working app, or better a minimal working example, so that he can really easily understand what we intent. Or we would have to find some existing, working C code, which we can convert to Nim. |
My objective is to through the GST Basic Tutorials. Right now I am on 3: Dynamic Pipelines which I am trying to translate into Nim. In particular in the part where error's are checked. My workaround is in line: echo &"Error received from element {gst_object_get_name(msg.impl.src)}: {err.message}" But I think it would be better a mean to get an My still crappy code (mixing C and nim): ex03_dynamic_pipelines.nim import gintro/[gst,gobject,glib], os, strformat
# Structure to contain all our information, so we can pass it to callbacks
type
CustomData = object
pipeline, source, convert, resample, sink: gst.Element
#[
typedef struct _CustomData {
GstElement *pipeline;
GstElement *source;
GstElement *convert;
GstElement *resample;
GstElement *sink;
} CustomData;
]#
#[
/* Handler for the pad-added signal */
static void pad_added_handler (GstElement *src, GstPad *pad, CustomData *data);
]#
#[ proc sourceName*(self: Message): string =
let resul0 = gst_object_get_name(cast[ptr Object00](self.impl.src))
if resul0.isNil:
return
result = $resul0
cogfree(resul0) ]#
# This function will be called by the pad-added signal NOTA: cast[ptr Pad00](pad.impl)
proc padAddedHandler(src:ptr Element00; newPad:ptr Pad00; dataPtr:pointer) {.cdecl.} =
var data = cast[CustomData](dataPtr)
#var sinkPad:gst.Pad = gst_element_get_static_pad(data.convert, "sink")
var sinkPad:gst.Pad = getRequestPad(data.convert, "sink")
#GstPadLinkReturn ret;
#GstCaps *new_pad_caps = NULL;
#GstStructure *new_pad_struct = NULL;
#const gchar *new_pad_type = NULL;
echo "New pad"
#echo("Received new pad '%s' from '%s':\n", newPad.name, src.name ) # GST_PAD_NAME, GST_ELEMENT_NAME
#[ /* If our converter is already linked, we have nothing to do here */
if (gst_pad_is_linked (sink_pad)) {
g_print ("We are already linked. Ignoring.\n");
goto exit;
} ]#
#[ /* Check the new pad's type */
new_pad_caps = gst_pad_get_current_caps (new_pad);
new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
new_pad_type = gst_structure_get_name (new_pad_struct);
if (!g_str_has_prefix (new_pad_type, "audio/x-raw")) {
g_print ("It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);
goto exit;
} ]#
#[ /* Attempt the link */
ret = gst_pad_link (new_pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret)) {
g_print ("Type is '%s' but link failed.\n", new_pad_type);
} else {
g_print ("Link succeeded (type '%s').\n", new_pad_type);
}
]#
#[ exit:
/* Unreference the new pad's caps, if we got them */
if (new_pad_caps != NULL)
gst_caps_unref (new_pad_caps);
/* Unreference the sink pad */
gst_object_unref (sink_pad); ]#
proc toBoolVal(b: bool): Value =
let gtype = typeFromName("gboolean")
discard init(result, gtype)
setBoolean(result, b)
proc toUIntVal(i: int): Value =
let gtype = typeFromName("guint")
discard init(result, gtype)
setUint(result, i)
proc toStringVal(i: string): Value =
let gtype = typeFromName("gchararray")
discard init(result, gtype)
setString(result, i)
echo repr result
converter toBin*(elem:gst.Element):gst.Bin =
cast[gst.Bin](elem)
proc main =
var data:CustomData
#GstBus *bus;
#GstMessage *msg;
#GstStateChangeReturn ret;
#gboolean terminate = FALSE;
## Initialize GStreamer
gst.init()
# Create the elements
data.source = make("uridecodebin", "source")
data.convert = make("audioconvert", "convert")
data.resample = make("audioresample", "resample")
data.sink = make("autoaudiosink", "sink")
# Create the empty pipeline
data.pipeline = newPipeline("test-pipeline")
# Check if the elements are empty
if data.source.isNil or data.pipeline.isNil or data.convert.isNil or data.resample.isNil or data.sink.isNil:
quit("Not all elements could be created.\n") # QuitFailure,
# Build the pipeline
# 1. Add the elements
discard data.pipeline.add(data.source)
discard data.pipeline.add(data.convert)
discard data.pipeline.add(data.resample)
discard data.pipeline.add(data.sink)
# 2. Linking
discard data.source.link(data.convert)
discard data.convert.link(data.resample)
discard data.resample.link(data.sink)
#[
/* Build the pipeline. Note that we are NOT linking the source at this
* point. We will do it later. */
gst_bin_add_many (GST_BIN (data.pipeline), data.source, data.convert, data.resample, data.sink, NULL);
if (!gst_element_link_many (data.convert, data.resample, data.sink, NULL)) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (data.pipeline);
return -1;
}
]#
# Set the URI to play
var uri = toStringVal("https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm")
data.source.setProperty("uri", uri)
# Connect to the pad-added signal
#g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data);
#var flag:ConnectFlag = 0
#discard scPadAdded( data.source, padAddedHandler, cast[pointer](data.unsafeAddr), {0.ConnectFlag})
# Start playing
discard gst.setState(data.pipeline, gst.State.playing)
## Wait until error or EOS
var bus:gst.Bus = gst.getBus(data.pipeline)
var msg:gst.Message = gst.timedPopFiltered(bus, gst.Clock_Time_None, {gst.MessageFlag.error, gst.MessageFlag.eos})
var tmp = msg.getType
discard gst.setState(data.pipeline, gst.State.null) # is this necessary?
#var msgFlag:MessageFlag = msg.getType
var msgType = msg.getType
#echo msg.impl.src.getName
#echo msg.getStructure.getName
if gst.MessageFlag.error in msgType:
var err:ptr glib.Error
var debugInfo:string
msg.parseError(err, debugInfo)
#echo typeof(msg.src)
echo &"Error received from element {gst_object_get_name(msg.impl.src)}: {err.message}" #<============== HERE
#echo cast[ptr gst.Object00](msg.impl).name
if debugInfo == "":
debugInfo = "none"
echo &"Debugging information: {debugInfo}\n"
#echo "Error received from element %s: %s", msg.src.name, err.message
#[
/* Listen to the bus */
bus = gst_element_get_bus (data.pipeline);
do {
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* Parse message */
if (msg != NULL) {
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
terminate = TRUE;
break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream reached.\n");
terminate = TRUE;
break;
case GST_MESSAGE_STATE_CHANGED:
/* We are only interested in state-changed messages from the pipeline */
if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) {
GstState old_state, new_state, pending_state;
gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
g_print ("Pipeline state changed from %s to %s:\n",
gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
}
break;
default:
/* We should not reach here */
g_printerr ("Unexpected message received.\n");
break;
}
gst_message_unref (msg);
}
} while (!terminate);
/* Free resources */
gst_object_unref (bus);
gst_element_set_state (data.pipeline, GST_STATE_NULL);
gst_object_unref (data.pipeline);
return 0;
}
]#
main() My first issue (raised here is looking into Message's content). But there are others (I don't know why the pipeline is not working). |
I managed doing what @mantielero wanted to achive. # Those procedures should be added to 'gst.nim'
proc src*(self: Message): ptr Object00 =
var srcElement: ptr gst.Object00 = self[].impl[].src
return srcElement
proc name*(self: ptr Object00): string =
let resul0 = gst_object_get_name(self)
if resul0.isNil:
return
result = $resul0
cogfree(resul0) The example n.3 of gstreamer in nim: https://gstreamer.freedesktop.org/documentation/tutorials/basic/dynamic-pipelines.html?gi-language=c import gintro/gst
import gintro/gobject
import strformat
## Working example with a dynamic pipeline
var source, convert, resample, sink: Element
proc padAdded(self: ptr Element00; newPad: ptr Pad00; xdata: pointer) {.cdecl} =
# is called twice, first time link fails
var name: Value
let gtype = typeFromName("gchararray")
discard gobject.init(name, gtype)
source.getProperty("name", name)
if source.link(convert):
echo fmt"New pad added for element {name.getString()}"
proc main =
# Initialize GStreamer
gst.init()
# create elements
source = gst.make("uridecodebin", "source")
convert = gst.make("audioconvert", "convert")
resample = gst.make("audioresample", "resample")
sink = gst.make("autoaudiosink", "sink")
assert not source.isNil and not convert.isNil and not resample.isNil and not sink.isNil, "Could not create all elements"
var pipeline = gst.newPipeline("mypipeline")
var bus = gst.getBus(pipeline)
bus.addSignalWatch()
bus.enableSyncMessageEmission()
assert pipeline.add(source) and pipeline.add(convert) and pipeline.add(resample) and pipeline.add(sink), "Cannot add elements to pipeline"
# link elements
assert link(convert, resample) and link(resample, sink), "Cannot link"
var v: Value
let gtype = typeFromName("gchararray")
discard gobject.init(v, gtype)
v.setString("https://gstreamer.freedesktop.org/media/sintel_trailer-480p.webm")
source.setProperty("uri", v)
var cf: ConnectFlags
echo scPadAdded(source, padAdded, nil, cf)
## Start playing
discard gst.setState(pipeline, gst.State.playing)
echo "waiting for messages"
while true:
var msg = gst.timedPopFiltered(bus, gst.Clock_Time_None,
{gst.MessageFlag.error, gst.MessageFlag.eos, gst.MessageFlag.info, gst.MessageFlag.stateChanged, gst.MessageFlag.buffering})
var kind = msg.getType.getName()
echo "Object kind:", kind, " name:", msg.src.name()
if kind == "eos":
echo "End of stream"
break
main() |
Great! |
The type from
Message.impl.src
isptr Object00
but I cannot feed that toname
:proc name*(self: Object): string
Is there a way to convert
ptr Object00
intoObject
?The text was updated successfully, but these errors were encountered: