GStreamer学习六(《GStreamer插件指南》笔记 )

1、GstElement 元件 是 GStreamer 的核心。在插件的开发中,一个元件就是继承于 GstElement 的一个对象。没有了元件,GStreamer 只是一堆概念性的管道,没有任何东西可供连接 。仅仅写一个新的元件并不够,为了使 GStreamer 能够使用它,你必须将元件封装到一个插件中。一个插件是一块可以加载的代码,通常被称为共享对象文件(shared object file)或动态链接库(dynamically linked library)。一个插件中可以包含一个或若干 element。为简单起见,本手册主要涉及只包含一个 element 的插件。
注:插件名称及其他信息,插件的Pad,插件的属性,插件的信号,插件的action(GstTagList),debug名称
2、滤镜filter 是一类处理流数据的重要插件。数据的生产者和消费者分别被称为 source  sink 元件箱柜(Bin)元件可以包含其它的元件。箱柜的主要职责是调度它包含的元件并使得数据流更平滑。热插拔(autoplugger)元件是另一种箱柜,它可以动态的加载其它元件,并将它们连接起了形成一个可以处理两个任意流的滤镜。
3、核心库中只有少量基本函数,其它所有的功能都由插件来实现。一个 XML 文件被用来保存所有注册的插件的详细信息。 这样,使用 GStreamer的程序可以只在需要时加载插件,而不必事先全部加载。
4、衬垫 GstPads 在GStreamer 中是用来在元件间协商连接和数据流的。pad 是 element 间传输数据的通道衬垫可以看作元件间互相连接的 “接口”,数据流通过这些接口流入流出元件。Pad 具有特殊的数据处理能力:衬垫可以限制通过它的数据类型。只有当两个衬垫允许通过的数据类型兼容时才可以将它们连接起来。大部分情况下,所有在 GStreamer 中流经的数据都遵循一个原则。数据从 element 的一个或多个源衬垫流出,从一个或多个 sink 衬垫流入。源和 sink 元件分别只有源和 sink 衬垫。
5、缓冲区的分配 
5.1、特殊的元件创建指向特殊内存的缓冲区,如filesrc使用 mmap()将一个文件映射到应用程序的地址空间,并创建指向那个地址范围的缓冲区。
5.2、可能得到特殊缓冲区的途径是向下游同伙(downstream peer)发出请求。如sink 元件的将数据拷到硬件的函数都经过了优化,或者可以直接操作硬件。例是 ximagesink。它创建包含 XImage的缓冲区,因此当一个上游伙伴将数据拷入缓冲区时,数据被直接拷入 XImage,这样 ximagesink 可以直接将图象画到屏幕上而不用先将数据拷到一个 XImage 中
5.3、自动创建一个通用缓冲区。并将缓冲区 push 给创建它的源衬垫。
6、特定条件下工作(例如,如果声卡没有被另一个进程使用),这必须处理为 element 不能进入 READY状态,而不是试图不让 element 出现。
7、如果你的_link ()函数不需要做任何特殊的操作(例如,它只是转发 cap),你可以将其设为
gst_pad_proxy_link ()。这是核心库提供的一个连接转发函数。它在诸如 identity 的 element 中是很
有用的。
8、push模式下所有的数据处理在 Chain 函数中进行。
9、注:缓冲区并不总是可写的。在更加高级的 element 中(那些进行事件处理的),你也许会要指定一个事件处理函数,当流事件发出时(例如流结束,连接中断,tags,等等)该函数会被调用。
gst_my_filter_event (GstPad *pad, GstEvent *event)
{
    GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
    switch (GST_EVENT_TYPE (event)) {
        case GST_EVENT_EOS:
        /* end-of-stream, we should close down all stream leftovers here */
        gst_my_filter_stop_processing (filter);
        break;
    default:
        break;
    }
    return gst_pad_event_default (pad, event);
}
 
static GstFlowReturn gst_my_filter_chain (GstPad *pad, GstBuffer *buf)
{
    GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
    GstBuffer *outbuf;
    outbuf = gst_my_filter_process_data (filter, buf);
    gst_buffer_unref (buf);
    if (!outbuf) {
        /* something went wrong - signal an error */
        GST_ELEMENT_ERROR (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
        return GST_FLOW_ERROR;
    }
    return gst_pad_push (filter->srcpad, outbuf);
}
10、pipeline状态
GST_STATE_NULL 是 element 的缺省状态。这种状态下,没有分配任何运行时资源,也没有加载任何运行
时库,显然此时不能处理数据。
GST_STATE_READY 是下 element 的下一个状态。在 READY 状态下,一个 element 拥有所有的缺省资源(运
行时库,运行时内存)。然而,所有流相关的东西还没有被分配或定义。当从 NULL 状态过渡到 READY
状态时(GST_STATE_CHANGE_NULL_TO_READY),一个 element 应该分配所有的非流相关的资源以及加载
所有运行时库(如果有的话)。反过来,(从 READY 到 NULL 状态 GST_STATE_CHANGE_READY_TO_NULL),
一个 element 应该卸载这些库并释放所有分配的资源。硬件设备就是这种资源的一个例子。注意,文件
通常是流,应当被视为流相关的资源,因此不应该在该状态下分配。
GST_STATE_PAUSED 下 element 已准备好接受并处理数据。对多数 element 来说,这个状态和 PLAYING 状
态是一样的。唯一的例外是 sink elements。sink elements 只接受一个 buffer 然后阻塞。在这种情况
下管道处于'prerolled'并且准备好可以立即将数据画出。
GST_STATE_PLAYING 是 element 的最高状态。对多数 element 来说,该状态和 PAUSED 状态是完全一样的,
它们接受并处理事件和缓冲区数据。只有 sink elements 需要区分 PAUSED 和 PALAYING 状态。在 PLAYING
状态下,sink elemnts 才真正将到达的数据输出(render),例如,将音频输出到声卡或将视频画面输
出到 image sink 上。
11、如果你使用一个基类,你基本不需要自己去处理状态的改变。你所要做的所有工作就是重载基类的start()和 stop()虚函数(也许会根据基类做不同的调用),基类将会为你做好所有的工作如果你的插件是解码器或编码器,这些是无可避免的,因为当前还没有解码器或编码器的基类,可以通过一个虚函数指针来得到状态变化的通知不要在未处理的状态变化中使用 g_assert;这由 GstElement 基类负责。
gst_my_filter_class_init (GstMyFilterClass *klass)
{
    GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
    element_class->change_state = gst_my_filter_change_state;
}
 
static GstStateChangeReturn gst_my_filter_change_state (GstElement *element, GstStateChange transition)
{
    //正向
    GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
    GstMyFilter *filter = GST_MY_FILTER (element);
    switch (transition) {
        case GST_STATE_CHANGE_NULL_TO_READY:
            if (!gst_my_filter_allocate_memory (filter))
            return GST_STATE_CHANGE_FAILURE;
            break;
        default:
            break;
    }
 
    //修改状态
    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
    if (ret == GST_STATE_CHANGE_FAILURE)
        return ret;
 
    //反向
    switch (transition) {
        case GST_STATE_CHANGE_READY_TO_NULL:
            gst_my_filter_free_memory (filter);
            break;
        default:
            break;
    }
    return ret;
}
12、最主要也是最重要的控制 element 行为的方法是通过设置 GObject 的属性实现一个_get_property ()和一个 _set_property ()函数。尽量使用枚举或标志来代替整形数。
13、GObject 信号可以用来通知程序该对象的特定事件的到来。然而要注意,应用程序必须要知道信号及其意义,因此如果你在寻找一个应用程序和 element 间的通用的交互方法,信号也许不是你所要的。然而,在许多情况下信号是很有用的。
14、源元件发出(存储在)缓冲中的样本。这个元件在每个缓冲里面放置一个时间戳来说明(保存在缓冲里面的)样本何时被播放。当一个 buffer 到达了下个元件的 sink pad 的时候,这个元件比较当前的元件时间和这个 buffer 的时间戳。如果时间戳高于或等于(元件时间),它就播放 buffer,否则它就调用 gst_element_wait()来等待,直到放置了(符合条件的)时间的 buffer 到来。
15、如果流被查找,那么下个被发出的样本将拥有一个没有根据元件时间校准过的时间戳。因此,源元件必发出一个非连续的事件
16、Tag标签是存储在流中的一些非流内容的信息,它们是用来 描述 流的内容。大多数媒体容器格式在某种方式上支持标记(tagging)。Ogg 通过 VorbisComment 来支持标签,MP3 使用 ID3,AVI 以及 WAV 使用 RIFF的 INFO 列表块等。
17、标签在 GStreamer 中被分为元数据标签和流信息标签
元数据:一种描述非技术方面的流内容的标签。它们可以不需要完全重编码流而被改变。例如 "作者", "标题" or "相册"。但是容器格式仍然需要被标签能重写。
流信息:一种描述流内容中技术性的内容。为了改变它们,需要对流重编码。例如 "codec" or "bitrate”。
18、自定义事件处理准则
18.1、始终使用 gst_pad_event_default 转发你不想处理的上游事件。
18.2、如果你要根据你收到事件创建一个新的事件,不要忘了用 gst_event_unref 来减少你收到的事件的引用。
18.3、事件处理函数会被假定返回 TRUE 或 FALSE 来表示事件是否被处 理了。永远不要简单的返回 TRUE或FALSE 除非你真的知道你以及处 理了哪个事件。
18.4、记住,事件处理器有可能在流化线程外的另一个线程里被调用 ,因此确保你在所有的地方以及在那些使用 gst_pad_get_parent()函数得到你的元件的函数的开头恰当的使用了锁(并且在函数的结尾使用函数gst_object_unref ()释放它。)。
19、接口,普通属性缺点:第一个缺陷涉及到用来建立控制元件的自定义最终用户接口的问题。第二个问题是这些参数都不是动态加载的。
19.1、混合器(mixer)接口的主要目的是提供一个简单但强大的 API 给应用程序以便达到对音频硬件混音/音量控制。混合器接口需要通过 GstImplementsInterface 接口才能被元件实现。
19.2、谐调器(tuner)接口作用于 N-1 的元件,但不是混合所有输入流,它是选择一个流然后把这个流中的数据推给输出流。
19.3、属性探测(property probe)接口试图完成一个和枚举列表类似的问题:给出一个限度,对每个属性显式列出允许的值。在枚举列表和属性探测之间有两个不同之处。首先,枚举仅允许字符串作为值;属性探测可以为所有的值类型有效。其次,所有有效的探测列表的内容可能在元件的生命周期内被改变。而枚举列表的的内容是静态的。目前,属性探测多用于设备的检测(像检测 OSS 元件,Video4linux 元件等)。但理论上,属性探测可以对任何的属性都有效。
19.4、X Overlay接口:一个 X Overlay 是 XFree86 中可拖拽的视频输出。实现了这个接口的元件可以在 X11 窗口中拖拽视频图象。通过这个接口,应用程序可以以 2 种方式来于实现了该接口的插件。第一种是被动模式,插件自己创建并销毁 X11 窗口。第二种是主动模式,应用程序处理 X11 窗口的创建,然后告诉插件在哪可以输出视频。
20、事件分为上游事件和下游事件,最常见的上游事件是定位事件(seek events)和服务质量事件(QoS events)。
21、事件汇总
21.1、流结束事件(即EOS事件):当一个元件发送完数据流时,流结束事件就会被发送。元件收到该事件(从上游,因此从它的 sink 衬垫接受的)通常只是处理一些缓冲数据(如果有的话)然后将事件向下游发送。gst_pad_event_default()会做所有这些工作,因此大多数元件不需要支持该事件。那些在流结束需要显式地关闭一个资源的元件以及 N 到 1 的元件是一个例外。注意,流自身不是一个在收到流结束事件时需要关闭的资源。应用程序也许会在流结束之前往回定位然后继续播放。它用 gst_event_new_eos()函数创建。值得一提的是只有那些驱动整个管道的元件才应该发出流结束事件。如果你的元件是基于链的(chain-based),它不会驱动整个管道。基于链的元件应该只是在流(或片断)结束时从它们的链函
数返回 GST_FLOW_UNEXPECTED,驱动管道的上游元件将负责发送流结束事件(或者给 bus 发送一个SEGMENT_DONE 消息,这取决于操作模式)。如果你在实现你自己的源元件,你也不必手动的发送一个流结束事件,你应该只是在创建函数中返回 GST_FLOW_UNEXPECTED(假设你的元件继承自 GstBaseSrc 或GstPushSrc)。
21.2、冲刷开始事件(即FLUSH_START事件):如果管道中所有缓存都为空时,冲刷事件将会发送给下游元件。"队列" 元件在接收到该事件后将会清空它们的内部缓存列表。通常地,接收到该事件的元件仅会将该事件往前发,因为大多数的过滤器和类过滤元件都没有内部缓存数据。gst_pad_event_default () 可以传递该事件,对大多数的元件而言,使用默认时间处理方法来向前传递该事件已经足矣。冲刷开始时间通过 gst_event_new_flush_start ()创建。
21.3、冲刷停止事件(即FLUSH_STOP事件):从管道中刷新所有数据有一定的边界效应,该事件会使所有的衬垫拒收数据直到收到 Flush Stop 信号,这期间它阻塞了流线程。冲刷结束事件由驱动管道的元件发送,发送时机是在冲刷开始事件后,它告诉下游元件它们可以再次接收其它事件和缓存。flush-stop 事件通过 gst_event_new_flush_stop ()被创建。
21.4、新片段事件(即NEW_SEGMENT事件):当通告数据流中的新数据片或用新值更新当前片段都会发送一个新片段事件。一个新片段事件总是在第一个缓存被冲刷之前。newsegment 事件通过函数 gst_event_new_new_segment ()被创建。
21.5、定位请求事件(即NEW_SEEK事件):请求定位意味着为元件请求一个新的流位置。这个新位置可以通过不同的格式来设置。(时间,字节或"默认单位" [标识视频帧的术语,音频样本的独立声道等])。定位事件通过特定格式的位置信息(时间,字节,单元)被建立。它们通过函数 gst_event_new_seek ()来被创建。注意大多数的插件不支持从流尾部或当前位置开始定位。一个没有驱动管道的元件发送了一个定位请求,这不能被认为定位成功或者做了定位请求的事情。这种情形下,该元件应该是收到一个NEWSEGMENT 事件后才被认为做了定位请求的事情。通过 gst_event_parse_seek()来解析该事件。
21.6、导航事件:导航事件通常由视频 sink 向上游元件发送,它用来通知上游元件鼠标位置。当鼠标点击事件发生或键盘被按下或松开,该事件便会发生。
21.7、标签事件(即TAG事件):标签事件被发送往下游,其用来标识流数据中的需要被解析的标签。目前主要用该事件来保护在流格式转换期间不改变标签信息。标签事件通过 gst_event_new_tag ()来创建,但更多的元件是使用gst_element_found_tags () 或gst_element_found_tags_for_pad (),这两个函数做的事情类似:往总线上发送一个消息,发送一个标签事件给下游。所有这些函数需要一个自主的标签列表作为参数。通过函数 gst_event_parse_tag () 得到事件包含的标签列表从而来解析该事件。
21.7、步进事件(即STEP事件):Step事件可以在改变后面的播放速度的情况下跳过一个指定的间隔(只能向前播放)。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值