• Gstreamer说明


    http://general.blog.51cto.com/927298/294928

    http://general.blog.51cto.com/927298/294931

    ====================================

    一 Gstreamer简介

    是一个框架,灵活轻便。

    第一部分基本没有难度,只要能看懂英文。从我目前接触的感觉上看,Gstreamer确实简化了动态 库的加载,模块与模块间的合作。

    但是Gstreamer用得还是有点不太习惯,可能是 GLIB这种风格没有适应。

    gstreamer整个分为:

    l         core:核心库

    l         基础插件:一些很基础的插件

    l         好插件:编写质量较好的遵循LGPL协议的插件

    l         坏插件:有待改进的插件

    l         其他库

    1.1    核 心库

    核心库是不了解任何媒体信息的,它只是一个框架,将所有单元联系起来。

    单元是gstreamer里的核心概念。

    二 基础知识

    2.1 单元

    Element是构成管道的组件, 每个element实际就是一个插件,在gst中得到组装成一个pipe,数据从源单元流向目的单元,完成整个流程。单元间是可以链接起来的(必须得链接起来以组 成pipe)。

    2.2 Pad

    pad是一个单元的输入输出端口, 通过pad, 才能将两个单元链接到一起。对输入来说,pad就是一个插口,对输出来说pad就是一个塞子。pad有自己的规格,所以不同规格的pad就限制了数据的规格。只有规格相符的pad才能链接到一起。

    l         规格协商的过程叫caps negotiation

    l         数据类型叫GstCaps

    2.3 盒子和管道

    盒子Bin是一组单元的集合,而管道Pipeline是一种特殊的盒子,在管道中,所有单元可以一体执行某些。

    在实现的时候,Bin也是一种单元,操纵Bin就可以改变内部所有单元的属性,而且Bin还能传递内部单元的信号事件。这样就简化了外界使用的难度。

    管道是一个顶层的bin,可以设置状态为PAUSED或者PLAYING。内部会启动一个独立线程来干活。

    三 GST构建

    3.1 初始化

    GST库必须先初始化,调用gst_init。

    3.2 单元elements

    GstElement是最重要的对 象。一些高级对象也是从它派生出来的。有好几种类型的elements,必须分清楚了。

    1.       源单元

    source单元是数据的产生方, 对应一个源pad。一般画在右边。

    l         源单元只能生产数据,不能接收数据

    2.       中间单元

    中间单元包括过滤器,转换器,复用器,解复用器,编解码器等。

    它有多个源pad,对应多个目标pad。

    3.       目标单元

    只能接受数据。

    4.       创建和使用单元

    通过factory_make和gst_object_unref来创建及释放单元。make需要两个参数,一个是工厂名,一个是单元名。工厂名实际就是插件名,所以需要先加载插件上 来,才能创建对应的单元。

    单元继承所有Gobject的属性,所以可以当做Gobject来处理。

    单元有属性,单元还能触发信号,所以必须关注这些。

    作为工厂,其功能还不仅限于创建单元,一个工厂有属性,它知道自己能创建怎样的单元。

    其实就是这个插件知道自己能创建怎样的单元。可能需要看了插件编写才真正知道。

    5.       链接单元

    单元必须链接起来,才能协同工作。

    源单元-à中间单元--à目标单元

    l         必须先加到管道后才能link起来。

    l         不在同一bin中的不能link

    6.       单元状态

    单元链接好后,啥事也不会发生,除非设置单元状态。单元一共有四种状态:

    l         GST_STATE_NULL:默认 状态,内部会释放单元的所有资源,其实就是初始状态。

    l         XXX_READY:就绪状态,分配 资源,打开设备。但是流不会打开,所以此时流信息都是零。如果之前打开了流,在这状态中将会被关闭,流信息都会被重设。

    l         XXX_PAUSED:已经打开了 流,但是暂时不处理它。这个时候可以去修改例如seek位置等流信息。时间轴停止

    l         XXX_PLAYING:时间轴运 行。设置为这个状态后,整个流程就开始启动了。内部会将消息发送从管道所在的线程转移到应用程序线程。(?)

    通过set_state函数设置状态,GST会平滑设置,例如从PLAY设置为NULL,将平滑设置READY和PAUSED。

    3.4 Bins

    Bin不仅是一个单元的集合,更是 集成了对内部单元的管理。管道是一种特殊的bin,实际要播放一个视音频就得用到管道。管道能独立在后台运行。

    1.       创建Bin

    Bin从element派生而来,所以创建 单元的函数均可创建Bin,但一般用两个更方便的函数:

    l         gst_bin_new

    l         gst_pipeline_new

    Bin是一个集合,需要将单元加入 进去,也可以删除。

    l         gst_bin_add,gst_bin_remove

    注意,一旦加入到Bin,单元的所有者就变为Bin了,所以删除Bin的话,内部的单元也会相应减少引用。

    2.       定制化Bin

    还是得看插件编程指南才能真正理解。

    3.5 Bus

    1. 总论

    Bus的好处是可以把pipeline所在的线程的消息 路由到应用程序指定的那个Context中去。

    是全局那个线程吗?待会查看下源码。定期检查bus?设计还是比较巧妙 的。

    bus上要加入监控回调函数。通过

    l         gst_bus_add_watch/gst_bus_add_signal_watch

    l         要从bus中取消息,得调用gst_bus_pop/peek/pop

    注意,Bus发出的消息是GstMessage结构,值得解释。

    Bus含一个队列,每次post一 个消息就加到队列里,然后出发maincontext的wakeup。 这样就完成了将消息路由到maincontext去了。因为maincontext等 待的有这个bus队列。

    这里边绕啊绕的..想法还是很直观。

    有没有办法不用默认context呢?有一个函数将message转换为signal去emit:

    l         gst_bus_async_signal_func:

    这里要区分下message和signal。signal是Gobject系统提供的,message是GST提供的。message的处理是异步的,而signal的处理是同步的。

    如果你不想写很多switch来区别message的话,那么另外一种办法就是注册对应的signal到系统。另外,如果不使 用mainloop的话,异步消息-信号不会发出去。

    bus的消息分为异步和同步两类。

    l         异步信号是通过加入到mainloop中的Gsource来触发的,所以必须有mainloop再运行才可

    l         同步信号必须先注册一个同步信号处理函数才可。

     

    需要自己设置一个同步信号处理函数,在那里触发另外一个context,并且调用上面这个函 数发送signal。

     

    2.  message类型

    描述一个message有以下:

    l         Message的来源:记录是从哪个 单元发出来的

    l         类型:

    l         时间戳

    比较重要的是类型信息:有以下几类类型

    l         error,warning,info等 信息:需要调用对应API进行解析

    l         EOS:文件结尾,需要重设管道状态 等

    l         Tag:标签信息(其实就是媒体信 息,比如长度,采样率等)

    l         State变化:

    l         缓存信息:调用gst_bus_get_structure来解析缓存信息

    l         单元信息:某些单元会发送特殊的信息

    l         应用程序自己的信息

     

    3.6 Pads和属性

    Pads很关键,代表了单元的出入 口。标示Pads特性的有两个:

    l         方向,从单元内角度看,sink收数据,source发数据

    l         可用性(availability)

    方向好说,只有sink和source两种,可用性是一个新概念。主要代表这个pad是存活期的。

    分三种:

    l         pad一直存在

    l         动态存在:有时候有,有时候没有,动态创建和删除

    l         响应存在:根据外界要求来创建

    这个可用性是针对媒体文件类型的一种简化表示。下面针对这个具体讲述,pad的可用性非常重要。

    1. 动态pad

    为何会有动态之说?原因很简单。例如播放音频的时候,要动态检测有几路音频,然后再创建对 应的pad。

    程序里边应该绑定一个消息处理函数到动态pad的创建通知上。

    2. 响应pad

    响应用户要求而创建的pad。必须从一个支持创建这种类型的单元中去创建,调用

    l         gst_element_get_request_pad

    这个element必须支持Request这种,这个熟悉由插件注册的时候指定的。

    还有一种就是查找相容的pad

    l         get_element_get_compatible_pad,根据源pad和caps来从单元中找一个相容的。

     

    3. Pad的属性

    刚才提到过,查找相容的pad,那么相容是怎么判断和体现的呢?pad有自己的能力熟悉(Capabilities)

    pad的能力熟悉是和pad模板以及pad绑定一起的。pad模板估计就是一个pad工厂。

    一个pad有很多不同的能力,这个是最原始的信息。但是具体工作后,一个pad要和别的pad协商,大家按照规定的能力办 事。这样,pad的能力就是协商后的能力了。

    能力在GST中用GstCaps来表示。

    GstCaps含一到多个Gstructure,一个Gstructure代表一种pad能处理的媒体类型。

    4. GST中属性和值的表示

    GST除了使用GLIB中的数据类型外,还单独定 义了一些数据类型,用来表示属性值。

    值得注意的有:

    l         GST_TYPE_INT_RANGE:范围值

    l         GST_TYPE_LIST:包含任 何基本类型都可以

    l         GST_TYPE_ARRAY:只能 包含相同的类型

    5. Caps的用处

    Caps实际的用处很多,其实就是 一个寻找匹配pad或element之用。

    Caps中有一项描述媒体信息的, 叫metadata。如何从caps中获取条目呢?

    caps中存的是structure条 目,一个structure代表一种能力

    gst_caps_get_structure/size

    根据条目多少和属性,caps可分为:

    l         简单caps:只含一条structure

    l         固定caps:含一条structure,并且属性值没有range之类可变化的

    l         任意caps和空caps是两种特殊cap

     

    6. 创建过滤器使用的caps

    刚才讲的全是从单元中获取caps,都是已经弄好了的。那么如果想动态创建caps该如何做呢?

    l         gst_caps_new_simple:创建simple的

    l         xx_full:创建n个structure的caps

    这还只是创建pad,要把src和dst通过过滤单元链接起来,用

    gst_element_link_filtered,内部会根据过滤pad自动创建一个capsfilter。

    所以关闭链接的时候,需要把src和dst分别从capsfilter中关闭链接。而非简单 的关闭源和目标

     

    7. 幽灵pad

    有啥用?其实就是创建一个代理pad吧。

    为啥要有个这个东西?因为bin本身是没有pad的。所以你就没办法把两个bin链接起来。

    这个时候,可以用bin中的一个单元的pad构造一个代理pad,这样bin就有一个代理pad了。这个pad实际指向被代理的那个单元的pad。

     

    3.7 缓冲与事件

    数据流动是以缓冲传递来实际工作的,所以buffer比较在重要。

    events和message不太一样,这个events实际就是命令,而且在 管道中流动。这么说的话,buffer对应的就是数据。

    从命名习惯上来说,buffer更应该看成是一种容器,里边含data和events。

    1. Buffer

    GstBuffer有以下成员:

    l         数据内存指针

    l         缓冲大小

    l         时间戳

    l         用者计数(与引用计数对应)

    l         标识

    2. Events

    事件是一种控制数据,能够在管道中上下流动。

    一般来说,上游的控制命令可能是真的在控制什么,来自下游的events可 能大多数是些状态通知之类的。?原文是这么说的。

    应用程序自己能发送控制?例如seek命令。

    恩,确实应该有地方可以发送控制命令。典型的就是seek。用户也需要一 个地方能做这个工作。

    看来都是通过events方式来做到控制的。

    l         gst_events_new_xxx

    l         gst_element_send_event

    先创建一个命令,然后发出去….


    四 基本例子

    这部分对应第10章,不打算介绍了。做到能看懂代码为准。

    或者自己可以想想该怎么写一个这样的例子,能解释清楚里边的API调用次序和关系等。

    看明白了,看来要使用一个gst还是相对比较容易的。但是要开发一个插 件,可能难度就大很多了。尤其是里边的Buffer,事件之类的东西。争取2周搞定。

    五 高级部分

    5.1 查询与Seek

    查询主要是获得进度信息(播放电影的时候那个进度条位置)。

    seek与查询类似,seek的完成通过event方式来发送控制命令。

    1. GST中的查询

    GST为查询提供了丰富的接口,例 如当前时间戳,当前读取帧数等信息,都可以查询到。

    questions:在哪儿查?查哪个单元,怎么查?

    Answer:估计是查pipe。 调用gst_element_query

    内部处理是先将该query发到sink单元,然后向上找看哪个单元能够处理,处理完了再把结果返回给调用程序。一般demuxer能够处理。

     

    2. Seek

    处理逻辑与查询类似。针对seek请求,单独可以构造一个gst_event_new_seek出来。

    一个seek请求包含很多参数,这里不详述了。

    有几个可以猜想到:seek的位置,seek多少等。

    有一个标识关于是否刷新内部buffer的似乎很重要。

    当处于PAUSED和PLAYING状态的时候,需要这个FLUSH标示。因为seek完了后,会回到以前的状态。

    你可以等待seek真正完成,用:

    l         gst_element_get_state

    l         或者等到ASYNC_DONE消息

    另外,只能在PLAYING状态下设置无FLUSH标示。seek命令的完成可能是在另外一个线程来做的。内部处理逻辑如下:

    l         先pause,如果开始是playing状态的话,位置信息将被重置

    l         中间单元将重新位置处开始处理,直到sink单元收到数据,如果之前是play状态,则seek完成后也是play状态

     

    5.2 元数据信息

    MetaData应该是描述媒体文 件信息之用的。gst将MD分为两类:

    l         标签信息(除媒体视音频格式之外的其他信息,例如属于哪个专辑,什么流派之类的),这类信息 由GstTag系统完成

    l         视音频格式信息,这个由pad完成

    1. Tag信息读取

    这个是通过管道的bus来读取的。可以监听GST_MESSAGE_TAG来完成。

    2. Tag写入

    使用GstTagSetter来完成,而且该单元必须支持tag设置。

    奇怪,怎么设置?源一般按普通文件打开的,没法设置啊。

    所以必须先从管道中找到那些能设置的。通过:

    l         gst_bin_iterate_all_by_interface(GST_TYPE_TAG_SETTER),

    l         然后调用gst_tag_setter_add等函数。

    看了下manual,Tagsetter是 一个接口,必须有类实现这个接口就可以了。

    5.3 接口组合

    接口类定义了一个实现单元应该支持的功能。

    1. URI接口

    其实就是定义一个支持通用路径的接口。

    例如本地文件用file:////,网页文件用http://等

    怎么获得一个支持特定URI地址的单元呢?

    l         gst_element_make_from_uri,可以指定SRC或DST

    创建一个支持特定URI地址的单元。

    2. MIXER接口

    支持对硬件或软件音量的统一管理。一般那些直接和声卡硬件打交道的单元用实现这个接口。

    有哪些功能呢?比如静音,调整左右声道等功能。

    一般不要在播放中使用这种接口来控制音量,相反,应该使用sink单元的音量属性来控制。

    也是啊,一般控制本地程序即可,不用去调节全局声卡的音量呀。

    3. Tuner接口

    用于调整多输入输出设备的,可能还是和硬件关系比较紧密。

    4. 色彩平衡接口

    用来调节亮度,对比度等内容的。

    5. 属性探测接口

    主要用途是来自动探测硬件设备的。

    6. X重叠接口

    X意味X-Window,主要是绘图用。

     

    5.4 时钟

    GST中使用时间的原因是:

    l         有些单元提供了时钟,要是管道中没有时钟的话,就会用默认的系统时钟

    l         有些单元根据时钟干活(clock slaves)

    GST中时间有好几种:

    l         时钟时间,就是普通时间,一直增加的

    l         基础时间:其实就是开始时间

    l         运行时间:播放的时间,包括重播,回播种种之和

    l         流时间:这个可能真的是一个单次播放的时间,例如一次重播,一次完整播放等

    1. 时钟提供者

    为何存在这个?因为有些视音频文件必须按照媒体自己的时间来走,而不是系统的时间频率。

    2. 时钟使用者

    管道会有一个时钟,然后给其他时钟使用者使用,时钟使用者应该确保回放的东西跟得上时钟。 一般是要等待一个时间,用gst_clock_id_wait函数,或者丢几帧数据。

    参考插件编写指南吧。

    5.5 动态修改参数

    这个东西不知道是干嘛的。manual上说是在流时间里调整gobject的属性。

    必须单独包含gstcontroller库和头文件。

    而且还得初始化。

    那怎么使用呢?

    l         1 先选择需要操作的参数,gst_object_control_properties,得到一个controller对象

    l         2 通过该对象,设置插值模式,用来 计算中间态的值。

    l         3 最后设置控制点,这是一个时间戳 值,当时间到了,这个值就其激活。

    还是不明白有啥用。

    5.6 线程

    使用队列单元?恩,内部应该就是一个线程安全的队列。

    GST通过不同的队列单元,将管道 分为不同的组。

    线程调度如何做?有push和pull模式两种。如果单元支持随机seek,…

    寥寥数语,怎么能说清楚呢?

    5.7 自动plugging(自动加载插件)

    就是想自动完成一些加载插件(生成合适单元)的工作,通过比较匹配视音频格式信息来完 成。

    如何匹配?用什么来描述匹配项呢?

    1. MIME类型

    这个是用来描述媒体信息的。

    2. 如何工作

    一般来说,一个管道刚开始的时候并不知道一个文件的MIME类型。 所以GST使用类型查找来探测MIME,这个typefinding是管道的一个组成部分,它从文件中读足够的数据直到它能探测为止。

    怎么说呢?读一点数据给所有的插件(注册了支持typefind的插 件),如果有哪个插件支持,则加载到管道中。

    注意:这里谈的都是自动加载的,如果手动加载的话,应该事先就知道了。

    插件如何实现?见manual吧。其实就是调用插件的一个特殊函数,判断是不是自己能支持的。

    5.8 管道的高级管理

    就是一些对其中传递的buffer进行中途监控的作用,难度相对比较大,等看完插件编写再说。

    插件编写更实际点应该,现在看的都是云里雾里。

    六 GST高级接口

    6.1 高级播放接口

    介绍两个高级点的播放接口,playbin和decodebin。

    支持自动加载,列表播放,淡入淡出音轨等功能。这里不再详述。

    6.2 XML

    将管道的信息保存到XML,并可以从XML文件中获取管道信息,然后创建管道。

     

    七 附录

    7.1 好习惯

    l         加入GstBus信息来获取错误等报告

    l         检查GST函数返回值

    l         解引用任何返回不是GLIB基本类型的对象(就是减少对象的引用计数)

    l         用管道对象来管理管道的状态,外部不要自己维护一个状态变量。

    7.2 调试

    在main可以设置-gst-debug=选项,然后传入gst_init中。

    7.3 工具

    几个工具还是比较有用的。

    1 gst-launch

    用来测试管道的。

    2. gst-insepect

    探查单元的各种信息用。


    Meet so Meet. C plusplus I-PLUS....
  • 相关阅读:
    异常总结
    反射
    面试题
    继承多态接口
    JAVA面向对象变成学习!
    学生管理系统---三层架构
    Secondary NameNode
    Hadoop之HDFS
    大数据相关概念二
    大数据相关概念
  • 原文地址:https://www.cnblogs.com/iplus/p/4467399.html
Copyright © 2020-2023  润新知