前言

  gtreamer播放ogg音频文件的流程讲解。

 

Ogg

  Ogg全称是OGGVobis(oggVorbis)是一种音频压缩容器格式。Ogg格式不仅是一个高效的容器格式,它还融合了Vorbis、Theora和Speex等多种媒体压缩技术。Ogg不仅是一个容器格式,更融合了多种媒体压缩技术,如Vorbis(音频)、Theora(视频)和Speex(语音)。值得一提的是,我们之前介绍的高保真FLAC格式也可以被纳入Ogg框架之中。因此,我们所探讨的Ogg,通常指的是Ogg与Vorbis的组合。

 

GStreamer

  GStreamer是一个非常强大和通用的框架,用于创建流媒体应用程序。GStreamer框架的许多优点来自其模块化:GStreamer可以无缝地整合新的插件模块。但是,由于模块化和强大的功能往往以更高的复杂性为代价,编写新的应用程序并不总是那么容易。
  GStreamer分为:

  • gstreamer:核心包
  • gst-plugins-base:一组基本的示例元素
  • gst-plugins-good:LGPL下的一组高质量插件
  • gst-plugins-ugly:一组可能造成分发问题的高质量插件
  • gst-plugins bad:一组需要更高质量的插件
  • gst-libav:一组封装libav进行解码和编码的插件
  • 其他几个包
 

GStreamer架构图

  

 

探测本地组件

  使用gst-inspect-1.0可以检测到本地安装了哪些模块,如下:
  

 

播放ogg文件

步骤一:初始化gst

  

步骤二:创建消息循环

  

步骤三:创建所有需要的组件

  

步骤四:设置本地文件路径属性

  

步骤五:添加一个检测管道消息处理

  

步骤六:将组件都放入管道

  

步骤七:连接组件

  连接组件后,这里分割器分割一个流就会回调产出一个pad,要对pad在创建时动态关联解码器,解码器才到sink播放。
  

步骤八:开始运行

  

步骤九:开始播放,进去循环阻塞

  

步骤十:清理资源

  

 

Demo源码

/******************** test003 ********************/
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; // 现在可以将这个焊盘与vorbis解码器接收焊盘连接起来
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);
} void test003PlayOggDemo(int *argc, char **argv[])
{
char const * fileName = "/home/yang/work/test/1.ogg";
// char const * fileName = "/home/yang/work/test/1.mp3";
// char const * fileName = "/home/yang/work/test/1.mov"; GMainLoop *loop; GstElement *pipeline, *source, *demuxer, *decoder, *conv, *sink;
GstBus *bus;
guint bus_watch_id; // 步骤一:初始化gst
gst_init (argc, argv); // 步骤二:创建gmain消息循环
loop = g_main_loop_new (NULL, FALSE); // 步骤三:创建组建
pipeline = gst_pipeline_new ("audio-player");
// 组件类型 组件唯一名称
source = gst_element_factory_make ("filesrc", "file-source");
demuxer = gst_element_factory_make ("oggdemux", "ogg-demuxer");
// demuxer = gst_element_factory_make ("mpeg123", "mp3-demuxer"); // mp3: 不用分割,所以步骤不一样
// demuxer = gst_element_factory_make ("splitmuxsink", "mov-demuxer");// mov: 分割格式不一样,要修改代码,没改了
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;
} // 步骤四:设置本地原的文件属性“location”,文件名
g_object_set (G_OBJECT (source), "location", fileName, NULL); // 步骤五:添加一个消息处理程序
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
// 消息回调函数原型:gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref(bus); // 步骤六:将所有的组件添加到管道 */
// file-source | ogg-demuxer | vorbis-decoder | converter | alsa-output
gst_bin_add_many(GST_BIN(pipeline),
source, demuxer, decoder, conv, sink, NULL); // 步骤七:链接组件
// file-source -> ogg-demuxer ~> vorbis-decoder -> converter -> alsa-output
gst_element_link (source, demuxer);
gst_element_link_many (decoder, conv, sink, NULL);
// 注意1:这里demuxer的pad-added消息会出发on_pad_added回调函数
// 注意2:demuxer是解码器,解码出来有多个流,每个流会产出一个pad,然后动态链接
// 注意2:在这个回调函数里面,会把added的焊盘关联到decoder上,就实现了demuxer->decoder的链接
// 注意3:
g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), decoder);
/* 请注意,解复用器将动态链接到解码器。原因是Ogg可能包含各种流(例如音频和视频)。
* 当解复用器检测到流的数量和性质时,它将在运行时创建源焊盘。
* 因此,我们连接了一个回调函数,该函数将在发出“添加焊盘”时执行
*/ // 步骤八:设置状态运行
g_print ("Now playing: %s\n", fileName);
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);
g_print ("Deleting pipeline\n");
gst_object_unref(GST_OBJECT (pipeline));
g_source_remove(bus_watch_id);
g_main_loop_unref(loop);
}
 

工程模板v1.2.0

  

 

入坑

入坑一:创建mp3分流器是吧

问题

  举一反三,试一试mp3分流器,结果失败:
  

尝试

  使用gst-inspect-1.0可以检测到本地安装了哪些模块,举例部分如下:
  

  继续扫描,可以看到:
  

  会扫描,然后又刷这些,定期更新吧,我们查找下ogg:
  

  那么找一下mp3:
  

  测试:
  

