interdependently seeking of multible filesources in pipeline

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

interdependently seeking of multible filesources in pipeline

fub3000
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: interdependently seeking of multible filesources in pipeline

Nicolas Dufresne-5


Le 17 déc. 2017 11:44 AM, <[hidden email]> a écrit :
Hello,

I want to create a lite sampler application. Where you can play,stop,loop multiple sound files.
im currently experimenting with gstreamer and stuck on some point.

this is how my application currently look like:

pipeline:
bin1: filesource1 -> decoder1 -> converter1 ---\
|-> audiomixer -> alsasink
bin2: filesource2 -> decoder2 -> converter2  ---/

i have an audiomixer connected with to file sources. how can i seek the 2 sources interdependently ?
I can seek the whole pipeline, but seeking the filesources don't work (see function play_button_CB in src).

can anybody help ?

For now, your only "easy" option would be to use GStreamer Editing Services, a library designed on top of GStreamer to implement non-linear audio/video editing applications. Second possibility would be to use it's helper plugins, NLE. The hard way is to implement something similar to NLE, though that requires strong GStreamer dynamic coding skills, it's not for everyone.


Thanks Richard


-----------------------------------------------
#include <gst/gst.h>
#include <gst/gstelement.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#include <glib.h>
#define FALSE (0)
#define TRUE (!FALSE)

#include <gtk/gtk.h>

typedef struct
{
    GstElement *pipeline;

    GstElement *file_source;
    GstElement *audio_decoder;
    GstElement *audioconvert;
    GstElement *bin_playback;

    GstElement *file_source2;
    GstElement *audio_decoder2;
    GstElement *audioconvert2;
    GstElement *bin_playback2;

    GstElement *audio_mixer;
    GstElement *alsasink;

    GstElement *visual;
    GstElement *tee;


    GstBus *bus;
    GstMessage *message;

    gchar filelocation[2000];
}playerData;

playerData gstreamerPlayer;


typedef struct
{
    GtkWidget *mainWindow;
    GtkWidget *play_button;

}guiData;

guiData guiElements;

/*
void on_pad_added2 (GstElement *src_element, GstPad *src_pad, gpointer data)
{
    g_print ("\nLinking dynamic pad between wavparse and alsasink\n");

    GstElement *sink_element = (GstElement *) data;     // Is alsasink
    GstPad *sink_pad = gst_element_get_static_pad (sink_element, "sink");
    gst_pad_link (src_pad, sink_pad);

    gst_object_unref (sink_pad);
    src_element = NULL;     // Prevent "unused" warning here
}
*/

gboolean player_Create(playerData *data)
{
    data->pipeline = gst_pipeline_new("audio_pipeline");

    if (data->pipeline == NULL)    return FALSE;
    gst_element_set_state (data->pipeline, GST_STATE_NULL);

    data->alsasink = gst_element_factory_make("alsasink", "audiosink");
    data->audio_mixer = gst_element_factory_make("audiomixer","audiomixer");

    if ( !data->pipeline || !data->alsasink || !data->audio_mixer)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }


    gst_bin_add_many(GST_BIN (data->pipeline), data->audio_mixer,data->alsasink,NULL);


    if (gst_element_link_many (data->audio_mixer, data->alsasink, NULL) != TRUE) {
        g_printerr("\nAudio mixer and audio sink element could not link\n");
        return FALSE;
    }


}


