将 gstreamer 命令转换为 C 代码

标签 c gstreamer

我有一个基本的 gstreamer 命令,用于播放从网络接收的音频流:

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

我试图将其转换为 C 程序,但在运行时出现“内部数据流错误”。

#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;
}

这是我用来测试服务器的命令:

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

谢谢。

最佳答案

因为decodebin的src pad是a dynamic (sometimes) pad .当 decodebin 获得其源板时,您必须将 decodebin 连接到 audioconvert

您可以使用 gst-inspect-1.0 查看它:

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

pad-added添加回调函数到decodebin,并在回调中链接到audioconvert。所需的更改基本上是这样的:

--- 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);

这里是 a link to a working code .

顺便说一句,你不必自己做,而是让 gst_parse_launch()处理以上所有问题。

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;
}

stackoverflow上有一些关于dynamic pad的问题:

关于将 gstreamer 命令转换为 C 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41698656/

相关文章:

c - 运行在普通内核上、使用普通调度程序的普通进程进入一个事件周期的平均时间是多少?

rust - 为 gstreamer crate 0.14 编写 rust/gstreamer 插件需要哪些依赖项?

streaming - 限制 gstreamer 管道吞吐量以模拟实时源

C递归返回2个值

Ubuntu 14.04 Gstreamer 自动视频接收器

go - gstreamer网络摄像头vp9enc滞后

audio - gstreamer管道混合了三个音频源?

c - libattr 的文档在哪里?

我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?

c - 堆栈上声明的最大允许大小是多少?