GStreamer应用程序——第一个应用程序

本章将总结您在前几章中学到的所有内容。它描述了一个简单的GStreamer应用程序的所有方面,包括初始化库、创建元素、将元素打包到管道中以及播放此管道。通过完成所有这些,您将能够构建一个简单的Ogg/Vorbis音频播放器。

Hello world

我们将创建一个简单的第一个应用程序,一个简单的Ogg/Vorbis命令行音频播放器。为此,我们将仅使用标准GStreamer组件。播放器将读取命令行上指定的文件。让我们开始吧!

我们在初始化GStreamer时了解到在您的应用程序中要做的第一件事是通过以下方式初始化GStreamer 调用gst_init ()。此外,请确保应用程序包括 gst/gst.h,以便正确定义所有函数名称和对象。使用 #include <gst/gst.h>

接下来,您将需要使用 gst_element_factory_make ()。对于Ogg/Vorbis音频播放器,我们将需要一个从磁盘读取文件的源元素。GStreamer包括名称为“filesrc”的元素。接下来,我们需要一些东西来解析文件并将其解码为原始音频。GStreamer有两个元素:第一个将Ogg流解析为基本流(视频, 音频)并被称为“oggdemux”。第二个是Vorbis音频解码器, 它被方便地称为“Vorbisdec”。由于“oggdemux”对于每个基本流创建动态 pads,您需要设置一个“pad-add”事件 oggdemux元素上的处理程序,就像你在动态(或有时)pads中学到的那样,链接 Ogg解复用器和Vorbis解码器元素在一起。最后,我们将还需要一个音频输出元素,我们将使用“autoaudiosink”,它自动检测您的音频设备。

最后要做的是将所有元素添加到容器中元素,GstPipeline,然后等到我们播放了整首歌。 我们之前已经学会了如何在Bins中向容器bin中添加元素,并且我们已经了解了Element States中的元素状态。我们还将附加一个消息处理程序到管道总线,以便我们可以检索错误并检测流结束。

现在让我们将所有代码添加在一起以获得我们的第一个音频播放器:

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


static void
on_pad_added (GstElement *element,
              GstPad     *pad,
              gpointer    data)
{
  GstPad *sinkpad;
  GstElement *decoder = (GstElement *) data;

  /* We can now link this pad with the vorbis-decoder sink pad */
  g_print ("Dynamic pad created, linking demuxer/decoder\n");

  sinkpad = gst_element_get_static_pad (decoder, "sink");

  gst_pad_link (pad, sinkpad);

  gst_object_unref (sinkpad);
}



int
main (int   argc,
      char *argv[])
{
  GMainLoop *loop;

  GstElement *pipeline, *source, *demuxer, *decoder, *conv, *sink;
  GstBus *bus;
  guint bus_watch_id;

  /* Initialisation */
  gst_init (&argc, &argv);

  loop = g_main_loop_new (NULL, FALSE);


  /* Check input arguments */
  if (argc != 2) {
    g_printerr ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]);
    return -1;
  }


  /* Create gstreamer elements */
  pipeline = gst_pipeline_new ("audio-player");
  source   = gst_element_factory_make ("filesrc",       "file-source");
  demuxer  = gst_element_factory_make ("oggdemux",      "ogg-demuxer");
  decoder  = gst_element_factory_make ("vorbisdec",     "vorbis-decoder");
  conv     = gst_element_factory_make ("audioconvert",  "converter");
  sink     = gst_element_factory_make ("autoaudiosink", "audio-output");

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

  /* Set up the pipeline */

  /* we set the input filename to the source element */
  g_object_set (G_OBJECT (source), "location", argv[1], 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);

  /* we add all elements into the pipeline */
  /* file-source | ogg-demuxer | vorbis-decoder | converter | alsa-output */
  gst_bin_add_many (GST_BIN (pipeline),
                    source, demuxer, decoder, conv, sink, NULL);

  /* we link the elements together */
  /* file-source -> ogg-demuxer ~> vorbis-decoder -> converter -> alsa-output */
  gst_element_link (source, demuxer);
  gst_element_link_many (decoder, conv, sink, NULL);
  g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), decoder);

  /* note that the demuxer will be linked to the decoder dynamically.
     The reason is that Ogg may contain various streams (for example
     audio and video). The source pad(s) will be created at run time,
     by the demuxer when it detects the amount and nature of streams.
     Therefore we connect a callback function which will be executed
     when the "pad-added" is emitted.*/


  /* Set the pipeline to "playing" state*/
  g_print ("Now playing: %s\n", argv[1]);
  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);

  return 0;
}

