Example of 3 live cameras streaming.
pavel
justason at mail.ru
Thu Oct 25 04:21:46 PDT 2012
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;
}
--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Example-of-3-live-cameras-streaming-tp4656703.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
More information about the gstreamer-devel
mailing list