当前位置: 首页 > 工具软件 > GStreamer > 使用案例 >

gstreamer教程(一)-基本概念

夏长卿
2023-12-01

Gstreamer基础知识:

1、gstreamer基本概念

2、gstreamer初始化、组件、箱柜

3、gstreamer总线、衬垫、缓冲区、事件

为什么需要看gstreamer教程:deepstream是基于gstreamer开发的,大量引用了gstreamer中的插件或自编插件。没有gstreamer基础,很难看懂代码流程。看懂gstreamer后,一切变得豁然开朗~

1、序言

本章将从技术的角度来描述本手册的总体结构。

1.1、GStreamer是什么 ?

GStreamer是一个创建流媒体应用程序的框架。GStreamer的程序开发框架使得编写任意类型的流媒体应用程序成为了可能。 GStreamer并不受限于音频和视频处理, 它能够处理任意类型的数据流。管道设计的方法对于实际应用的滤波器几乎没有负荷, 它甚至可以用来设计出对延时有很高要求的高端音频应用程序。

GStreamer更像是一个播放器。但是它主要的优点却是在于:它的可插入组件能够很方便的接入到任意的管道当中。GStreamer框架是基于插件的, 有些插件中提供了各种各样的多媒体数字信号编译码器,也有些提供了其它的功能。所有的插件都能够被链接到任意的已经定义了的数据流管道中。 GStreamer的管道能够被GUI编辑器编辑, 能够以XML档来保存。这样的设计使得管道链接库的消耗变得非常少。

1.2、预备知识

GStreamer一直采用GObject编程模式。另外, 当你读完本手册后, 请读一下GStreamer Plugin Writer's Guide。 当然,你还需要关注一下其它的GStreamer文档。插件编写指南(Plugin WritersGuide)-支持c/js/python三种语言:

https://gstreamer.freedesktop.org/documentation/tutorials/index.html?gi-language=c

2、动机和目标

GStreamer 正是为解决 Linux 多媒体方面当前问题而设计的。

2.1、当前的问题

1)大量的代码复制

对于那些想要播放一个声音文件的 Linux 用户来说,他们必须搜索各种声音播放器来播放不同格式档,而在这些播放器中,大部分的都一遍又一遍地重复使用了相同的代码。

对于那些想在应用程序中嵌入视频剪辑的 Linux 开发人员来说,他们必须要用粗略的 hacks 来运行外部的视频播放器,因为没有一套可用的库提供给开发人员来创建可定制的播放器。

2)“一个目标”媒体播放器/媒体库

典型的 MPEG 播放器可以播放 MPEG 视频和音频,多数的播放器实现了完整的底层构造来达到他们的唯一目标:播放。没有一套有效的机制可以提供对于音频和视频数据过滤和效果处理,更没有制定在视频或音频数据中添加滤波器或特殊效果的任何规定。

如果你希望将 MPEG-2 视频流转为 AVI 档,那么你的最佳选择是,将所有的MPEG-2 译码算法从播放器分离出来,并复制到你的 AVI 编码器中,因为这类算法不能简单的在应用程序之间共享。开发人员曾经尝试着创建一个可以处理多种媒体类型的库,但由于缺乏通用的API,所以如何集成就成了重要的工作了。因为在集成的过程中,我们需要关注一些特殊的媒体类型(avi 文件, libmpeg2, ...),而集成这些媒体类型文件需要一个统一的接口。 GStreamer 允许将这些库与通用的 API 一起打包,这样就简化了集成和复用。

3)没有统一的插件管理机制

典型的播放器对于不同的媒体类型会有不同的插件,两个媒体播放器会实现各自不同的插件机制,所以编译码器不能方便的交换。每一个典型的媒体播放器的插管理件系统是具有其特定应用程序的需求。缺少统一的插件机制,已经严重阻碍了二进制编译码器的发展,因为没有一家公司希望将代码移植到不同的插件机制。GStreamer 当然也采用自己的插件系统,它为插件开发者提供了一个非常丰富的框架,从而保证这些插件能够广泛应用,并与其它插件能够无缝的交互。GStreamer 为插件提供的框架是非常灵活,它足以满足大多数插件的需求。

4)拙劣的用户感

因为上述问题的原因,使得应用程序开发人员将相当多的时间花在如何处理后端、插件机制等等问题上。从而耽误了大部分的项目时间,这样就常常导致后端和用户接口都只完成了一半,于是就导致了拙劣的用户感。

