Lucian Georgescu
Lucian Georgescu

Reputation: 15

Convert gstreamer command to C code

I have a basic gstreamer command for playing audio stream received from network:

gst-launch-1.0 tcpserversrc host=127.0.0.1 port=5000 ! decodebin ! audioconvert ! alsasink

I tried to convert it to a C program, but when I'm running it I get "Internal data flow error".

#include <gst/gst.h>


static gboolean bus_call (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_free (debug);

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

      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }

  return TRUE;
}


gint main (gint   argc, gchar *argv[])
{
  GMainLoop *loop;
  GstElement *pipeline, *src, *dec, *conv, *sink;
  GstBus *bus;

  /* init GStreamer */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* setup */
  pipeline = gst_pipeline_new ("pipeline");

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  src = gst_element_factory_make ("tcpserversrc", "source");
  g_object_set (G_OBJECT (src), "host", "127.0.0.1",NULL);
  g_object_set (G_OBJECT (src), "port", 5000 ,NULL);


  dec = gst_element_factory_make ("decodebin", "decoder");
  conv = gst_element_factory_make ("audioconvert", "aconv");
  sink = gst_element_factory_make ("alsasink", "sink");

  gst_bin_add_many (GST_BIN (pipeline), src, dec, conv, sink, NULL);

  gst_element_link (src, dec);
  gst_element_link (dec, conv);
  gst_element_link (conv, sink);

  /* run */

  gst_element_set_state (pipeline, GST_STATE_PLAYING);
  g_main_loop_run (loop);

  /* cleanup */
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (pipeline));

  return 0;
}

Here is the command which I'm using to test the server:

gst-launch-1.0 filesrc location="file.wav" ! tcpclientsink host=127.0.0.1 port=5000

Thanks.

Upvotes: 0

Views: 2035

Answers (1)

Yasushi Shoji
Yasushi Shoji

Reputation: 4282

Because decodebin's src pad is a dynamic (sometimes) pad. You have to connect decodebin to audioconvert when decodebin got its source pad.

You can see it with gst-inspect-1.0:

$ gst-inspect-1.0 decodebin
  :
  :
Pad Templates:
  SRC template: 'src_%u'
    Availability: Sometimes
    Capabilities:
      ANY
  :
  :

Add a callback function for pad-added to decodebin and link to audioconvert in the callback. A required change is basically this:

--- orig.c  2017-01-18 13:35:50.434605255 +0900
+++ new.c   2017-01-18 14:04:16.428847528 +0900
@@ -31,6 +31,21 @@
   return TRUE;
 }

+static void cb_new_pad (GstElement *element, GstPad *pad, gpointer data)
+{
+  gchar *name;
+  GstElement *other = data;
+
+  name = gst_pad_get_name (pad);
+  g_print ("A new pad %s was created for %s\n", name, gst_element_get_name(element));
+  g_free (name);
+
+  g_print ("element %s will be linked to %s\n",
+           gst_element_get_name(element),
+           gst_element_get_name(other));
+  gst_element_link(element, other);
+}
+
 gint main (gint   argc, gchar *argv[])
 {
   GMainLoop *loop;
@@ -59,9 +74,13 @@
   gst_bin_add_many (GST_BIN (pipeline), src, dec, conv, sink, NULL);

   gst_element_link (src, dec);
-  gst_element_link (dec, conv);
   gst_element_link (conv, sink);

+  /* you don't link them here */
+  /* gst_element_link (dec, conv); */
+  /* add call-back, instead */
+  g_signal_connect (dec, "pad-added", G_CALLBACK (cb_new_pad), conv);
+
   /* run */
   gst_element_set_state (pipeline, GST_STATE_PLAYING);
   g_main_loop_run (loop);

Here is a link to a working code.

BTW, you don't have to do it by yourself but let gst_parse_launch() handle all of the above.

int main(int argc, char *argv[])
{
    GstElement *pipeline;
    GError *err = NULL;
    GstBus *bus;
    GMainLoop *loop;

    gst_init(&argc, &argv);

    loop = g_main_loop_new(NULL, FALSE);
    pipeline = gst_parse_launch("tcpserversrc host=127.0.0.1 port=5000 ! decodebin ! audioconvert ! alsasink", &err);
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    bus = gst_element_get_bus(pipeline);
    gst_bus_add_watch (bus, bus_call, loop);
    g_main_loop_run(loop);

    return 0;
}

There are some questions about dynamic pads on stackoverflow:

Upvotes: 2

Related Questions