Pipeline 生命周期、状态机与 GStreamer 引用所有权
专栏:GStreamer C++ 从零到工程实战 · 第 7 篇 / 共 17 篇
系统掌握 Pipeline、Bin、NULL/READY/PAUSED/PLAYING、Preroll、Live Source,并用 RAII 理清 GstObject 与 GstMiniObject 的引用所有权。
第 6 课:Pipeline / Bin / State / Preroll
这一课非常重要,因为到现在为止,我们只是认识了“零件”:
Plugin
↓
Factory
↓
Element
↓
Pad / Property
但真正运行起来时,还需要回答三个问题:
这些 Element 放在哪里?
谁统一管理它们?
整个媒体系统怎么启动、暂停、停止?
答案就是:
Bin
Pipeline
State
一、为什么不能只创建 Element?
假设你创建了三个 Element:
videotestsrc
videoconvert
autovideosink
它们现在只是三个独立对象:
Element A
Element B
Element C
即使你把 Pad 连起来:
A → B → C
还缺一个东西:
谁来统一管理这组 Element?
比如:
全部启动
全部暂停
全部停止
统一处理时钟
统一接收消息
统一管理生命周期
如果 Application 自己一个个管:
start(A);
start(B);
start(C);
pause(A);
pause(B);
pause(C);
stop(A);
stop(B);
stop(C);
很快就会乱。
所以 GStreamer 引入:
Bin
二、什么是 Bin?
可以把 Bin 理解为:
Element 的容器。
比如:
GstBin
┌──────────────────────────┐
│ │
│ Source → Convert → Sink │
│ │
└──────────────────────────┘
它里面可以装:
Element
Element
Element
…
可以类比普通对象树:
QObject
└── child QObject
或者 UI:
QWidget
├── QPushButton
├── QLabel
└── QLineEdit
但是不要完全等同。
这里最关键的是:
Bin 可以把一组 Element 当成一个整体管理。
比如:
VideoBin
┌──────────────────────────┐
│ Decoder → Convert → Scale│
└──────────────────────────┘
Application 不一定需要关心内部三个 Element。
对外可以把:
VideoBin
看成一个整体。
三、一个很漂亮的设计:Bin 本身也是 Element
这点特别重要。
GStreamer 的层次大致是:

图:GstObject、GstElement、GstBin 与 GstPipeline 的继承关系
也就是说:
GstBin IS-A GstElement
所以:
一个 Bin 里面可以装 Element,而 Bin 本身又可以作为更大 Bin 的一个 Element。
这样就可以无限组合。
比如:
Pipeline
│
├── Source
│
├── VideoBin
│ ├── Decoder
│ ├── Convert
│ └── Scale
│
└── Sink
甚至:
Pipeline
│
├── InputBin
├── DecodeBin
├── ProcessingBin
└── OutputBin
这是一种非常典型的层次化组合设计。
四、那 Pipeline 又是什么?
你可以先记一句:
Pipeline 是最顶层的 Bin。
也就是:
GstPipeline
↓
GstBin
↓
GstElement
普通 Bin:
一组 Element 的容器
Pipeline:
整个媒体处理系统的顶层容器
例如:
Pipeline
┌────────────────────────────────────────┐
│ │
│ videotestsrc → convert → videosink │
│ │
└────────────────────────────────────────┘
所以以后我们写:
GstElement *pipeline =
gst_pipeline_new(\”pipeline\”);
虽然变量类型经常写成:
GstElement*
但真实对象类型是:
GstPipeline
因为它也是 Element。
五、Pipeline 比普通 Bin 多做了什么?
Pipeline 不只是“最大的盒子”。
它还承担一些顶层职责,比如:
Clock
Bus
State synchronization
整体运行管理
所以可以粗略理解:
GstPipeline
┌───────────────────────────────────┐
│ │
│ Element → Element → Element │
│ │
│ 统一 State │
│ 统一 Clock │
│ 提供 Bus │
│ │
└───────────────────────────────────┘
你以后 Application 通常不会分别操作每个 Element。
而是主要操作:
Pipeline
例如:
gst_element_set_state(
pipeline,
GST_STATE_PLAYING
);
意思不是:
“只让 Pipeline 这个对象 PLAYING。”
而是:
让整个 Pipeline 及其内部 Element 进入对应运行状态。
六、为什么 Element 必须 add 到 Pipeline?
这是个非常重要的问题。
假设:
GstElement *source =
gst_element_factory_make(\”videotestsrc\”, \”source\”);
GstElement *sink =
gst_element_factory_make(\”autovideosink\”, \”sink\”);
此时:
source
sink
只是两个独立对象。
如果创建:
pipeline
但不 add:
pipeline
source
sink
三者依旧互不属于。
所以要:
gst_bin_add_many(
GST_BIN(pipeline),
source,
sink,
nullptr
);
变成:
Pipeline
┌──────────────────────────┐
│ │
│ source sink │
│ │
└──────────────────────────┘
这一步叫:
把 Element 加入 Bin
然后才去:
gst_element_link(source, sink);
形成:
Pipeline
┌──────────────────────────┐
│ │
│ source ───────
网硕互联帮助中心




评论前必须登录!
注册