5)没有网络透明度的规定

当前还没有一个底层框架出现,来允许对网络透明媒体的操作。有趣的是,一个分布式的 MPEG 编码器能够复制非分布式编码器的相同的算法。并没有关于使用 GNOME 和 KDE 桌面平台的技术的规定被制定出来,因为GNOME 和 KDE 桌面平台本身还在改进和完善,所以很难将多媒体恰当地集成到很多用户的环境中。注意到GStreamer还提供很多种方法,这些方法提供将GSreamer与不同的桌面系统进行集成(见附录里的集成一节),而这些方法往往都不是网络透明化。

GStreamer 内核在最底层没有采用网络透明技术,只是在顶层加了作为本地使用,这就是说,创建一个核心组件的包就变得比较容易了。 GStreamer 允许管道在 TCP协议上分离,使用 tcp 插件来实现 GStreamer 数据协议, 这个被包含在 gst-plugins模块,目录 gst/tcp。

2.2、设计目标

我们将阐述在 GStreamer 开发中的目标:

1)结构清晰且威力强大

GStreamer 提供一套清晰的接口给以下一些开发人员:

• 希望构建媒体管道的应用程序员。程序员可以使用一系列强有利的工具来创建媒体管道,而不用去写一行代码,从而使得复杂的媒体控制变得非常简单。

• 插件程序员。GStreamer 向插件程序员提供了简洁而简单的 API 来创建self-plugin(自包含)插件,同时还集成了大量的调试和跟踪机制和工具。GStreamer 也提供了一系列现实例子。

2)面向物件的编程思想

GStreamer 是依附于 GLib 2.0 对象模型的,熟悉 GLib 或者旧版本的 GTK+的程序员对 GStreamer 将会驾轻就熟。GStreamer 采用了信号与对象属性的机制。所有对象的属性和功能都能在运行态被查询。GStreamer 与 GTK+的编程方法非常相似,需要对象模型,对象所有(ownership ofobjects),参考计算(reference counting)...

3)灵活的可扩展性能

所有的 GStreamer 对象都可以采用 GObject 继承的方法进行扩展。所有的插件都可以被动态装载,可以独立的扩展或升级。

4)支持插件以二进制形式发布

作为共享库发布的插件能够在运行态直接加载,插件的所有属性可以由 GObject属性来设置,而无需(事实上决不)去安装插件的头档。我们更多的关注在插件能够独立化,运行的时候还需要很多与插件相关的因素。

5)高性能

高性能主要体现在:

• 使用 GLib的 g_mem_chunk和非模块化分配算法使得内存分配尽可能最小。

插件之间的连接非常轻型(light-weight)。数据在管道中的传递使用最小的消耗,管道中插件之间的数据传递只会涉及指针废弃。

• 提供了一套对目标内存直接进行操作的机制。例如,插件可以向 X server共享的内存空间直接写数据,缓冲区也可以指向任意的内存,如声卡的内部硬件缓冲区。

• refcounting 和写拷贝将 memcpy 减少到最低。子缓冲区有效地将缓冲区分离为易于管理的块。

• 使用线程联合(cothreads)减少线程消耗。线程联合(cothreads)是简单又高速的方法来切换子程序,作为衡量最低消耗 600 个 cpu 周期的标准。

• 使用特殊的插件从而支持硬件加速。

• 采用带有说明的插件注册,这样的话只在实际需要使用该插件才会去装载。

• 所有的判断数据都不用互斥锁。

6)核心库与插件(core/plugins)分离

GStreamer 内核的本质是 media-agnostic,我们了解的仅仅是字节和块,以及包含基本的组件,GStreamer 内核的强大功能甚至能够实现底层系统工具,像 cp。所有的媒体处理功能都是由插件从外部提供给内核的,并告诉内核如何去处理特定的媒体类型。

7)为多媒体数字信号编译码实验提供一个框架

GStreamer成为一个简单的框架,编译码器的开发人员可以试验各种不同的算法,提高开源多媒体编译码器开发的速度,如Theora and Vorbis。

3、基础概念介绍

本章将介绍GStreamer的基本概念。理解这些概念对于你后续的学习非常重要,因为后续深入的讲解我们都假定你已经完全理解了这些概念。

3.1、组件(Elements)