解决

  未尝试,mp3就是一个文件格式,不是封装容器,不需要分割器进行动态pad关联。其管道过程不一样。
  

GStreamer开发笔记(七):gstreamer播放ogg详解的更多相关文章

  1. ArcGIS API for javascript开发笔记(六)——REST详解及如何使用REST API调用GP服务

    感谢一路走来默默支持和陪伴的你~~~ -------------------欢迎来访,拒绝转载-------------------- 一.Rest API基础 ArcGIS 平台提供了丰富的REST ...

  2. Android开发笔记之: 数据存储方式详解

    无论是神马平台,神马开发环境,神马软件程序,数据都是核心.对于开发平台来讲,如果对数据的存储有良好的支持,那么对应用程序的开发将会有很大的促进作用.总体的来讲,数据存储方式有三种:一个是文件,一个是数 ...

  3. python开发笔记之zip()函数用法详解

    今天分享一篇关于python下的zip()函数用法. zip()是Python的一个内建函数,它接受一系列可迭代的对象作为参数,将对象中对应的元素按顺序组合成一个tuple,每个tuple中包含的是原 ...

  4. Android 高级UI设计笔记07:RecyclerView 的详解

    1. 使用RecyclerView       在 Android 应用程序中列表是一个非常重要的控件,适用场合非常多,如新闻列表.应用列表.消息列表等等,但是从Android 一出生到现在并没有非常 ...

  5. IP地址和子网划分学习笔记之《IP地址详解》

    2018-05-03 18:47:37   在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. ...

  6. [ 转载 ] Java开发中的23种设计模式详解(转)

    Java开发中的23种设计模式详解(转)   设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...

  7. “全栈2019”Java第七十章:静态内部类详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. 最锋利的Visual Studio Web开发工具扩展:Web Essentials详解

    原文:最锋利的Visual Studio Web开发工具扩展:Web Essentials详解 Web Essentials是目前为止见过的最好用的VS扩展工具了,具体功能请待我一一道来. 首先,从E ...

  9. Android进阶笔记:Messenger源码详解

    Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...

  10. 【笔记】Pandas分类数据详解

    [笔记]Pandas分类数据详解 Pandas  Pandas分类数据详解|轻松玩转Pandas(5) 参考:Pandas分类数据详解|轻松玩转Pandas(5)

随机推荐

  1. msvcp110.dll丢失修复 按我的方法来,保证修复!

    方法很简单,msvcp110.dll丢失,安装Microsoft Visual C++ 2012 Redistributable Package就可以,我把修复程序的链接放下面.链接地址: 链接:ht ...

  2. IvorySQL v4 逻辑复制槽同步功能解析:高可用场景下的数据连续性保障

    功能简介 IvorySQL v4 基于 PostgreSQL 17,引入了逻辑复制槽同步至热备份数据库的功能.这一改进有效解决了旧版本中主数据库与备份数据库切换后逻辑复制中断的问题.对于那些追求数据高 ...

  3. 主存的扩展及其与CPU的连接——字扩展

    一块芯片的容量为\(2^{18}B\),而该CPU需要的容量为:\(2^{地址总线位宽}\)=\(2^{21}B\),所以需要8片该芯片来扩展. 由于CPU由21个地址引脚,芯片只有18个地址引脚,C ...

  4. Cursor:一个让程序员“失业”的AI代码搭子

    Tab,Tab,再来一次 Tab 在当今AI工具横飞的时代,用一款好用的AI编码工具会让你的效率成倍增长. 上篇我们刚试过国内的Trae工具写了一个简单的demo,表现的中规中矩吧.Trae可以尝试写 ...

  5. 【自用】restful api 常用状态码

    GET(SELECT):从服务器取出资源(一项或多项). POST(CREATE):在服务器新建一个资源. PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源). PATCH(UPD ...

  6. 没错,Go 语言的函数参数没有引用传递方式

    这篇文章想浅浅地讲解 Go 语言函数参数传递的值拷贝. 一句话观点 Go语言中所有传递都是值传递,严格来说并不存在引用传递的概念.传递指针只是传递指针的值,并不是引用传递,只不过通过指针可以间接修改变 ...

  7. 在 ASP.NET Core 中编写高性能 Web API 的4个小技巧

    Web API 通常用来与外部模块进行通信.发送和接收数据,作为后端开发人员,应该把写出高性能的应用作为目标. 下面 4 个技巧是我在编写 Web API 的小技巧. 1 .大量数据使用分页查询 接口 ...

  8. 2025dsfz集训Day12: 斜率优化DP

    Day12:斜率优化DP 一次函数与斜率 斜率:表示一个直线倾斜程度.定义为和正方向水平轴的夹角的正切值. 经过两个点 \((x1, y1)\) 和 \((x2, y2)\) 的直线的斜率为 \(\f ...

  9. RK356X网口限速

    1. 参考资料 Linux 上的虚拟网络接口,主要要了解一下 IFB,对输入的流量进行整形 https://lyyao09.github.io/2020/06/13/linux/An-introduc ...

  10. 使用Tortoise-ORM和FastAPI构建评论系统

    title: 使用Tortoise-ORM和FastAPI构建评论系统 date: 2025/04/25 21:37:36 updated: 2025/04/25 21:37:36 author: c ...