gboolean player_Add(playerData *data)
{
    data->bin_playback = gst_bin_new ("bin_playback");
    data->bin_playback2 = gst_bin_new ("bin_playback2");




    data->file_source = gst_element_factory_make("filesrc", "filesource");
    data->audioconvert = gst_element_factory_make("audioconvert", "audioconverter");

    data->file_source2 = gst_element_factory_make("filesrc", "filesource2");
    data->audioconvert2 = gst_element_factory_make("audioconvert", "audioconverter2");





    if ( !data->file_source || !data->audioconvert)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }

    if ( !data->file_source2 || !data->audioconvert2)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }



    g_object_set (G_OBJECT (data->file_source), "location", "/home/admin2/Downloads/SampleAudio_0.4mb.mp3", NULL);

    g_object_set (G_OBJECT (data->file_source2), "location", "/home/admin2/Downloads/SampleAudio_0.7mb.mp3", NULL);



    data->audio_decoder = gst_element_factory_make("mad", "audiomp3decoder");
    if ( !data->audio_decoder)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }


    gst_bin_add_many(GST_BIN(data->bin_playback), data->file_source, data->audio_decoder, data->audioconvert, NULL);

    if (gst_element_link_many (data->file_source, data->audio_decoder, NULL) != TRUE) {
        g_printerr("\nFile source and audio decoder element could not link\n");
        return FALSE;
    }

    if (gst_element_link_many (data->audio_decoder, data->audioconvert, NULL) != TRUE) {
        g_printerr("\nAudio decoder and audio converter element could not link\n");
        return FALSE;
    }

    {
    GstPad *pad;
    pad = gst_element_get_static_pad (data->audioconvert, "src");
    gst_element_add_pad (data->bin_playback, gst_ghost_pad_new ("src", pad));
    gst_object_unref (GST_OBJECT (pad));
    }



/*################################################################################*/
    data->audio_decoder2 = gst_element_factory_make("mad", "audiomp3decoder2");
    if ( !data->audio_decoder2)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }

    gst_bin_add_many(GST_BIN(data->bin_playback2), data->file_source2, data->audio_decoder2, data->audioconvert2,NULL);

    if (gst_element_link_many (data->file_source2, data->audio_decoder2, NULL) != TRUE) {
        g_printerr("\nFile source and audio decoder element could not link\n");
        return FALSE;
    }
    if (gst_element_link_many (data->audio_decoder2, data->audioconvert2, NULL) != TRUE) {
        g_printerr("\nAudio decoder and audio converter element could not link\n");
        return FALSE;
    }

    {
    GstPad *pad;
    pad = gst_element_get_static_pad (data->audioconvert2, "src");
    gst_element_add_pad (data->bin_playback2, gst_ghost_pad_new ("src", pad));
    gst_object_unref (GST_OBJECT (pad));
    }



    return TRUE;
}





gboolean player_Start(playerData *data)
{
    gst_bin_add_many(GST_BIN (data->pipeline), data->bin_playback, data->bin_playback2, NULL);



    if (gst_element_link_many (data->bin_playback, data->audio_mixer, NULL) != TRUE) {
        g_printerr("\nbin_playback and audio mixer element could not link\n");
        return FALSE;
    }
    if (gst_element_link_many (data->bin_playback2, data->audio_mixer, NULL) != TRUE) {
            g_printerr("\nbin_playback2 and audio mixer element could not link\n");
            return FALSE;
    }

    if (gst_element_set_state (data->pipeline, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS) {
        g_print("\nFailed to set pipeline state to NULL\n");
        return FALSE;
    }

    gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
    while(gst_element_get_state(data->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_SUCCESS);
    return TRUE;

}




static gboolean bus_call_CB (GstBus *bus, GstMessage *msg, gpointer    data) {
    GMainLoop *loop = (GMainLoop *) data;

    switch (GST_MESSAGE_TYPE (msg)) {

        case GST_MESSAGE_EOS:
            g_print ("End of stream\n");
            g_main_loop_quit (loop);
            break;

        case GST_MESSAGE_ERROR:
            {
            gchar  *debug;
            GError *error;

            gst_message_parse_error (msg, &error, &debug);

            g_printerr ("Error: %s\n", error->message);
            g_error_free (error);

            if (debug) {
                g_printerr ("\nDebug details: %s\n", debug);
                g_free (debug);
            }

            g_main_loop_quit (loop);
            break;
            }

        default:
            break;
    }

  return TRUE;
}

static void play_button_CB (GtkButton *button, guiData *data) {

    //this works ...
    /*
    if (!gst_element_seek(gstreamerPlayer.pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT,GST_SEEK_TYPE_SET,0,GST_SEEK_TYPE_NONE, 6)) {
        g_print("Seek failed!\n");
    }
    */

    //how to seek file_source independently ???

    //this not ...
    if (!gst_element_seek(gstreamerPlayer.file_source, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT,GST_SEEK_TYPE_SET,0,GST_SEEK_TYPE_NONE, 6)) {
        g_print("Seek failed!\n");
    }
}

void create_Gui(guiData *data) {


      data->mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);


      data->play_button = gtk_button_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_SMALL_TOOLBAR);
      g_signal_connect (G_OBJECT (data->play_button), "clicked", G_CALLBACK (play_button_CB), data);

      GtkWidget *controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
      gtk_box_pack_start (GTK_BOX (controls), data->play_button, FALSE, FALSE, 2);
      gtk_container_add (GTK_CONTAINER (data->mainWindow), controls);

      gtk_widget_show_all(data->mainWindow);

}