我们现在已经创建了一个完整的管道。我们可以如下可视化管道:

编译和运行helloworld. c

要编译helloworld示例,请使用:

gcc -Wall helloworld.c -o helloworld $(pkg-config --cflags --libs gstreamer-1.0)

GStreamer利用pkg-config来获取编译器和链接器 编译此应用程序所需的标志。

如果您正在运行非标准安装(即,你已经安装了 GStreamer来自源代码,而不是使用预构建的包), 确保PKG_CONFIG_PATH环境变量设置为 正确的位置($libdir/pkgconfig)。

在您使用GStreamer开发环境(即gst-env)的不太可能的情况下,您将需要使用libtools来构建hello world程序,如下所示:

libtool --mode=link gcc -Wall helloworld.c -o helloworld $(pkg-config --cflags --libs gstreamer-1.0)

您可以使用./helloworld file.ogg运行此示例应用程序。将file.ogg替换为您最喜欢的Ogg/Vorbis文件。

结论

我们的第一个例子到此结束。如您所见,设置管道是非常低级但功能强大。您将在本手册后面看到您如何可以使用更少的努力创建更强大的媒体播放器 高级接口。我们将在GStreamer应用程序的高级接口中讨论所有这些。但是,我们首先深入了解更高级的GStreamer内部结构。

从示例中应该很清楚,我们可以非常轻松地将“filesrc”元素替换为从网络读取数据的其他一些元素,或者与您的桌面环境更好地集成的其他一些数据源元素。此外,您可以使用其他解码器和解析器/解复用器来支持其他媒体类型。如果您运行的不是Linux,而是Mac OS X、Windows或FreeBSD,您可以使用另一个音频接收器,或者您可以改为使用文件链接将音频文件写入磁盘,而不是回放它们。通过使用音频卡源,您甚至可以进行音频捕获而不是播放。所有这些都显示了GStreamer元素的可重用性,这是它最大的优势。

helloworld. c 解析:

#include <gst/gst.h>  // GStreamer库的头文件
#include <glib.h>     // GLib库的头文件

// 处理GStreamer总线消息的回调函数
static gboolean
bus_call (GstBus     *bus,       // GStreamer总线
          GstMessage *msg,       // 接收到的消息
          gpointer    data)      // 用户数据(这里是主循环)
{
  GMainLoop *loop = (GMainLoop *) data;  // 将用户数据转换为GMainLoop类型

  // 根据消息类型进行处理
  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;  // 继续监听消息
}

// 动态链接pad的回调函数
static void
on_pad_added (GstElement *element,   // 被添加pad的元素
              GstPad     *pad,       // 新的pad
              gpointer    data)      // 用户数据(这里是解码器)
{
  GstPad *sinkpad;
  GstElement *decoder = (GstElement *) data;  // 将用户数据转换为GstElement类型(解码器)

  // 打印调试信息
  g_print ("Dynamic pad created, linking demuxer/decoder\n");

  // 获取解码器的sink pad
  sinkpad = gst_element_get_static_pad (decoder, "sink");

  // 将新创建的pad链接到解码器的sink pad
  gst_pad_link (pad, sinkpad);

  // 解除引用sink pad
  gst_object_unref (sinkpad);
}

// 主函数
int
main (int   argc,        // 参数数量
      char *argv[])      // 参数值
{
  GMainLoop *loop;       // 主循环

  GstElement *pipeline, *source, *demuxer, *decoder, *conv, *sink;  // GStreamer元素
  GstBus *bus;  // 用于消息的总线
  guint bus_watch_id;  // 总线监听ID

  // 初始化GStreamer
  gst_init (&argc, &argv);

  // 创建一个新的主循环
  loop = g_main_loop_new (NULL, FALSE);

  // 检查输入参数
  if (argc != 2) {
    g_printerr ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]);
    return -1;
  }

  // 创建GStreamer元素
  // 创建一个名为"audio-player"的GStreamer管道
  pipeline = gst_pipeline_new ("audio-player");
  // 创建一个文件源元素,用于读取音频文件
  source = gst_element_factory_make ("filesrc", "file-source");
  // 创建一个Ogg格式的解复用器,用于将Ogg文件中的音频和视频分离
  demuxer = gst_element_factory_make ("oggdemux", "ogg-demuxer");
  // 创建一个Vorbis解码器,用于将Vorbis编码的音频数据解码为原始音频数据
  decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder");
  // 创建一个音频转换器,用于将原始音频数据转换为其他格式
  conv = gst_element_factory_make ("audioconvert", "converter");
  // 创建一个自动音频输出设备,用于将解码后的音频数据发送到音频设备进行播放
  sink = gst_element_factory_make ("autoaudiosink", "audio-output");

  // 检查所有元素是否成功创建
  if (!pipeline || !source || !demuxer || !decoder || !conv || !sink) {
    g_printerr ("One element could not be created. Exiting.\n");
    return -1;
  }

  // 设置管道

  // 设置输入文件名到source元素
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);

  // 添加消息处理器到总线
  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, demuxer, decoder, conv, sink, NULL);

  // 将source元素链接到demuxer
  gst_element_link (source, demuxer);
  // 将decoder、converter和sink元素链接在一起
  gst_element_link_many (decoder, conv, sink, NULL);

  // 连接demuxer的pad-added信号到回调函数
  g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), decoder);

  // 打印正在播放的文件名
  g_print ("Now playing: %s\n", argv[1]);

  // 设置管道为“播放”状态
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  // 打印运行状态
  g_print ("Running...\n");

  // 运行主循环
  g_main_loop_run (loop);

  // 主循环退出后进行清理
  g_print ("Returned, stopping playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);  // 设置管道为NULL状态

  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));  // 解除引用管道
  g_source_remove (bus_watch_id);  // 移除总线监听
  g_main_loop_unref (loop);  // 解除引用主循环

  return 0;
}

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gstreamer应用程序开发中,要调用插件接口,可以按照以下步骤进行: 1. 创建GStreamer的pipeline:创建一个GstPipeline对象,作为音视频流的处理管道。 2. 加载插件:使用gst_element_factory_make()函数来加载所需的插件。该函数接受插件的类型和插件名称作为参数,并返回一个对应的GstElement对象。 3. 连接元素:使用gst_element_link()函数将不同的GstElement对象连接起来,形成数据流的处理链。通过将源元素和目标元素传递给该函数,可以将它们连接起来。 4. 配置插件属性:对需要的插件进行属性设置。可以使用gst_element_set_property()函数为插件设置属性值,也可以使用gst_element_get_property()函数获取属性的当前值。 5. 监听事件:为需要监听特定事件的插件添加相应的事件处理器。可以通过使用gst_element_add_event_probe()函数来添加事件探针,该函数将在触发特定事件时调用相应的回调函数。 6. 启动流媒体流:使用gst_element_set_state()函数将pipeline设置为播放状态,开始处理音视频数据流。 7. 处理数据:处理从插件接收到的数据。可以通过连接插件的src pad和sink pad来获取输入和输出数据,并在处理数据时使用对应的回调函数。 8. 监听信号:为需要监听信号的插件添加相应的信号处理函数。使用g_signal_connect()函数将信号与回调函数连接起来,在触发信号时执行相应的操作。 9. 控制流媒体流:使用gst_element_set_state()函数将pipeline设置为停止状态,结束数据的处理。 总之,调用插件接口的关键是正确配置和连接GstElement对象,以及使用适当的函数设置和获取属性值、添加事件探针和信号处理函数。以上步骤可以帮助开发者在gstreamer应用程序中调用插件接口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值