Hello.
I have made an example code for switching between 3 live cameras, which are streaming mjpeg frames over rtp. The code is not perfect, but is working. Switching between streams is done by pressing space in console. Comments are welcome. my setup: export STREAM1=rtsp://192.168.1.109:554/channel1 export STREAM2=rtsp://192.168.1.109:554/channel2 export STREAM3=rtsp://192.168.1.109:554/channel3 export SINK=autovideosink > ./example $STREAM1 $STREAM2 $STREAM3 $SINK ----------------------- code ------------------ /* Compile string: gcc main.c -o example -Wall `pkg-config --cflags --libs gstreamer-1.0` gcc main.c -o example -Wall `pkg-config --cflags --libs gstreamer-0.10` */ #include <gst/gst.h> #include <glib.h> #include <strings.h> #include <stdio.h> typedef struct _CustomData { GstElement *pipeline; GstElement *src[3]; GstElement *rtpjpegdepay[3]; GstElement *queue[3]; GstElement *inputselector; GstElement *jpegdec; GstElement *colorspace; GstElement *videoscale; GstElement *sink; GMainLoop *loop; GstPad *activepad; int activeidx; } CustomData; /////////////////////////////////////////////////////////////// /* Process keyboard input */ static gboolean handle_keyboard (GIOChannel *source, GIOCondition cond, CustomData *data) { gchar *str = NULL; if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) != G_IO_STATUS_NORMAL) { return TRUE; } switch (g_ascii_tolower (str[0])) { case ' ': { gchar padname[32]; data->activeidx ++; if (data->activeidx>2) data->activeidx=0; g_print("Switching to %d\n", data->activeidx); sprintf(padname, "sink%d", data->activeidx); data->activepad = gst_element_get_static_pad (data->inputselector, padname); g_object_set (G_OBJECT(data->inputselector), "active-pad", data->activepad, NULL); break; } default: break; } g_free (str); return TRUE; } /////////////////////////////////////////////////////////////// static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data) { CustomData *cdata = (CustomData *) data; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: g_print ("End of stream\n"); g_main_loop_quit (cdata->loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error (msg, &error, &debug); g_free (debug); g_printerr ("Error: %s\n", error->message); g_error_free (error); g_main_loop_quit (cdata->loop); break; } default: break; } return TRUE; } /////////////////////////////////////////////////////////////// static void on_pad_added (GstElement *element, GstPad *pad, void *data) { GstPad *sinkpad; GstElement *data_element = GST_ELEMENT(data); GstPadLinkReturn res; g_print ("Request linking for %s and %s\n", GST_OBJECT_NAME(element), GST_OBJECT_NAME(data_element)); sinkpad = gst_element_get_static_pad (data_element, "sink"); if (!gst_pad_is_linked (sinkpad)) { g_print ("Linking %s and %s\n", GST_OBJECT_NAME(pad), GST_OBJECT_NAME(sinkpad)); res = gst_pad_link (pad, sinkpad); if (res!=GST_PAD_LINK_OK) { g_error ("Failed to link %s %s! Error: %d\n",GST_OBJECT_NAME(pad), GST_OBJECT_NAME(sinkpad), res); } } gst_object_unref (sinkpad); } /////////////////////////////////////////////////////////////// int main (int argc, char *argv[]) { CustomData data; GstBus *bus; guint bus_watch_id; gboolean res; int i; GIOChannel *io_stdin; /* Initialisation */ gst_init (&argc, &argv); data.loop = g_main_loop_new (NULL, FALSE); /* Check input arguments */ g_print("Parameters:\n\tOutput: %s\n", argv[argc-1]); /* Create gstreamer elements */ data.pipeline = gst_pipeline_new ("test"); for (i=0; i<3; i++) { g_print("Source #%d: %s\n", i, argv[i+1]); data.src[i] = gst_element_factory_make("rtspsrc", NULL); if (!data.src[i]) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.src[i])); return -1; } else { g_object_set (G_OBJECT(data.src[i]), "location", argv[i+1], NULL); g_object_set (G_OBJECT(data.src[i]), "latency", 10, NULL); data.rtpjpegdepay[i] = gst_element_factory_make("rtpjpegdepay", NULL); if (!data.rtpjpegdepay[i]) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.rtpjpegdepay[i])); return -1; } else { data.queue[i] = gst_element_factory_make("queue", NULL); if (!data.queue[i]) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.queue[i])); return -1; } } } } data.inputselector = gst_element_factory_make("input-selector", NULL); data.jpegdec = gst_element_factory_make("jpegdec", NULL); data.colorspace = gst_element_factory_make("ffmpegcolorspace", NULL); data.videoscale = gst_element_factory_make("videoscale", NULL); data.sink = gst_element_factory_make(argv[argc-1], NULL); if (!data.pipeline) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.pipeline)); return -1; } else if (!data.inputselector) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.inputselector)); return -1; } if (!data.jpegdec) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.jpegdec)); return -1; } if (!data.colorspace) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.colorspace)); return -1; } if (!data.sink) { g_printerr ("Object %s could not be created.\n", GST_OBJECT_NAME(data.sink)); return -1; } g_print("1. Objects created.\n\n"); /* Set up the pipeline */ /* Add a keyboard watch so we get notified of keystrokes */ #ifdef _WIN32 io_stdin = g_io_channel_win32_new_fd (fileno (stdin)); #else io_stdin = g_io_channel_unix_new (fileno (stdin)); #endif g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc)handle_keyboard, &data); /* Add a message handler */ bus = gst_pipeline_get_bus (GST_PIPELINE (data.pipeline)); bus_watch_id = gst_bus_add_watch (bus, bus_call, &data); gst_object_unref (bus); /* we add all elements into the pipeline */ gst_bin_add_many(GST_BIN(data.pipeline), data.inputselector, data.jpegdec, data.colorspace, data.videoscale, data.sink, NULL); for (i=0; i<3; i++) { gst_bin_add_many(GST_BIN(data.pipeline), data.src[i], data.rtpjpegdepay[i], data.queue[i], NULL); } g_print("2. Objects added.\n\n"); /* Link the elements together */ // 1. Sources - queues for (i=0; i<3; i++) { g_print("Delayed linking: %s - %s\n",GST_OBJECT_NAME(data.src[i]), GST_OBJECT_NAME(data.rtpjpegdepay[i])); g_signal_connect (data.src[i] , "pad-added", G_CALLBACK (on_pad_added), data.rtpjpegdepay[i]); g_print("Linking: %s - %s\n",GST_OBJECT_NAME(data.rtpjpegdepay[i]), GST_OBJECT_NAME(data.queue[i])); if (!gst_element_link (data.rtpjpegdepay[i], data.queue[i])) { g_error ("Failed to link %s %s!\n",GST_OBJECT_NAME(data.rtpjpegdepay[i]), GST_OBJECT_NAME(data.queue[i])); return -1; } } // Queues - input selector for (i=0; i<3; i++) { GstPad *srcpad = gst_element_get_static_pad (data.queue[i], "src"); GstPad *sinkpad = gst_element_get_request_pad (data.inputselector, "sink%d"); g_print("Linking pads: %s-%s - %s\n",GST_OBJECT_NAME(data.queue[i]), GST_OBJECT_NAME(srcpad), GST_OBJECT_NAME(sinkpad)); if (gst_pad_link (srcpad, sinkpad)) { g_error ("Failed to link %s %s!\n",GST_OBJECT_NAME(srcpad), GST_OBJECT_NAME(sinkpad)); return -1; } } // Input selector - JPEG decoder g_print("Linking: %s - %s\n",GST_OBJECT_NAME(data.inputselector), GST_OBJECT_NAME(data.jpegdec)); if (!gst_element_link (data.inputselector, data.jpegdec)) { g_error ("Failed to link %s %s!\n",GST_OBJECT_NAME(data.inputselector), GST_OBJECT_NAME(data.jpegdec)); return -1; } // JPEG Decoder - colorspace converter g_print("Linking: %s - %s\n",GST_OBJECT_NAME(data.jpegdec), GST_OBJECT_NAME(data.colorspace)); if (!gst_element_link (data.jpegdec, data.colorspace)) { g_error ("Failed to link %s %s!\n",GST_OBJECT_NAME(data.jpegdec), GST_OBJECT_NAME(data.colorspace)); return -1; } // Colorspace converter - scaler g_print("Linking: %s - %s\n", GST_OBJECT_NAME(data.colorspace), GST_OBJECT_NAME(data.videoscale)); res = gst_element_link (data.colorspace, data.videoscale); if (!res) { g_error ("Failed to link %s %s!\n",GST_OBJECT_NAME(data.colorspace), GST_OBJECT_NAME(data.videoscale)); return -1; } // Scaler - sink g_print("Linking: %s - %s\n",GST_OBJECT_NAME(data.videoscale), GST_OBJECT_NAME(data.sink)); res = gst_element_link_pads_filtered (data.videoscale, "src", data.sink, "sink", gst_caps_new_simple ("video/x-raw-yuv", "width", G_TYPE_INT, 800, "height", G_TYPE_INT, 480, "framerate", GST_TYPE_FRACTION, 15, 1, NULL)); if (!res) { g_error ("Failed to link %s %s!\n",GST_OBJECT_NAME(data.videoscale), GST_OBJECT_NAME(data.sink)); return -1; } g_print("3. Objects linked.\n\n"); data.activeidx = 0; data.activepad = gst_element_get_static_pad (data.inputselector, "sink0"); g_object_set (G_OBJECT(data.inputselector), "active-pad", data.activepad, NULL); g_print("4. Active pad set.\n\n"); // Set the pipeline to "playing" state gst_element_set_state (data.pipeline, GST_STATE_PLAYING); // Iterate g_print ("5. Running...\n\n"); g_main_loop_run (data.loop); // Out of the main loop, clean up nicely g_print ("Returned, stopping playback\n"); gst_element_set_state (data.pipeline, GST_STATE_NULL); g_print ("Deleting pipeline\n"); gst_object_unref (GST_OBJECT (data.pipeline)); g_source_remove (bus_watch_id); g_main_loop_unref (data.loop); return 0; } |
Hello, Do you have a idea how to make gstreamer detect the /dev/video*
devices and start a recording for each one? do i need to use some kind of for loop? -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
> -----Original Message-----
> From: gstreamer-devel [mailto:gstreamer-devel- > [hidden email]] On Behalf Of socieboy > Sent: vrijdag 14 juni 2019 22:38 > To: [hidden email] > Subject: Re: Example of 3 live cameras streaming. > > CAUTION: This Email originated from outside Televic. Do not click links or > open attachments unless you recognize the sender and know the content is > safe. > > > Hello, Do you have a idea how to make gstreamer detect the /dev/video* > devices and start a recording for each one? > > do i need to use some kind of for loop? > > Do you want to monitor the /dev/video* on the fly? Or are they available at startup? Via a shell-script you can do something like: #!/bin/sh if [ -e /dev/video0 ]; then gst-launch1.0 ................ & fi if [ -e /dev/video1 ]; then gst-launch1.0 ................ & fi ..... Or you create an application to detect the /dev/video* and start a gstreamer pipeline accordingly grt _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
In reply to this post by socieboy
On Mon, Jun 17, 2019 at 5:01 AM socieboy <[hidden email]> wrote: Hello, Do you have a idea how to make gstreamer detect the /dev/video* You can just define three separate pipelines on the command line using gst-launch-1.0 to test. What are you actually going to do with these streams? For example, I record using two cameras and use a muxer and multifilesink to combine them into one mkv container. -aps _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
In reply to this post by socieboy
Le vendredi 14 juin 2019 à 15:38 -0500, socieboy a écrit :
> Hello, Do you have a idea how to make gstreamer detect the /dev/video* > devices and start a recording for each one? > > do i need to use some kind of for loop? You can use GstDeviceMonitor API. https://gstreamer.freedesktop.org/documentation/gstreamer/gstdevicemonitor.html?gi-language=c > > > > -- > Sent from: http://gstreamer-devel.966125.n4.nabble.com/ > _______________________________________________ > gstreamer-devel mailing list > [hidden email] > https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel signature.asc (201 bytes) Download Attachment |
Free forum by Nabble | Edit this page |