int main(int argc, char *argv[])
{
    gtk_init_check(&argc, &argv);
    gst_init (&argc, &argv);


    player_Create(&gstreamerPlayer);
    player_Add(&gstreamerPlayer);
    player_Start(&gstreamerPlayer);



    GstBus *bus;
    guint bus_watch_id;
    GMainLoop *loop;
    loop = g_main_loop_new (NULL, FALSE);



    bus = gst_pipeline_get_bus (GST_PIPELINE (gstreamerPlayer.pipeline));
    bus_watch_id = gst_bus_add_watch (bus, bus_call_CB, loop);
    gst_object_unref (bus);







    create_Gui(&guiElements);
    g_main_loop_run (loop);


    gst_element_set_state (gstreamerPlayer.pipeline, GST_STATE_NULL);
    gst_object_unref (GST_OBJECT (gstreamerPlayer.pipeline));
    g_source_remove (bus_watch_id);
    g_main_loop_unref (loop);

    //to more cleanup here
}

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

Re: interdependently seeking of multible filesources in pipeline

Nicolas Dufresne-5
I forgot, but an in the middle option is to split your source pipelines into seperate pipelines. Then use appsr/appsink to pass the data to the mixing pipeline. This way you can simply retimestamp and it no longer matter how you seek the sources.

Le 17 déc. 2017 1:41 PM, "Nicolas Dufresne" <[hidden email]> a écrit :


Le 17 déc. 2017 11:44 AM, <[hidden email]> a écrit :
Hello,

I want to create a lite sampler application. Where you can play,stop,loop multiple sound files.
im currently experimenting with gstreamer and stuck on some point.

this is how my application currently look like:

pipeline:
bin1: filesource1 -> decoder1 -> converter1 ---\
|-> audiomixer -> alsasink
bin2: filesource2 -> decoder2 -> converter2  ---/

i have an audiomixer connected with to file sources. how can i seek the 2 sources interdependently ?
I can seek the whole pipeline, but seeking the filesources don't work (see function play_button_CB in src).

can anybody help ?

For now, your only "easy" option would be to use GStreamer Editing Services, a library designed on top of GStreamer to implement non-linear audio/video editing applications. Second possibility would be to use it's helper plugins, NLE. The hard way is to implement something similar to NLE, though that requires strong GStreamer dynamic coding skills, it's not for everyone.


Thanks Richard


-----------------------------------------------
#include <gst/gst.h>
#include <gst/gstelement.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#include <glib.h>
#define FALSE (0)
#define TRUE (!FALSE)

#include <gtk/gtk.h>

typedef struct
{
    GstElement *pipeline;

    GstElement *file_source;
    GstElement *audio_decoder;
    GstElement *audioconvert;
    GstElement *bin_playback;

    GstElement *file_source2;
    GstElement *audio_decoder2;
    GstElement *audioconvert2;
    GstElement *bin_playback2;

    GstElement *audio_mixer;
    GstElement *alsasink;

    GstElement *visual;
    GstElement *tee;


    GstBus *bus;
    GstMessage *message;

    gchar filelocation[2000];
}playerData;

playerData gstreamerPlayer;


typedef struct
{
    GtkWidget *mainWindow;
    GtkWidget *play_button;

}guiData;

guiData guiElements;

