您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > 用GStreamer 简化 Linux 多媒体开发
GStreamer是GNOME桌面环境下用来构建流媒体应用的编程框架(framework),其目标是要简化音/视频应用程序的开发,目前已经能够被用来处理像MP3、Ogg、MPEG1、MPEG2、AVI、Quicktime等多种格式的多媒体数据。一、基本概念GStreamer作为GNOME桌面环境推荐的流媒体应用框架,采用了基于插件(plugin)和管道(pipeline)的体系结构,框架中的所有的功能模块都被实现成可以插拔的组件(component),并且在需要的时候能够很方便地安装到任意一个管道上,由于所有插件都通过管道机制进行统一的数据交换,因此很容易利用已有的各种插件“组装”出一个功能完善的多媒体应用程序。1.1元件处理对于需要应用GStreamer框架的程序员来讲,GstElement是一个必须理解的概念,因为它是组成管道的基本构件,也是框架中所有可用组件的基础,这也难怪GStreamer框架中的大部分函数都会涉及到对GstElement对象的操作。从GStreamer自身的观点来看,GstElement可以描述为一个具有特定属性的黑盒子,它通过连接点(linkpoint)与外界进行交互,向框架中的其余部分表征自己的特性或者功能。按照各自功能上的差异,GStreamer又将GstElement细分成如下几类:SourceElement数据源元件只有输出端,它仅能用来产生供管道消费的数据,而不能对数据做任何处理。一个典型的数据源元件的例子是音频捕获单元,它负责从声卡读取原始的音频数据,然后作为数据源提供给其它模块使用。FilterElement过滤器元件既有输入端又有输出端,它从输入端获得相应的数据,并在经过特殊处理之后传递给输出端。一个典型的过滤器元件的例子是音频编码单元,它首先从外界获得音频数据,然后根据特定的压缩算法对其进行编码,最后再将编码后的结果提供给其它模块使用。SinkElement接收器元件只有输入端,它仅具有消费数据的能力,是整条媒体管道的终端。一个典型的接收器元件的例子是音频回放单元,它负责将接收到的数据写到声卡上,通常这也是音频处理过程中的最后一个环节。图1将有助于你更好地理解数据源元件、过滤器元件和接收器元件三者的区别,同时也不难看出它们是如何相互配合形成管道的:图1需要注意的是,过滤器元件的具体形式是非常灵活的,GStreamer并没有严格规定输入端和输出端的数目,事实上它们都可以是一个或者多个。图2是一个AVI分离器的基本结构,它能够将输入数据分离成单独的音频信息和视频信息,用于实现该功能的过滤器元件很明显只具有一个输入端,但却需要有两个输出端。图2要想在应用程序中创建GstElement对象,唯一的办法是借助于工厂对象GstElementFactory。由于GStreamer框架提供了多种类型的GstElement对象,因此对应地提供了多种类型的GstElementFactory对象,它们是通过特定的工厂名称来进行区分的。例如,下面的代码通过gst_element_factory_find()函数获得了一个名为mad的工厂对象,它之后可以用来创建与之对应的MP3解码器元件:GstElementFactory*factory;factory=gst_element_factory_find(mad);成功获得工厂对象之后,接下来就可以通过gst_element_factory_create()函数来创建特定的GstElement对象了,该函数在调用时有两个参数,分别是需要用到的工厂对象,以及即将创建的元件名称。元件名称可以用查询的办法获得,也可以通过传入空指针(NULL)来生成工厂对象的默认元件。下面的代码示范了如何利用已经获得的工厂对象,来创建名为decoder的MP3解码器元件:GstElement*element;element=gst_element_factory_create(factory,decoder);当创建的GstElement不再使用的时候,还必须调用gst_element_unref()函数释放其占用的内存资源:gst_element_unref(element);GStreamer使用了与GObject相同的机制来对属性(property)进行管理,包括查询(query)、设置(set)和读取(get)等。所有的GstElement对象都需要从其父对象GstObject那里继承名称(name)这一最基本的属性,这是因为像gst_element_factory_make()和gst_element_factory_create()这样的函数在创建工厂对象和元件对象时都会用到名称属性,通过调用gst_object_set_name()和gst_object_get_name()函数可以设置和读取GstElement对象的名称属性。1.2衬垫处理衬垫(pad)是GStreamer框架引入的另外一个基本概念,它指的是元件(element)与外界的连接通道,对于框架中的某个特定元件来说,其能够处理的媒体类型正是通过衬垫暴露给其它元件的。成功创建GstElement对象之后,可以通过gst_element_get_pad()获得该元件的指定衬垫。例如,下面的代码将返回element元件中名为src的衬垫:GstPad*srcpad;srcpad=gst_element_get_pad(element,src);如果需要的话也可以通过gst_element_get_pad_list()函数,来查询指定元件中的所有衬垫。例如,下面的代码将输出element元件中所有衬垫的名称:GList*pads;pads=gst_element_get_pad_list(element);while(pads){GstPad*pad=GST_PAD(pads-data);g_print(padnameis:%s\n,gst_pad_get_name(pad));pads=g_list_next(pads);}与元件一样,衬垫的名称也能够动态设置或者读取,这是通过调用gst_pad_get_name()和gst_pad_set_name()函数来完成的。所有元件的衬垫都可以细分成输入衬垫和输出衬垫两种,其中输入衬垫只能接收数据但不能产生数据,而输出衬垫则正好相反,只能产生数据但不能接收数据,利用函数gst_pad_get_direction()可以获得指定衬垫的类型。GStreamer框架中的所有衬垫都必然依附于某个元件之上,调用gst_pad_get_parent()可以获得指定衬垫所属的元件,该函数的返回值是一个指向GstElement的指针。衬垫从某种程度上可以看成是元件的代言人,因为它要负责向外界描述该元件所具有的能力。GStreamer框架提供了统一的机制来让衬垫描述元件所具有的能力(capability),这是借助数据结构_GstCaps来实现的:struct_GstCaps{gchar*name;/*thenameofthiscaps*/guint16id;/*typeid(majortype)*/guintrefcount;/*capsarerefcounted*/GstProps*properties;/*propertiesforthiscapability*/GstCaps*next;/*capscanbechainedtogether*/};以下是对mad元件的能力描述,不难看出该元件中实际包含sink和src两个衬垫,并且每个衬垫都带有特定的功能信息。名为sink的衬垫是mad元件的输入端,它能够接受MIME类型为audio/mp3的媒体数据,此外还具有layer、bitrate和framed三种属性。名为src的衬垫是mad元件的输出端,它负责产生MIME类型为audio/raw媒体数据,此外还具有format、depth、rate和channels等多种属性。Pads:SINKtemplate:’sink’Availability:AlwaysCapabilities:’mad_sink’:MIMEtype:’audio/mp3’:SRCtemplate:’src’Availability:AlwaysCapabilities:’mad_src’:MIMEtype:’audio/raw’:format:String:intendianness:Integer:1234width:Integer:16depth:Integer:16channels:Integerrange:1-2law:Integer:0signed:Boolean:TRUErate:Integerrange:11025-48000准确地说,GStreamer框架中的每个衬垫都可能对应于多个能力描述,它们能够通过函数gst_pad_get_caps()来获得。例如,下面的代码将输出pad衬垫中所有能力描述的名称及其MIME类型:GstCaps*caps;caps=gst_pad_get_caps(pad);g_print(padnameis:%s\n,gst_pad_get_name(pad));while(caps){g_print(Capabilitynameis%s,MIMEtypeis%s\n,gst_caps_get_name(cap),gst_caps_get_mime(cap));caps=caps-next;}1.3箱柜箱柜(bin)是GStreamer框架中的容器元件,它通常被用来容纳其它的元件对象,但由于其自身也是一个GstElement对象,因此实际上也能够被用来容纳其它的箱柜对象。利用箱柜可以将需要处理的多个元件组合成一个逻辑元件,由于不再需要对箱柜中的元件逐个进行操作,因此能够很容易地利用它来构造更加复杂的管道。在GStreamer框架中使用箱柜还有另外一个优点,那就是它会试着对数据流进行优化,这对于多媒体应用来讲是很具吸引力的。图3描述了箱柜在GStreamer框架中的典型结构:图3在GStreamer应用程序中使用的箱柜主要有两种类型:GstPipeline管道是最常用到的容器,对于一个GStreamer应用程序来讲,其顶层箱柜必须是一条管道。GstThread线程的作用在于能够提供同步处理能力,如果GStreamer应用程序需要进行严格的音视频同步,一般都需要用到这种类型的箱柜。GStreamer框架提供了两种方法来创建箱柜:一种是借助工厂方法,另一种则是使用特定的函数。下面的代码示范了如何使用工厂方法创建线程对象,以及如何使用特定函数来创建管道对象:GstElement*thread,*pipeline;//创建线程对象,同时为其指定唯一的名称。thread=gst_element_factory_make(thread,NULL);//根据给出的名称,创建一个特定的管道对象。pipeline=gst_pipeline_new(pipeline_name);箱柜成功创建之后,就可以调用gst_bin_add()函数将已经存在的元件添加到其中来了:GstElement*element;GstElement*bin;bin=gst_bin_new(bin_name);element=gst_element_factory_make(mpg123,decoder);gst_bin_add(GST_BIN(bin),element);而要从箱柜中找到特定的元件也很容易,可以借助gst_bin_get_by_name()函数实现:GstElement*element;element=gst_bin_get_by_name(GST_BIN(bin),decoder);由于GStreamer框架中的一个箱柜能够添加到另一个箱柜之中,因此有可能会出现箱柜嵌套的情况,gst_bin_get_by_name()函数在查找元件时会对嵌套的箱柜作递归查找。元件有添加到箱
本文标题:用GStreamer 简化 Linux 多媒体开发
链接地址:https://www.777doc.com/doc-6899 .html