GSteamer 学习笔记
GSteamer 学习笔记
前言
本文是笔者阅读 GStreamer 官方文档去学习 GStreamer 时的记录,大部分内容可以在 GStreamer 官方文档中找到。
笔者学习 GStreamer 的主要目的是:使用 GStreamer 处理从 TCP Socket 接收到的 H.265 裸流(使用 live555 的 testRTSPclient 程序从 RTSP URL 中获取到),将其解码并保存为 jpeg 图片。
笔者最终放弃使用 GStreamer 的想法,使用 FFmpeg 完成了上述目的。
Elements 元素
GStreamer 中最重要的对象是 GstElement
对象。元素是媒体管道的基本构建基块。使用的所有不同的高级组件都派生自 GstElement
。每个解码器、编码器、解复用器、视频或音频输出实际上都是一个 GstElement
对于解码器元素,您将输入编码数据,该元素将输出解码数据。
源元素生成供管道使用的数据,例如从磁盘或声卡读取数据。源元素的可视化显示了我们将如何可视化源元素。我们总是在元素的右侧绘制一个源垫。源元素不接受数据,它们只生成数据。您可以在图中看到这一点,因为它只有一个源pad(在右侧)。源键盘只能生成数据。
Filters, convertors, demuxers, muxers and codecs 滤波器、转换器、解复用器、多路复用器和编解码器
滤波器和类似滤波器的元件具有输入和输出 pad。它们对输入(接收)pad 上接收的数据进行操作,并将在输出(源)pad 上提供数据。此类元素的示例包括音量元素(滤波器)、视频缩放器(转换器)、Ogg 解复用器或 Vorbis 解码器。
类似过滤器的元件可以具有任意数量的源或接收垫。例如,视频解复用器将有一个接收器 pad 和几个 (1-N) 源 pad,一个用于容器格式中包含的每个基本流。另一方面,解码器只有一个源和接收 pad。
过滤器元素的可视化显示了我们将如何可视化类似过滤器的元素。此特定元素具有一个源垫和一个接收垫。接收输入数据的接收垫在元件的左侧绘制;源键盘仍然在右侧。
具有多个输出 pad 的滤波元件的可视化显示了另一个类似滤波器的滤波器元件,该滤波元件具有多个输出(源)pad。例如,一个此类元素的示例可以是包含音频和视频的 Ogg 流的 Ogg 解复用器。一个源 pad 将包含基本视频流,另一个将包含基本音频流。解复用器通常会在创建新 pad 时触发信号。然后,应用程序程序员可以在信号处理程序中处理新的初级流。
Sink elements 接收器元素
接收器元素是媒体管道中的端点。他们接受数据,但不产生任何东西。磁盘写入、声卡播放和视频输出都将由接收器元素实现。接收器元素的可视化显示接收器元素。
Creating a GstElement
创建 GstElement
创建元素的最简单方法是使用 gst_element_factory_make ()
.此函数采用工厂名称和新创建的元素的元素名称。例如,元素的名称是稍后可用于在 bin 中查找元素的名称。该名称也将用于调试输出。可以作为 name 参数传递 NULL
以获取唯一的默认名称。
当您不再需要该元素时,您需要使用 gst_object_unref ()
取消引用它。这会将元素的引用计数减少 1。元素在创建时的引用计数为 1。当 refcount 减少到 0 时,元素将被完全销毁。
下面的示例 [1] 展示了如何从名为 fakesrc 的元素工厂创建名为 source 的元素。它检查创建是否成功。检查后,它会取消引用元素。
1 |
|
gst_element_factory_make
实际上是两个函数组合的简写。 GstElement
对象是从工厂创建的。要创建元素,您必须使用唯一的工厂名称访问 GstElementFactory
对象。这是用 gst_element_factory_find ()
.
以下代码片段用于获取可用于创建 fakesrc 元素(假数据源)的工厂。该函数gst_element_factory_create ()
将使用元素工厂创建具有给定名称的元素。
1 |
|
使用元素作为 GObject
A GstElement
可以具有多个属性,这些属性是使用标准 GObject
属性实现的。因此,支持查询、设置和获取属性值 GParamSpecs
的常用 GObject
方法。
每个 GstElement
都从其父 GstObject
级继承至少一个属性:“name”属性。这是我们提供给函数 gst_element_factory_make ()
的名称,或者 gst_element_factory_create ()
.可以使用函数 gst_object_set_name
获取和设置此属性,或者 gst_object_get_name
使用如下所示的 GObject
属性机制。
1 |
|
大多数插件都提供额外的属性,以提供有关其配置或配置元素的更多信息。 gst-inspect
是查询特定元素属性的有用工具,它还将使用属性自省来简要说明属性的功能以及它支持的参数类型和范围。有关 的详细信息,请参阅附录中的 gst-inspect gst-inspect
。
有关 GObject
属性的更多信息,我们建议您阅读 GObject 手册和 Glib 对象系统简介。
GstElement
还提供了各种 GObject
信号,可用作灵活的回调机制。在这里,您也可以用来 gst-inspect
查看特定元素支持哪些信号。总之,信号和属性是元素和应用程序交互的最基本方式。
有关元件工厂的更多信息
在上一节中,我们简要介绍了 GstElementFactory
该对象作为创建元素实例的一种方式。然而,元素工厂远不止于此。元素工厂是从 GStreamer 注册表中检索到的基本类型,它们描述了 GStreamer 可以创建的所有插件和元素。这意味着元素工厂对于自动元素实例化(例如自动插件的作用)和创建可用元素列表非常有用。
使用工厂获取有关元素的信息
像 gst-inspect
这样的工具将提供有关元素的一些通用信息,例如编写插件的人、描述性名称(和简称)、排名和类别。该类别可用于获取可以使用此元素工厂创建的元素的类型。类别的示例包括 Codec/Decoder/Video
(视频解码器)、 Codec/Encoder/Video
(视频编码器)、 Source/Video
(视频生成器)、 Sink/Video
(视频输出),当然,所有这些也都存在于音频中。然后, Codec/Demuxer
Codec/Muxer
还有更多。 gst-inspect
将列出所有工厂的列表,并 gst-inspect <factory-name>
列出上述所有信息,以及更多。
可以使用 gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY)
来获取 GStreamer 所知道的所有元素工厂的列表。
找出元素可以包含哪些 pad
也许元素工厂最强大的功能是它们包含元素可以生成的的完整描述,以及这些 pad 的功能(通俗地说:哪些类型的媒体可以通过这些 pad 进行流式传输),而无需实际将这些插件加载到内存中。这可用于为编码器提供解码器选择列表,也可以用于媒体播放器的自动插入目的。当前所有基于 GStreamer 的媒体播放器和自动插件都以这种方式工作。我们将在 GstPad
GstCaps
下一章中更深入地了解这些功能:Pads 和 capabilities
链接元素
通过将源元素与零个或多个类似筛选器的元素以及最终的接收器元素链接起来,可以设置媒体管道。数据将流经元素。这是 GStreamer 中媒体处理的基本概念。
通过链接这三个元素,我们创建了一个非常简单的元素链。这样做的效果是,源元素的输出将用作类似过滤器的元素的输入。类似筛选器的元素将对数据执行某些操作,并将结果发送到最终的接收器元素。
在代码中,上面的图是这样写的:
1 |
|
对于更具体的行为,还有函数 gst_element_link ()
和 gst_element_link_pads ()
.您还可以获取对单个焊盘的引用,并使用各种 gst_pad_link_* ()
功能链接这些焊盘。有关更多详细信息,请参阅 API 参考。
重要提示:在链接元素或管道之前,必须将元素添加到图格或管道中,因为将元素添加到图格中会断开任何已存在的链接。此外,不能直接链接不在同一 bin 或管道中的元素;如果要链接不同层次结构级别的元素或填充物,则需要使用 ghost pads(稍后将详细介绍 ghost pads)。
元素状态
创建后,元素实际上不会执行任何操作。您需要更改元素状态以使其执行某些操作。GStreamer 知道四种元素状态,每种状态都有非常具体的含义。这四个状态是:
GST_STATE_NULL
:这是默认状态。在此状态下不会分配任何资源,因此,过渡到该状态将释放所有资源。当元素的 refcount 达到 0 并被释放时,该元素必须处于此状态。GST_STATE_READY
:在就绪状态下,元素已分配其所有全局资源,即可以保留在流中的资源。您可以考虑打开设备、分配缓冲区等。但是,流不会在此状态下打开,因此流位置自动为零。如果以前打开了流,则应在此状态下关闭该流,并应重置位置、属性等。GST_STATE_PAUSED
:在此状态下,元素已打开流,但未主动处理它。允许元素修改流的位置、读取和处理数据等,以便在状态更改为 PAUSE 后立即准备播放,但不允许播放会使时钟运行的数据。总之,PAUSED 与 PLAYING 相同,但没有运行时钟。进入
PAUSED
状态的元素应为尽快进入PLAYING
状态做好准备。例如,视频或音频输出将等待数据到达并对其进行排队,以便它们可以在状态更改后立即播放。此外,视频接收器已经可以播放第一帧(因为这还不会影响时钟)。自动插拔器可以使用相同的状态转换来将管道插入在一起。但是,大多数其他元素(如编解码器或筛选器)不需要在此状态下显式执行任何操作。GST_STATE_PLAYING
:在PLAYING
状态中,元素的操作与PAUSED
状态中的元素完全相同,只是时钟现在运行。
可以使用函数 gst_element_set_state ()
更改元素的状态。如果将元素设置为另一种状态,GStreamer 将在内部遍历所有中间状态。因此,如果将元素从 NULL
设置为 PLAYING
,GStreamer 将在内部将元素设置为介 READY
于 和 PAUSED
之间。
移动到 GST_STATE_PLAYING
时,管道将自动处理数据。它们不需要以任何形式进行迭代。在内部,GStreamer 将启动线程来为他们承担此任务。GStreamer 还将负责将消息从管道的线程切换到应用程序自己的线程,方法是使用 GstBus
.有关详细信息,请参阅 Bus 文档。
当您将 bin 或管道设置为特定目标状态时,它通常会自动将状态更改传播到 bin 或管道中的所有元素,因此通常只需设置顶级管道的状态即可启动或关闭管道。但是,当动态地将元素添加到已经运行的管道中时,例如从“pad 添加”信号回调中,您需要使用 gst_element_set_state ()
或 gst_element_sync_state_with_parent ()
自行将其设置为所需的目标状态。
Bins 箱
bin 是容器元素。您可以将元素添加到 bin 中。由于 bin 本身就是一个元素,因此 bin 的处理方式与任何其他元素相同。因此,上一章(元素)也适用于 bin。
bin 允许您将一组链接的元素组合成一个逻辑元素。您不再处理单个元素,而只处理一个元素,即 bin。我们将看到,当您要构建复杂的管道时,这非常强大,因为它允许您将管道分解为更小的块。
bin 还将管理其中包含的元素。它将对元素执行状态更改,以及收集和转发总线消息。
GStreamer 程序员可以使用一种特殊类型的 bin:
- 管道:管理所包含元素的同步和总线消息的通用容器。顶层 bin 必须是一个管道,因此每个应用程序至少需要其中一个。
Creating a bin
bin 的创建方式与其他元素的创建方式相同,即使用元素工厂。还有便利功能可用( gst_bin_new ()
和 gst_pipeline_new ()
)。要将元素添加到 bin 中或从 bin 中删除元素,可以使用 gst_bin_add ()
和 gst_bin_remove ()
。请注意,添加元素的 bin 将获得该元素的所有权。如果销毁 bin,则该元素将与它一起取消引用。如果从 bin 中删除元素,则该元素将自动取消引用。
1 |
|
有多种功能可以在 bin 中查找元素。最常用的是 gst_bin_get_by_name ()
和 gst_bin_get_by_interface ()
。您还可以使用函数 gst_bin_iterate_elements ()
循环访问 bin 包含的所有元素。有关详细信息,请参阅GstBin
API 参考。
Bin 管理其子项的状态
Bins 管理其中包含的所有元素的状态。如果使用 gst_element_set_state ()
将 bin(或管道,这是一种特殊的顶级 bin 类型)设置为特定目标状态,它将确保其中包含的所有元素也将设置为此状态。这意味着通常只需设置顶级管道的状态即可启动或关闭管道。
bin 将对其从 sink 元素到源元素的所有子元素执行状态更改。这可确保下游元素在上游元素被带到 PAUSED
或 PLAYING
时准备好接收数据。同样,在关闭时,接收器元素将设置为 READY
or NULL
first,这将导致上游元素收到 FLUSHING
错误,并在元素设置为 READY
or NULL
状态之前停止流线程。
但是请注意,如果元素被添加到已经在运行的 bin 或管道中,例如从“pad-added”信号回调中,其状态不会自动与添加它的 bin 或管道的当前状态或目标状态保持一致。相反,您需要自己使用 gst_element_set_state ()
或 gst_element_sync_state_with_parent ()
在将元素添加到已运行的管道时将其设置为所需的目标状态。
Bus 总线
总线是一个简单的系统,它负责将消息从流式处理线程转发到其自己的线程上下文中的应用程序。总线的优点是,即使 GStreamer 本身是大量线程的,应用程序也不需要线程感知即可使用 GStreamer。
默认情况下,每个管道都包含总线,因此应用程序不需要创建总线或任何内容。应用程序唯一应该做的就是在总线上设置消息处理程序,这类似于对象的信号处理程序。当主循环运行时,会定期检查总线是否有新消息,当有消息可用时会调用回调。
有两种不同的总线使用方式:
运行 GLib/Gtk+ 主循环(或自己定期迭代默认的 GLib 主上下文)并将某种监视连接到总线上。这样,GLib 主循环将检查总线是否有新消息,并在有消息时通知您。
通常,在这种情况下,您会使用
gst_bus_add_watch ()
orgst_bus_add_signal_watch ()
。要使用总线,请使用
gst_bus_add_watch ()
将消息处理程序附加到管道的总线上。每当管道向总线发出消息时,都会调用此处理程序。在此处理程序中,检查信号类型(请参阅下一节)并执行相应的操作。处理程序的返回值应该是TRUE
保持处理程序连接到总线,返回FALSE
以删除它。自行检查 bus 上的消息。这可以使用
gst_bus_peek ()
和/或gst_bus_poll ()
来完成。
1 |
|
重要的是要知道处理程序将在 mainloop 的线程上下文中调用。这意味着管道和应用程序之间通过总线的交互是异步的,因此不适合某些实时目的,例如音轨之间的交叉淡入淡出、执行(理论上)无缝播放或视频效果。所有这些事情都应该在管道上下文中完成,这可以通过编写 GStreamer 插件来获得最简单的操作。不过,它对于其主要目的非常有用:将消息从管道传递到应用程序。这种方法的优点是 GStreamer 在内部执行的所有线程都对应用程序隐藏,应用程序开发人员根本不需要担心线程问题。
请注意,如果您使用的是默认的 GLib 主环路集成,则可以连接到总线上的“消息”信号,而不是连接总线。这样,您就不必 switch()
处理所有可能的消息类型;只需以 的形式 message::<type>
连接到感兴趣的信号,其中 <type>
是特定的消息类型(有关消息类型的说明,请参阅下一节)。
上面的片段也可以写成:
1 | GstBus *bus; |
如果不使用 GLib 主循环,则默认情况下异步消息信号将不可用。但是,您可以安装一个自定义同步处理程序,该处理程序用于唤醒自定义主循环并用于 gst_bus_async_signal_func ()
发出信号。(有关详细信息,另请参阅文档)
消息类型
GStreamer 有一些预定义的消息类型,可以通过总线传递。但是,这些消息是可扩展的。插件可以定义其他消息,应用程序可以决定为这些消息提供特定代码或忽略它们。强烈建议所有应用程序至少通过向用户提供视觉反馈来处理错误消息。
所有消息都有消息源、类型和时间戳。消息源可用于查看发出消息的元素。例如,对于某些消息,只有顶级管道发出的消息对大多数应用程序(例如状态更改通知)感兴趣。下面是所有消息的列表,以及它们的作用以及如何解析消息特定内容的简短说明。
Pads 和 capabilities
正如我们在 Elements 中看到的,pads 是元素与外界的接口。数据从一个元素的 source pad 流到另一个元素的 sink pad。元素可以处理的特定类型的媒体将由 pads 的功能公开。我们将在本章后面详细讨论功能(请参阅 Capabilities of a pad)。
Pads
Pad 类型由两个属性定义:其方向和可用性。正如我们之前提到的,GStreamer 定义了两个 pad 方向:源 pad 和接收 pad。该术语是从元素内部的视图定义的:元素在其接收 pad 上接收数据,并在其源 pad 上生成数据。从原理上讲,接收 pad 绘制在元素的左侧,而源 pad 绘制在元素的右侧。在此类图形中,数据从左向右流动。
与 pad 可用性相比,pad 方向非常简单。pad 可以有三种可用性中的任何一种:always, sometimes and on-request。这三种类型的含义正如它所说的那样:always pad 始终存在,sometimes pad 只存在于特定情况下(并且可以随机消失),并且 on-request pad 仅在应用程序明确请求时才会出现。
Dynamic (or sometimes) pads
创建元素时,某些元素可能没有所有 pad。例如,使用 Ogg 解复用器元件时可能会发生这种情况。当该元素在 Ogg 流中检测到这样的流时,它将读取 Ogg 流并为每个包含的基本流(vorbis、theora)创建动态 pad。同样,它将在流结束时删除 pad。例如,此原理对于解复用器元件非常有用。
运行 gst-inspect-1.0 oggdemux
将显示该元素只有一个焊盘:一个名为“sink”的 sink 焊盘。其他焊盘处于“休眠状态”。您可以在 pad 模板中看到这一点,因为有一个“可用性:有时”属性。根据您播放的 Ogg 文件的类型,将创建 pad。我们将看到,当您要创建动态管道时,这一点非常重要。您可以将信号处理程序附加到元素,以便在元素从其“sometimes” pad 模板之一创建新 pad 时通知您。以下代码段是执行此操作的示例:
1 |
|
仅从“pad-added”回调中向管道添加元素的情况并不少见。如果执行此操作,请不要忘记使用 gst_element_set_state ()
或 gst_element_sync_state_with_parent ()
将新添加元素的状态设置为管道的目标状态。
Request pads
元素也可以具有请求 pad。这些 pad 不是自动创建的,而只是按需创建。这对于多路复用器、聚合器和 T 恤元件非常有用。聚合器是将多个输入流的内容合并到一个输出流中的元素。Tee 元素则相反:它们是具有一个输入流并将此流复制到每个输出 pad 的元素,这些输出 pad 是根据请求创建的。每当应用程序需要流的另一个副本时,它只需从 tee 元素请求新的输出 pad 即可。
以下代码段演示如何从“tee”元素请求新的输出 pad :
1 | static void some_function (GstElement * tee) |
该 gst_element_request_pad_simple ()
方法可用于根据 pad 模板的名称从元素中获取 pad。也可以请求与另一个 pad 模板兼容的 pad。如果要将元件链接到多路复用器元件,并且需要请求兼容的 pad ,这将非常有用。该方法 gst_element_get_compatible_pad ()
可用于请求兼容的 pad,如下例所示。它将从任何输入的 Ogg 多路复用器请求兼容 pad。
1 | static void |
Capabilities of a pad
由于 pad 在外界如何看待元素方面起着非常重要的作用,因此使用 capabilities 实现了一种机制来描述可以流过 pad 或当前流经 pad 的数据。在这里,我们将简要描述什么是 capabilities 以及如何使用它们,足以理解这个概念。
capabilities 附加到 pad 模板和 pad 上。对于 pad 模板,它将描述可能流式传输通过从此模板创建的 pad 的媒体类型。对于 pad ,它可以是可能的上限列表(通常是 pad 模板功能的副本),在这种情况下, pad 尚未协商,或者它是当前流经此 pad 的媒体类型,在这种情况下, pad 已经协商好了。
Dissecting capabilities 解剖能力
打击垫的功能在 GstCaps
对象中描述。在内部,a GstCaps
将包含一个或多个 GstStructure
将描述一种媒体类型的内容。协商 pad 将具有仅包含一个结构的功能集。此外,此结构将仅包含固定值。对于未协商的 pad 或 pad 模板,这些约束不成立。
例如,下面是“vorbisdec”元素功能的转储,您将通过运行 gst-inspect vorbisdec
.您将看到两个 pad :源 pad 和接收 pad 。这两个 pad 始终可用,并且都附加了功能。接收器 pad 将接受 vorbis 编码的音频数据,媒体类型为“audio/x-vorbis”。源 pad 将用于将原始(解码)音频样本发送到下一个元素,其原始音频媒体类型(在本例中为“audio/x-raw”)。源 pad 还将包含音频采样率和通道数量的属性,以及一些您现在无需担心的属性。
使用什么 capabilities
capabilities(简称:caps)描述在两个 pad 之间传输的数据类型,或者一个 pad(模板)支持的数据类型。这使得它们对于各种目的非常有用:
Autoplugging:根据其功能自动查找要链接到 pad 的元素。所有自动插入器都使用此方法。
Compatibility detection:当两个 pad 连接时,GStreamer 可以验证两个 pad 是否正在谈论相同的媒体类型。连接两个 pad 并检查它们是否兼容的过程称为“上限协商”。
Metadata:通过读取 pad 的功能,应用程序可以提供有关通过 pad 传输的媒体类型的信息,即有关当前正在播放的流的信息。
Filtering:应用程序可以使用功能将两个 pad 之间流式传输的可能媒体类型限制为其支持的流类型的特定子集。例如,应用程序可以使用“过滤上限”来设置应在两个 pad 之间流式传输的特定(固定或非固定)视频大小。您将在本手册后面的“手动向管道添加或删除数据”中看到过滤上限的示例。您可以通过将 capsfilter 元素插入管道并设置其“caps”属性来进行 caps 过滤。 Caps 过滤器通常放置在 audioconvert、audioresample、videoconvert 或 videoscale 等转换器元素之后,以强制这些转换器在流中的某个点将数据转换为特定的输出格式。
Using capabilities for metadata
垫可以附加一组(即一个或多个)功能。功能 ( GstCaps
) 表示为一个或多个 GstStructure
的数组,每个 GstStructure
是一个字段数组,其中每个字段由一个字段名称组成字符串(例如“width”)和键入的值(例如 G_TYPE_INT
或 GST_TYPE_INT_RANGE
)。
请注意,pad 的可能功能(即,通常您发现的 pad 模板的上限,如 gst-inspect 中所示)、pad 允许的上限(可以与 pad 的上限相同)之间存在明显差异。模板上限或其子集,具体取决于对等 pad 的可能上限)和最后协商的上限(这些描述了流或缓冲区的确切格式,并且仅包含一个结构,并且没有像范围或列表之类的可变位,即。它们是固定 caps)。
您可以通过查询一个结构的各个属性来获取一组功能中的属性值。您可以使用 gst_caps_get_structure ()
从大写中获取结构,并使用 gst_caps_get_size ()
获取 GstCaps
中的结构数量。
当 Caps 仅包含一种结构时,称为 simple caps ;当 Caps 仅包含一种结构且没有可变字段类型(如可能值的范围或列表)时,称为 fixed caps 。另外两种特殊类型的 caps 是 ANY caps 和 empty caps。
以下是如何从一组固定视频上限中提取宽度和高度的示例:
1 | static void read_video_props (GstCaps *caps) |
Creating capabilities for filtering
虽然功能主要在插件内部用于描述 pad 的媒体类型,但应用程序程序员通常还必须对功能有基本的了解,以便与插件交互,尤其是在使用 filtered caps 时。当您使用 filtered caps 或 fixation 时,您将允许在两个 pad 之间传输的媒体类型限制为其支持的媒体类型的子集。您可以使用管道中的 capsfilter
元素来执行此操作。为此,您还需要创建自己的 GstCaps
。最简单的方法是使用函数
1 | static gboolean |
这将强制这两个元素之间的数据流达到特定的视频格式、宽度、高度和帧速率(或者,如果在所涉及的元素的上下文中无法实现链接将失败)。请记住,当您使用 gst_element_link_filtered ()
时,它会自动为您创建一个 capsfilter
元素,并将其插入到您要连接的两个元素之间的容器或管道中(如果您曾经想要断开这些元件的连接,因为这样您就必须将这两个元件与 capsfilter 断开连接)。
Buffers and Events 缓冲区和事件
流经管道的数据由缓冲区和事件的组合组成。缓冲区包含实际的媒体数据。事件包含控制信息,例如寻找信息和流结束通知程序。所有这些都会在管道运行时自动流过。本章主要是为了向您解释这个概念;您不需要为此做任何事情。
Buffers 缓冲器
缓冲区包含将流经您创建的管道的数据。源元素通常会创建一个新的缓冲区,并将其通过 pad 传递到链中的下一个元素。当使用 GStreamer 基础设施创建媒体管道时,您不必自己处理缓冲区;这些元素会为你做到这一点。
除其他外,缓冲区还包括:
指向内存对象的指针。内存对象封装了内存中的一个区域。
缓冲区的时间戳。
指示有多少元素正在使用此缓冲区的引用计数。当没有元素引用缓冲区时,该引用计数将用于销毁缓冲区。
缓冲区标志。
简单的情况是创建一个缓冲区,分配内存,将数据放入其中,然后传递到下一个元素。该元素读取数据,执行某些操作(例如创建新缓冲区并对其进行解码),然后取消引用该缓冲区。这会导致数据被释放并且缓冲区被破坏。典型的视频或音频解码器的工作原理如下。
不过,还有更复杂的场景。元素可以就地修改缓冲区,即无需分配新缓冲区。元素还可以写入硬件内存(例如来自视频捕获源)或从 X 服务器分配的内存(使用 XShm)。缓冲区可以是只读的,等等。