/*
void on_pad_added2 (GstElement *src_element, GstPad *src_pad, gpointer data)
{
    g_print ("\nLinking dynamic pad between wavparse and alsasink\n");

    GstElement *sink_element = (GstElement *) data;     // Is alsasink
    GstPad *sink_pad = gst_element_get_static_pad (sink_element, "sink");
    gst_pad_link (src_pad, sink_pad);

    gst_object_unref (sink_pad);
    src_element = NULL;     // Prevent "unused" warning here
}
*/

gboolean player_Create(playerData *data)
{
    data->pipeline = gst_pipeline_new("audio_pipeline");

    if (data->pipeline == NULL)    return FALSE;
    gst_element_set_state (data->pipeline, GST_STATE_NULL);

    data->alsasink = gst_element_factory_make("alsasink", "audiosink");
    data->audio_mixer = gst_element_factory_make("audiomixer","audiomixer");

    if ( !data->pipeline || !data->alsasink || !data->audio_mixer)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }


    gst_bin_add_many(GST_BIN (data->pipeline), data->audio_mixer,data->alsasink,NULL);


    if (gst_element_link_many (data->audio_mixer, data->alsasink, NULL) != TRUE) {
        g_printerr("\nAudio mixer and audio sink element could not link\n");
        return FALSE;
    }


}


gboolean player_Add(playerData *data)
{
    data->bin_playback = gst_bin_new ("bin_playback");
    data->bin_playback2 = gst_bin_new ("bin_playback2");




    data->file_source = gst_element_factory_make("filesrc", "filesource");
    data->audioconvert = gst_element_factory_make("audioconvert", "audioconverter");

    data->file_source2 = gst_element_factory_make("filesrc", "filesource2");
    data->audioconvert2 = gst_element_factory_make("audioconvert", "audioconverter2");





    if ( !data->file_source || !data->audioconvert)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }

    if ( !data->file_source2 || !data->audioconvert2)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }



    g_object_set (G_OBJECT (data->file_source), "location", "/home/admin2/Downloads/SampleAudio_0.4mb.mp3", NULL);

    g_object_set (G_OBJECT (data->file_source2), "location", "/home/admin2/Downloads/SampleAudio_0.7mb.mp3", NULL);



    data->audio_decoder = gst_element_factory_make("mad", "audiomp3decoder");
    if ( !data->audio_decoder)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }


    gst_bin_add_many(GST_BIN(data->bin_playback), data->file_source, data->audio_decoder, data->audioconvert, NULL);

    if (gst_element_link_many (data->file_source, data->audio_decoder, NULL) != TRUE) {
        g_printerr("\nFile source and audio decoder element could not link\n");
        return FALSE;
    }

    if (gst_element_link_many (data->audio_decoder, data->audioconvert, NULL) != TRUE) {
        g_printerr("\nAudio decoder and audio converter element could not link\n");
        return FALSE;
    }

    {
    GstPad *pad;
    pad = gst_element_get_static_pad (data->audioconvert, "src");
    gst_element_add_pad (data->bin_playback, gst_ghost_pad_new ("src", pad));
    gst_object_unref (GST_OBJECT (pad));
    }



/*################################################################################*/
    data->audio_decoder2 = gst_element_factory_make("mad", "audiomp3decoder2");
    if ( !data->audio_decoder2)    {
        g_printerr ("\nNot all elements for audio pipeline were created\n");
        return FALSE;
    }

    gst_bin_add_many(GST_BIN(data->bin_playback2), data->file_source2, data->audio_decoder2, data->audioconvert2,NULL);

    if (gst_element_link_many (data->file_source2, data->audio_decoder2, NULL) != TRUE) {
        g_printerr("\nFile source and audio decoder element could not link\n");
        return FALSE;
    }
    if (gst_element_link_many (data->audio_decoder2, data->audioconvert2, NULL) != TRUE) {
        g_printerr("\nAudio decoder and audio converter element could not link\n");
        return FALSE;
    }

    {
    GstPad *pad;
    pad = gst_element_get_static_pad (data->audioconvert2, "src");
    gst_element_add_pad (data->bin_playback2, gst_ghost_pad_new ("src", pad));
    gst_object_unref (GST_OBJECT (pad));
    }



    return TRUE;
}





