Example of 3 live cameras streaming.

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Example of 3 live cameras streaming.

pavel
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;
}
Reply | Threaded
Open this post in threaded view
|

Re: Example of 3 live cameras streaming.

socieboy
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
Reply | Threaded
Open this post in threaded view
|

RE: Example of 3 live cameras streaming.

Wouter Vanhauwaert
> -----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
Reply | Threaded
Open this post in threaded view
|

Re: Example of 3 live cameras streaming.

pisymbol .
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*
devices and start a recording for each one?

do i need to use some kind of for loop?

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
Reply | Threaded
Open this post in threaded view
|

Re: Example of 3 live cameras streaming.

Nicolas Dufresne-5
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