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}" #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()