gboolean player_Start(playerData *data)
{
    gst_bin_add_many(GST_BIN (data->pipeline), data->bin_playback, data->bin_playback2, NULL);



    if (gst_element_link_many (data->bin_playback, data->audio_mixer, NULL) != TRUE) {
        g_printerr("\nbin_playback and audio mixer element could not link\n");
        return FALSE;
    }
    if (gst_element_link_many (data->bin_playback2, data->audio_mixer, NULL) != TRUE) {
            g_printerr("\nbin_playback2 and audio mixer element could not link\n");
            return FALSE;
    }

    if (gst_element_set_state (data->pipeline, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS) {
        g_print("\nFailed to set pipeline state to NULL\n");
        return FALSE;
    }

    gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
    while(gst_element_get_state(data->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_SUCCESS);
    return TRUE;

}




static gboolean bus_call_CB (GstBus *bus, GstMessage *msg, gpointer    data) {
    GMainLoop *loop = (GMainLoop *) data;

    switch (GST_MESSAGE_TYPE (msg)) {

        case GST_MESSAGE_EOS:
            g_print ("End of stream\n");
            g_main_loop_quit (loop);
            break;

        case GST_MESSAGE_ERROR:
            {
            gchar  *debug;
            GError *error;

            gst_message_parse_error (msg, &error, &debug);

            g_printerr ("Error: %s\n", error->message);
            g_error_free (error);

            if (debug) {
                g_printerr ("\nDebug details: %s\n", debug);
                g_free (debug);
            }

            g_main_loop_quit (loop);
            break;
            }

        default:
            break;
    }

  return TRUE;
}

static void play_button_CB (GtkButton *button, guiData *data) {

    //this works ...
    /*
    if (!gst_element_seek(gstreamerPlayer.pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT,GST_SEEK_TYPE_SET,0,GST_SEEK_TYPE_NONE, 6)) {
        g_print("Seek failed!\n");
    }
    */

    //how to seek file_source independently ???

    //this not ...
    if (!gst_element_seek(gstreamerPlayer.file_source, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT,GST_SEEK_TYPE_SET,0,GST_SEEK_TYPE_NONE, 6)) {
        g_print("Seek failed!\n");
    }
}

void create_Gui(guiData *data) {


      data->mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);


      data->play_button = gtk_button_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_SMALL_TOOLBAR);
      g_signal_connect (G_OBJECT (data->play_button), "clicked", G_CALLBACK (play_button_CB), data);

      GtkWidget *controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
      gtk_box_pack_start (GTK_BOX (controls), data->play_button, FALSE, FALSE, 2);
      gtk_container_add (GTK_CONTAINER (data->mainWindow), controls);

      gtk_widget_show_all(data->mainWindow);

}




int main(int argc, char *argv[])
{
    gtk_init_check(&argc, &argv);
    gst_init (&argc, &argv);


    player_Create(&gstreamerPlayer);
    player_Add(&gstreamerPlayer);
    player_Start(&gstreamerPlayer);



    GstBus *bus;
    guint bus_watch_id;
    GMainLoop *loop;
    loop = g_main_loop_new (NULL, FALSE);



    bus = gst_pipeline_get_bus (GST_PIPELINE (gstreamerPlayer.pipeline));
    bus_watch_id = gst_bus_add_watch (bus, bus_call_CB, loop);
    gst_object_unref (bus);







    create_Gui(&guiElements);
    g_main_loop_run (loop);


    gst_element_set_state (gstreamerPlayer.pipeline, GST_STATE_NULL);
    gst_object_unref (GST_OBJECT (gstreamerPlayer.pipeline));
    g_source_remove (bus_watch_id);
    g_main_loop_unref (loop);

    //to more cleanup here
}

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

Re: interdependently seeking of multible filesources in pipeline

fub3000
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: interdependently seeking of multible filesources in pipeline

Nicolas Dufresne-5
Le lundi 18 décembre 2017 à 01:26 +0100, [hidden email] a
écrit :
> so there is no simple solution for that problem at all ?

Not really, it's quite complex to figure-out how to align these
randomly seek data into something that make sense. But it's doable for
sure, a project doing it:

  http://buzztrax.org/

regards,
Nicolas
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel