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