【问题标题】:how can I parse audio raw data recorder with gstreamer?如何使用 gstreamer 解析音频原始数据记录器?
【发布时间】:2014-05-02 11:19:15
【问题描述】:

我正在编写一个使用 gstreamer 从麦克风录制音频的 C 应用程序。 我希望能够解析该音频并显示该音频的可视化。

我有以下代码:

#include <gst/gst.h>
#include <glib.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;
}


void create_loop()
{
GMainLoop *loop;

GstElement *pipeline, *source, *sink;
GstBus *bus;
guint bus_watch_id;

 /* Initialisation */

loop = g_main_loop_new (NULL, FALSE);



/* Create gstreamer elements */
pipeline = gst_pipeline_new ("audio-player");
source   = gst_element_factory_make ("alsasrc",       "alsa-source");
sink     = gst_element_factory_make ("autoaudiosink", "audio-output");

if (!pipeline || !source  || !sink) {
 g_printerr ("One element could not be created. Exiting.\n");
 return;
}

g_object_set (G_OBJECT(source),"device","hw:3,0",NULL);

/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);

gst_bin_add_many (GST_BIN (pipeline),
                source,  sink, NULL);

gst_element_link (source, sink);
gst_element_set_state (pipeline, GST_STATE_PLAYING);


/* Iterate */
g_print ("Running...\n");
g_main_loop_run (loop);


/* Out of the main loop, clean up nicely */
g_print ("Returned, stopping playback\n");
gst_element_set_state (pipeline, GST_STATE_NULL);

g_print ("Deleting pipeline\n");
gst_object_unref (GST_OBJECT (pipeline));
g_source_remove (bus_watch_id);
g_main_loop_unref (loop);

}

int main(int argc, char** argv) {
  gst_init(&argc,&argv);
  create_loop();
  return 0;
}

正如您在我的代码中看到的,我创建了一个 alsasrc 和 autoaudiosink。我测试了,我可以 正确收听该设备。

我怎样才能在中间写一些东西来解析数据以创建可视化。

任何有关该问题的信息将不胜感激。

【问题讨论】:

    标签: c gstreamer


    【解决方案1】:

    您需要为您的 gsteamer 应用程序创建一个“插件”或 pad。 有一个关于如何创建一个 pad 的完整描述: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/chapter-building-boiler.html#section-boiler-source

    在大多数情况下,您需要使用 gobject 创建一个类。 https://developer.gnome.org/gobject/stable/

    方法如下:https://developer.gnome.org/gobject/stable/chapter-gobject.html

    你至少需要:

    /* Definition of structure storing data for this element. */
    typedef struct _GstMyFilter {
      GstElement element;
    
      GstPad *sinkpad, *srcpad;
    
      gboolean silent;
    
    } GstMyFilter;
    
    
    static GstStaticPadTemplate sink_factory =
    GST_STATIC_PAD_TEMPLATE (
      "sink",
      GST_PAD_SINK,
      GST_PAD_ALWAYS,
      GST_STATIC_CAPS ("ANY")
    );
    
    //... likewise for your src
    
    static void
    gst_my_filter_class_init (GstMyFilterClass * klass)
    {
      GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
    
      //...
      gst_element_class_set_static_metadata (element_klass,
        "An example plugin",
        "Example/FirstExample",
        "Shows the basic structure of a plugin",
            "your name <your.name@your.isp>");
    
      gst_element_class_add_pad_template (element_class,
        gst_static_pad_template_get (&src_factory));
      gst_element_class_add_pad_template (element_class,
        gst_static_pad_template_get (&sink_factory));
    }
    

    您还需要对插件进行说明

    static gboolean
    plugin_init (GstPlugin *plugin)
    {
      return gst_element_register (plugin, "my_filter",
                       GST_RANK_NONE,
                       GST_TYPE_MY_FILTER);
    }
    
    GST_PLUGIN_DEFINE (
      GST_VERSION_MAJOR,
      GST_VERSION_MINOR,
      my_filter,
      "My filter plugin",
      plugin_init,
      VERSION,
      "LGPL",
      "GStreamer",
      "http://gstreamer.net/"
    )
    
    
    static void
    gst_my_filter_init (GstMyFilter *filter)
    {
      /* pad through which data comes in to the element */
      filter->sinkpad = gst_pad_new_from_static_template (
        &sink_template, "sink");
      /* pads are configured here with gst_pad_set_*_function () */
    
    
      gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
    
      /* pad through which data goes out of the element */
      filter->srcpad = gst_pad_new_from_static_template (
        &src_template, "src");
      /* pads are configured here with gst_pad_set_*_function () */
    
      gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
    
      /* configure chain function on the pad before adding
       * the pad to the element */
      gst_pad_set_chain_function (filter->sinkpad,
          gst_my_filter_chain);
    
      /* properties initial value */
      filter->silent = FALSE;
    }
    

    而你的魔法被锁链

    static GstFlowReturn
    gst_my_filter_chain (GstPad    *pad,
                         GstObject *parent,
                 GstBuffer *buf)
    {
      GstMyFilter *filter = GST_MY_FILTER (parent);
    
      if (!filter->silent)
        g_print ("Have data of size %" G_GSIZE_FORMAT" bytes!\n",
            gst_buffer_get_size (buf));
    
      return gst_pad_push (filter->srcpad, buf);
    }
    
    static gboolean
    gst_my_filter_sink_event (GstPad    *pad,
                      GstObject *parent,
                      GstEvent  *event)
    {
      GstMyFilter *filter = GST_MY_FILTER (parent);
    
      switch (GST_EVENT_TYPE (event)) {
        case GST_EVENT_CAPS:
          /* we should handle the format here */
          break;
        case GST_EVENT_EOS:
          /* end-of-stream, we should close down all stream leftovers here */
          gst_my_filter_stop_processing (filter);
          break;
        default:
          break;
      }
    
      return gst_pad_event_default (pad, parent, event);
    }
    
    static GstFlowReturn
    gst_my_filter_chain (GstPad    *pad,
                 GstObject *parent,
                 GstBuffer *buf)
    {
      GstMyFilter *filter = GST_MY_FILTER (parent);
      GstBuffer *outbuf;
    
      outbuf = gst_my_filter_process_data (filter, buf);
      gst_buffer_unref (buf);
      if (!outbuf) {
        /* something went wrong - signal an error */
        GST_ELEMENT_ERROR (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
        return GST_FLOW_ERROR;
      }
    
      return gst_pad_push (filter->srcpad, outbuf);
    }
    

    用例:

    //... your code and elements init...
    
    //Creating your filter
    filter = gst_element_factory_make ("my_filter", "my_filter");
    
    //Adding it
    gst_bin_add_many (GST_BIN (pipeline), source, filter, sink, NULL);
    
    //Linking it
    if (!gst_element_link_many (source, filter, sink, NULL)) {
        g_print ("Failed to link one or more elements!\n");
        return -1;
    }
    
    //... here the rest of your code
    

    红利*有一个简单的例子:http://siilo.dyndns.org/wiki/index.php/Creating_a_Plugin_template

    【讨论】:

      【解决方案2】:

      appsink 元素允许您从管道中获取数据。

      您有三个选择:

      我认为第三种选择是最简单和更有效的。

      所以,只需将autoaudiosink 替换为appsink,注册回调并在其中处理您的数据。

      您可以在manual 中阅读有关appsrcappsink 的信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-01
        • 1970-01-01
        相关资源
        最近更新 更多