Reputation: 118
Can someone, please, tell me where I can find an example of how to read an rtsp with gstreamer in C?. Actually there are many out there, but I need one where the "rtspsrc" component is explicitly used, all I can find is either "gst-launch" examples or in C code, but using "uridecodebin"
I tried with this, but the "pad_added_handler()" never is called and I don't get any error either
#include <gst/gst.h>
static void pad_added_handler (GstElement *src, GstPad *new_pad, GstElement *rtphepay);
int main(int argc, char *argv[]) {
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
gboolean terminate = FALSE;
/* Initialize GStreamer */
gst_init (&argc, &argv);
GstElement *pipeline = gst_pipeline_new ("rtsp-pipeline");
if (!pipeline) {
g_printerr ("Pipeline could not be created. Exiting.\n");
return -1;
}
// input
GstElement *rtspsrc = gst_element_factory_make("rtspsrc", "rtspsrc");
g_object_set (G_OBJECT (rtspsrc), "location", "rtsp://192.168.1.88:554/11", "latency", 10, NULL);
// decoding
GstElement *rtph265depay = gst_element_factory_make("rtph265depay", "rtph265depay");
GstElement *h265parse = gst_element_factory_make("h265parse", "h265parse");
GstElement *avdec_h265 = gst_element_factory_make("avdec_h265", "avdec_h265");
// display
GstElement *videoconvert = gst_element_factory_make("videoconvert", "videoconvert_screen");
GstElement *sink = gst_element_factory_make("autovideosink", "nvvideo_renderer");
gst_bin_add_many(GST_BIN(pipeline), rtph265depay, h265parse, avdec_h265, videoconvert, sink, NULL);
if (!gst_element_link_many(rtph265depay, h265parse, avdec_h265, videoconvert, sink, NULL)) {
g_printerr("Elements could not be linked. Exiting.\n");
return -1;
}
// register callback
g_signal_connect (rtspsrc, "pad-added", G_CALLBACK (pad_added_handler), rtph265depay);
/* Start playing */
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr ("Unable to set the pipeline to the playing state.\n");
gst_object_unref (pipeline);
return -1;
}
/* Listen to the bus */
bus = gst_element_get_bus (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 (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 (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
static void pad_added_handler (GstElement *src, GstPad *new_pad, GstElement *rtphepay) {
GstPad *sink_pad = gst_element_get_static_pad (rtphepay, "sink");
GstPadLinkReturn ret;
GstCaps *new_pad_caps = NULL;
GstStructure *new_pad_struct = NULL;
const gchar *new_pad_type = NULL;
g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));
/* 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 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);
}
Upvotes: 1
Views: 658
Reputation: 7373
It looks like you followed the "Hello World" example from GStreamer. You are actually doing more than just "Hello World. You want to have callback events triggered. These come from a GLib mainloop.
I would recommend to check out the "Your first application" example from GStreamer instead:
Basically you what you want is to add the GLib mainloop and add a bus watch instead to iterating over the bus messages.
Upvotes: 3