组件(element)是GStreamer中最重要的概念。你可以通过创建一系列的组件(Elements), 并 把 它 们 连 接 起 来 , 从 而 让 数 据 流 在 这 个 被 连 接 的 各 个 组 件(Elements)之间传输。 每个组件(Elements)都有一个特殊的函数接口,对于有些组件(Elements)的函数接口它们是用于能够读取文件的数据,译码文件数据的。而有些组件(Elements)的函数接口只是输出相应的数据到具体的设备上(例如,声卡设备)。你可以将若干个组件(Elements)连接在一起,从而创建一个管道(pipeline)来完成一个特殊的任务,例如,媒体播放或者录音。 GStreamer已经默认安装了很多有用的组件(Elements),通过使用这些组件(Elements)你能够构建一个具有多种功能的应用程序。当然,如果你需要的话,你可以自己编写一个新的组件(Elements)。对于如何编写组件(Elements)的话题在GStreamer PluginWriter's Guide中有详细的说明。

组件:封装的最小功能模块,可以是读取文件、译码、也可以是输出之类的功能。自己编写组件可参考文档:

插件编写指南(Plugin WritersGuide)-支持c/js/python三种语言:

https://gstreamer.freedesktop.org/documentation/tutorials/index.html?gi-language=c

3.2、箱柜(Bins)和管道(pipelines)

箱柜(Bins)是一个可以装载组件(element)的容器。管道(pipelines)是箱柜(Bins)的一个特殊的子类型,管道(pipelines)可以操作包含在它自身内部的所有组件(element)。因为箱柜(Bins)本身又是组件(element)的子集,所以你能够象操作普通组件(element)一样的操作一个箱柜(Bins), 通过这种方法可以降低你的应用程序的复杂度。你可以改变一个箱柜(Bins)的状态来改变箱柜(Bins)内部所有组件(element)的状态。箱柜(Bins)可以发送总线消息(bus messages)给它的子集组件(element)(这些消息包括:错误消息(error messages),卷标消息(tag messages),EOS消息(EOS messages))。

箱柜:

1)装在组件的容器;

2)是组件的子集,与组件操作方法一样;

3)改变一个箱柜(Bins)的状态来改变箱柜(Bins)内部所有组件(element)的状态;

4)箱柜可以发送总线消息(bus messages)给它的子集组件。

管道(pipeline)是高级的箱柜(Bins)。当你设定管道的暂停或者播放状态的时候,数据流将开始流动,并且媒体数据处理也开始处理。一旦开始,管道将在一个单独的线程中运行,直到被停止或者数据流播放完毕。

管道:

特殊箱柜,设置管道的暂停或播放状态,数据开始暂停或流动,在一个单独的线程中运行。

3.3、衬垫(Pads)

衬垫(Pads)在GStreamer中被用于多个组件的链接,从而让数据流能在这样的链接中流动。一个衬垫(Pads)可以被看作是一个组件(element)插座或者端口,组件(element)之间的链接就是依靠着衬垫(Pads)。衬垫(Pads)有处理特殊数据的能力:一个衬垫(Pads)能够限制数据流类型的通过。链接成功的条件是:只有在两个衬垫(Pads)允许通过的数据类型一致的时候才被建立。数据类型的设定使用了一个叫做caps negotiation的方法。数据类型被为一个GstCaps变数所描述。

下面的这个比喻可能对你理解衬垫(Pads)有所帮助。一个衬垫(Pads)很象一个物理设备上的插头。例如一个家庭影院系统。一个家庭影院系统由一个放大器(amplifier),一个DVD机,还有一个无声的视频投影组成。我们需要连接DVD机到功放(amplifier),因为两个设备都有音频插口;我们还需要连接投影机到DVD机上,因为两个设备都有视频处理插口。但我们很难将投影机与功放(amplifier)连接起来,因为他们之间处理的是不同的插口。GStreamer衬垫(Pads)的作用跟家庭影院系统中的插口是一样的。

对于大部分情况,所有的数据流都是在链接好的元素之间流动。数据向组件(element)以外流出可以通过一个或者多个 source 衬垫(Pads),组件(element)接受数据是通过一个或者多个sink 衬垫(Pads)来完成的。Source组件(element)和sink组件(element)分别有且仅有一个 sink 衬垫(Pads)或者source 衬垫(Pads)。数据在这里代表的是缓冲区(buffers) (GstBuffer对象描述了数据的缓冲区(buffers)的信息)和事件(events) (GstEvent对象描述了数据的事件(events)信息)。

衬垫:组件的接口。

传送门:deepstream系列文章分类目录整理

 类似资料: