GStreamer基础概念篇【详细】

文章目录

什么是Gstreamer?

从历史的角度来看, Linux在多媒体方面已经远远落后于其他的操作系统。 Microsoft's Windows 和Apple's MacOS它们对多媒体设备、多媒体创作、播放和实时处理等方面已经有了很好的支持。另一方面, Linux对多媒体应用的综合贡献比较少,这也使得Linux很难在专业级别的软件上与MS Windows和MacOS去竞争。

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

GStreamer 是一个非常强大而且通用的流媒体应用程序框架。

其基本设计思想来自于俄勒冈(Oregon)研究生学院有关视频管道的创意, 同时也借鉴了DirectShow的设计思想。

GStreamer并不受限于音频和视频处理, 它能够处理任意类型的数据流。GStreamer已经支持很多格式的文件了, 包括: MP3、 Ogg/Vorbis、MPEG-1/2、 AVI、 Quicktime、 mod等等。

主要的优点在于: 它的可插入组件能够很方便的接入到任意的管道当中。这个优点使得利用GStreamer编写一个万能的可编辑音视频应用程序成为可能。

GStreamer框架是基于插件的, 有些插件中提供了各种各样的多媒体数字信号编解码器,也有些提供了其他的功能。所有的插件都能够被链接到任意的已经定义了的数据流管道中。

为什么使用Gstreamer?它的优点?

  1. 结构清晰且威力强大:GStreamer提供一套清晰的接口,无论是构建媒体管道的应用程序员还是插件程序员,均可以方便的使用这些API。
  2. 面向对象的编程思想:GStreamer是依附于GLib 2.0对象模型的,采用了信号与对象属性的机制。
  3. 灵活的可扩展性能:所有的GStreamer对象都可以采用GObject继承的方法进行扩展。所有的插件都可以被动态装载,可以独立的扩展或升级。
  4. 核心库与插件(core/plugins)分离:所有的媒体处理功能都是由插件从外部提供给内核的,并告诉内核如何去处理特定的媒体类型

Gstreamer总览

1、元件

元件(Element)是GStreamer中最重要的概念。

可以通过创建一系列的元件,并把它们连接起来,从而让数据流在这个被连接的各个元件之间传输。每个元件都有一个特殊的函数接口,对于有些元件的函数接口它们是用于能够读取文件的数据,解码文件数据的。而有些元件的函数接口只是输出相应的数据到具体的设备上(例如:声卡设备)。

可以将若干个元件连接在一起,从而创建一个管道(pipeline)来完成一个特殊的任务,例如,媒体播放或者录音。

对程序员来说, GStreamer中最重要的一个概念就是GstElement对象。元件是构建一个媒体管道的基本块。每一个元件都对应一个GstElement。任何一个解码器编码器、分离器、视频/音频输出部件实际上都是一个GstElement对象。

元件分类

源元件:


源元件为管道产生数据,比如从磁盘或者声卡读取数据。下图是形象化的源元件,我们总是将源衬垫(source pad)画在元件的右端。

源元件不接收数据,仅产生数据。你可从上图中明白这一点,因为上图仅有一个源衬垫(右端 )。

过滤/类过滤元件:

过滤器(Filters)以及类过滤元件(Filter-like elements)都同时拥有输入和输出衬垫。他们对从输入衬垫得到的数据进行操作,然后将数据提供给输出衬垫。音量元件(filter) 、视频转换器(convertor) 、 Ogg分流器或者Vorbis解码器都是这种类型的元件。

类过滤元件可以拥有任意个的源衬垫或者接收衬垫。

像解码器只有一个源衬垫及一个接收衬垫。而视频分流器可能有一个接收衬垫以及多个源衬垫,每个接收衬垫对应一种元数据流。

形象化的过滤元件

这个特殊的元件同时拥有源衬垫和接收衬垫。接收输入数据的接收衬垫在元件的左端,源衬垫在右端。

 形象化的拥有多个输出的过滤元件

它有多个输出衬垫。 Ogg分流器是个很好的实例。因为Ogg流包含了视频和音频。一个源衬垫可能包含视频元数据流,另一个则包含音频元数据流。

接收元件:

接收元件是媒体管道的末端,它接收数据但不产生任何数据。写磁盘、利用声卡播放声音以及视频输出等都是由接收元件实现的。下图显示了接收元件。
 

元件之间的连接

通过将一个源元件,零个或多个类过滤元件,和一个接收元件链接在一起,你可以建立起一条媒体管道。数据将在这些元件间流过。这是 GStreamer中处理媒体的基本概念。

把上述过程想象成一个简单的Ogg/Vorbis音频解码器。源元件从磁盘读取文件。第二个元件就是Ogg/Vorbis 音频解码器。最终的接收元件是你的声卡,它用来播放经过解码的音频数据。

注意:在链接不同的元件之前,你需要确保这些元件都被加在同一个箱柜中,因为将一个元件加载到一个箱柜中会破坏该元件已存在的一些链接关系。同时,你不能直接链接不在同一箱柜或管道中的元件。

元件状态

一个元件在被创建后,它不会执行任何操作。所以你需要改变元件的状态,使得它能够做某些事。Gstreamer中,元件有四种状态,每种状态都有其特定的意义。这四种状态为:

  1. GST_STATE_NULL: 默认状态。该状态将会回收所有被该元件占用的资源。
  2. GST_STATE_READY: 准备状态。元件会得到所有所需的全局资源,这些全局资源将被通过该元件的数据流所使用。
  3. GST_STATE_PAUSED: 在这种状态下,元件已经对流开始了处理,但此刻暂停了处理。因此该状态下元件可以修改流的位置信息,读取或者处理流数据,以及一旦状态变为 PLAYING,流可以重放数据流。这种情况下,时钟是禁止运行的。
  4. GST_STATE_PLAYING: PLAYING 状态除了当前运行时钟外,其它与 PAUSED 状态一模一样。你可以通过函数gst_element_set_state()来改变一个元件的状态。你如果显式地改变一个元件的状态,GStreamer可能会使它在内部经过一些中间状态。例如你将一个元件从 NULL状态设置为 PLAYING 状态,GStreamer在其内部会使得元件经历过 READY 以及 PAUSED 状态。 当处于GST_STATE_PLAYING 状态,管道会自动处理数据。它们不需要任何形式的迭代。

状态迁移只能在相邻的状态里迁移,也就是说,你不能从NULL一下跳到PLAYING。你必须经过READY和PAUSED状态。如果你把pipeline设到PLAYING状态, GStreamer自动会经过中间状态的过渡。

2、箱柜(Bins)

箱柜(Bins)是一个可以装载元件(element)的容器。

同时箱柜本身也是一种元件,所以你能够象操作普通元件一样的操作一个箱柜,可以改变一个箱柜的状态来改变箱柜内部所有元件的状态。

箱柜可以发送总线消息给它的子集元件 (这些消息包括:错误消息(error messages),标签消息(tag messages),EOS消息(EOS messages))。

3、管道(pipeline)

管道(pipeline)是箱柜(Bin)的一个特殊的子类型,管道可以操作包含在它自身内部的所有元件。

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

4、总线(Bus)

总线是一个简单的系统,它采用自己的线程机制将一个管道线程的消息分发到一个应用程序当中。每一个管道默认包含一个总线,所以应用程序不需要再创建总线。应用程序只需要在总线上设置一个类似于对象的信号处理器的消息处理器。当主循环运行的时候,总线将会轮询这个消息处理器是否有新的消息,当消息被采集到后,总线将呼叫相应的回调函数来完成任务。

5、消息类型(Message types)

  1. 应用程序至少要处理错误消息并直接的反馈给用户。
  2.  错误、警告和消息提示:它们被各个元件用来在必要的时候告知用户现在管道的状态。错误信息表明有致命的错误并且终止数据传送。错误应该被修复,这样才能继续管道的工作。警告并不是致命的,但是暗示有问题存在。
  3. 数据流结束(End-of-stream)提示:当数据流结束的时候,该消息被发送。管道的状态不会改变,但是之后的媒体操作将会停止。
  4. 状态转换(State-changes):当状态成功的转换时发送该消息。
  5. 缓冲(Buffering):当缓冲网络数据流时此消息被发送

6、衬垫(Pads)

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

形象化的过滤元件

这个特殊的元件同时拥有源衬垫和接收衬垫。接收输入数据的接收衬垫在元件的左端,源衬垫在右端。
 

形象化的拥有多个输出的过滤元件


它有多个输出衬垫。 Ogg分流器是个很好的实例。因为Ogg流包含了视频和音频。一个源衬垫可能包含视频元数据流,另一个则包含音频元数据流。

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

衬垫的特性---数据导向

  1. 一个衬垫的类型由2个特性决定:它的数据导向(direction)以及它的时效性(availability)。
  2. Gstreamer定义了2种衬垫的数据导向:源衬垫以及接收衬垫。衬垫的数据导向这个术语是从元件内部的角度给予定义的: 元件通过它们的接收衬垫接收数据,通过它们的源衬垫输出数据。如果通过一张图来形象地表述,接收衬垫画在元件的左侧,而源衬垫画在元件的右侧,数据从左向右流动。

衬垫的特性---时效性

衬垫的时效性比衬垫的数据导向复杂得多。一个衬垫可以拥有三种类型的时效性: 永久型(always)、随机型(sometimes)、请求型(on request)。三种时效性的意义顾名思义: 永久型的衬垫一直会存在,随机型的衬垫只在某种特定的条件下才存在(会随机消失的衬垫也属于随机型),请求型的衬垫只在应用程序明确发出请求时才出现。

通过gst-inspect可以查看一个元件所包含的pads信息。下面列举一下:

随机型衬垫(sometimes)

一些元件在其被创建时不会立刻产生所有它将用到的衬垫。例如在一个Ogg demuxer的元件中可能发生这种情况。这个元件将会读取Ogg流,每当它在Ogg流中检测到一些元数据流时(例如vorbis, theora ),它会为每个元数据流创建动态衬垫。同样,它也会在流终止时删除该衬垫。动态衬垫在demuxer这种元件中可以起到很大的作用。

以oggdemux为例,运行gst-inspect oggdemux会显示出一个名字叫做’sink’的永久型接收衬垫和名字叫做’src_%d’的随机型衬垫。可以从衬垫模板(Pad Templates)中的“Availability”属性中看到这些信息。

请求型衬垫

这个衬垫在后面说。

衬垫(Pads)的性能(capabilities)

由于衬垫对于一个元件起了非常重要的作用,一个衬垫能够限制数据流类型的通过,因此就有了一个术语来描述能够通过衬垫或当前通过衬垫的数据流。这个术语就是性能 (capabilities)

衬垫的性能通过GstCaps 对象来进行描述。一个GstCaps对象会包含一个或多个 GstStructure。一个 GstStructure描述一种媒体类型。

下面给出了一个例子,你可以通过运行 gstinspect vorbisdec 看到“vorbisdec” 元件的一些性能。你可能会看到2个衬垫: 源衬垫和接收衬垫, 2个衬垫的时效性都是永久型,并且每个衬垫都有相应的功能描述。接收衬垫将会接收vorbis编码的音频数据,其 mime-type显示为“audio/x-vorbis”。源衬垫可以将解码后的音频数据发送给下一个元件,其 mimetype显示为“audio/x-raw-float”。源衬垫的功能描述中还包含了一些其它的特性: 音频采样率(rate)、声道数(channels)、以及一些其他信息。

衬垫性能的用途

自动填充(Autoplugging): 根据元件的功能自动找到可连接的元件。

兼容性检测(Compatibility detection): 当两个个衬垫连接时,GStreamer 会验证它们是否采用的同样的数据流格式进行交互。连接并验证两个衬垫是否兼容的过程叫“功能谈判” (capsnegotiation)。

元数据(Metadata): 通过读取衬垫的功能(capabilities),应用程序能够提供有关当前流经衬垫的正在播放的媒体类型信息。而这个信息我们叫做元数据(Metadata)。

过滤(Filtering): 应用程序可以通过衬垫的功能(capabilities)来给两个交互的衬垫之间的媒体类型加以限制,这些被限制的媒体类型的集合应该是两个交互的衬垫共同支持的格式集的子集。

动态创建pipeline

给出一张示意图,图中有一个demuxer和两个分支,一个处理音频一个处理视频。在一个容器文件中可能包含多个流(比如:一路视频,两路音频), demuxer会把他们分离开来,然后从不同的输出口送出来。

这里主要复杂在demuxer在没有看到容器文件之前无法确定需要做的工作,不能生成对应的内容。也就是说, demuxer开始时是没有source pad给其他element连接用的。

解决方法是只管建立pipeline,让source和demuxer连接起来,然后开始运行。当demuxer接收到数据之后它就有了足够的信息生成source pad。这时我们就可以继续把其他部分和demuxer新生成的pad连接起来,生成一个完整的pipeline。

下方链接有详细的Gstreamer学习笔记,大家可以自行深入学习:

GStreamer 详细学习笔记 — gstreamer_tutorial 1 documentation (walterfan.github.io)

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值