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

news2024/11/24 12:04:46

本章将总结您在前几章中学到的所有内容。它描述了一个简单的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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1817518.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业的crm客户管理系统的部署方式,是选私有云部署,还是公有云部署?

随着&#xff0c;现代化企业的发展&#xff0c;企业在选型CRM客户管理系统后&#xff0c;通过会选一种部署方式&#xff0c;然后才将其与企业现有的管理系统对接&#xff0c;那么一般企业在部署CMR客户管理系统时&#xff0c;一般会选哪种部署方式呢&#xff1f;是私有云crm部署…

PHP在线生成查询产品防伪证书系统源码

源码介绍 PHP在线生成查询产品防伪证书系统源码&#xff0c;源码自带90套授权证书模板&#xff0c;带PSD公章模板&#xff0c;证书PSD源文件。 环境要求&#xff1a;PHPMYSQL&#xff0c;PHP 版本请使用PHP5.1 ~5.3。 图片截图 源码安装说明 1.上传所有文件至你的空间服务器…

大文件word生成的处理与解决策略

前言 对于简单word文档的生成导出&#xff0c;java已经有着很多技术来进行处理&#xff0c;在有着相对固定的格式样板下&#xff0c;采用word模板导出相对会是比较好的选择。但是当数据量且包含大量图片后&#xff0c;采用模板导出就显得无力了&#xff0c;模板的缺点是无法应…

iOS ReactiveCocoa MVVM

学习了在MVVM中如何使用RactiveCocoa&#xff0c;简单的写上一个demo。重点在于如何在MVVM各层之间使用RAC的信号来更方便的在各个层之间进行响应式数据交互。 demo需求&#xff1a;一个登录界面(登录界面只有账号和密码都有输入&#xff0c;登录按钮才可以点击操作)&#xff0…

主流3D视频编码技术

3D视频通过模拟人眼的立体视觉&#xff0c;使我们能够感受到深度和距离&#xff0c;提供了一种更加真实而富有沉浸感的视觉体验。长期以来&#xff0c;大量3D视频内容并没有使用专用的视频编码标准&#xff0c;而是使用通用的视频编码标准进行编码。主要的做法是将3D视频以SBS&…

安卓动画特效(帧动画、补间动画、属性动画、遮罩动画及滚动器)

本章介绍App开发中常见的动画特效技术&#xff0c;主要包括&#xff1a;如何使用帧动画实现电影播放效果&#xff0c;如何使用补间动画实现视图的4种基本状态变化&#xff0c;如何使用属性动画实现视图各种状态的动态变换效果&#xff0c;以及如何借助绘图层次与滚动器实现动画…

Javaweb04-Servlet技术2(HttpServletResponse, HttpServletRequest)

Servlet技术基础 HttpServletResponse对象 HttpServletResponce对象是继承ServletResponse接口&#xff0c;专门用于封装Http请求 HttpServletResponce有关响应行的方法 方法说明功能描述void setStatus(int stauts)用于设置HTTP响应消息的状态码&#xff0c;并生成响应状态…

Flutter- AutomaticKeepAliveClientMixin 实现Widget保持活跃状态

前言 在 Flutter 中&#xff0c;AutomaticKeepAliveClientMixin 是一个 mixin&#xff0c;用于给 State 类添加能力&#xff0c;使得当它的内容滚动出屏幕时仍能保持其状态&#xff0c;这对于 TabBarView 或者滚动列表中使用 PageView 时非常有用&#xff0c;因为这些情况下你…

【blender特效】卡通火焰

核心思想就是通过多个不同缩放尺寸的沃罗诺伊叠加&#xff0c;分别构成火焰的大型&#xff0c;中型和小型&#xff08;形状&#xff09;&#xff0c;最后通过自发光纹理实现火焰加亮。 用的是ev渲染&#xff0c;完全可以把噪音贴图都烘焙出来&#xff0c;自己改改shader就可以扔…

Python 越来越火爆

Python 越来越火爆 Python 在诞生之初&#xff0c;因为其功能不好&#xff0c;运转功率低&#xff0c;不支持多核&#xff0c;根本没有并发性可言&#xff0c;在计算功能不那么好的年代&#xff0c;一直没有火爆起来&#xff0c;甚至很多人根本不知道有这门语言。 随着时代的…

从深度嵌套的JSON结构中提取值

问题背景 在某些情况下&#xff0c;我们可能需要从深度嵌套的JSON结构中提取值。例如&#xff0c;给定以下JSON结构&#xff1a; {"foo_code": 404,"foo_rbody": {"query": {"info": {"acme_no": "444444","…

html是什么?http是什么?

html Html是什么&#xff1f;http是什么&#xff1f; Html 超文本标记语言&#xff1b;负责网页的架构&#xff1b; http(&#xff08;HyperText Transfer Protocol&#xff09;超文本传输协议&#xff1b; https&#xff08;全称&#xff1a;Hypertext Transfer Protocol …

数组还可以这样用!常用但不为人知的应用场景

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

NLP入门——数据预处理:子词切分及应用

BPE(Byte-Pair Encoding)算法 【西湖大学 张岳老师&#xff5c;自然语言处理在线课程 第十六章 - 4节】BPE&#xff08;Byte-Pair Encoding&#xff09;编码 如果有一个字符串aabaadaab&#xff0c;对其执行BPE算法 因为字符对aa出现频率最高&#xff0c;因此将其替换为码Z&…

开源-Docker部署Cook菜谱工具

开源-Docker部署Cook菜谱工具 文章目录 开源-Docker部署Cook菜谱工具介绍资源列表基础环境一、安装Docker二、配置加速器三、查看Docker版本四、拉取cook镜像五、部署cook菜谱工具5.1、创建cook容器5.2、查看容器运行状态5.3、查看cook容器日志 六、访问cook菜谱服务6.1、访问c…

Web端在线Stomp服务测试与WebSocket服务测试

Stomp服务测试 支持连接、发送、订阅、接收&#xff0c;可设置请求头、自动重连 低配置云服务器&#xff0c;首次加载速度较慢&#xff0c;请耐心等候 预览页面&#xff1a;http://www.daelui.com/#/tigerlair/saas/preview/lxbho9lkzvgc 演练页面&#xff1a;http://www.da…

设计模式-创建型-04-建造者模式

1、盖房项目需求 1&#xff09;需要建房子&#xff1a;这一过程为打桩、砌墙、封顶2&#xff09;房子有各种各样的&#xff0c;比如普通房&#xff0c;高楼&#xff0c;别墅&#xff0c;各种房子的过程虽然一样&#xff0c;但是要求不要相同的3&#xff09;请编写程序&#xf…

解决linux jenkins要求JDK版本与项目版本JDK不一致问题

背景–问题描述&#xff1a; 新入职公司&#xff0c;交接人说jenkins运行有问题&#xff0c;现在都是手动发布&#xff0c;具体原因让我自己看&#xff08;笑哭&#xff09;。我人都蒙了&#xff0c;测试环境都手动发布&#xff0c;那不是麻烦的要死&#xff01; 接手后&am…

bfs+枚举,CF666B - World Tour

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 Problem - 666B - Codeforces 二、解题报告 1、思路分析 数据量允许跑N次bfs预处理所有点的最短路&#xff0c;以及预处理到达每个点距离最远的3个点&#xff0c;以及每个点能够到达的最远的3个点 我们枚举…

计算机网络(5) ARP协议

什么是ARP 地址解析协议&#xff0c;即ARP&#xff08;Address Resolution Protocol&#xff09;&#xff0c;是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机&#xff0c;并接收返回消息&#xff0c;以此确定…