本节摘要:解封装类元件的衬垫要等读到流信息才出现,程序必须在"衬垫新增"信号里完成接线;监控、会议类应用还要在运行中增删整条支路。本节写全动态接线的标准代码与判断逻辑,再讲运行中增删分支的阻塞垫手法与顺序。承接上一节的总线,通往下一节的完整播放器,是监控与多路场景的机制基础。
回放第三章的一个场景:命令行里 decodebin ! sink 一气呵成,换成 C 代码静态链接却报"垫不存在"。原因在第二章埋过——解码装配器是混合形态元件,它的源垫是偶发衬垫,读到流信息才逐个长出来。命令行工具在底层替你监听了"衬垫新增"信号;自己写代码,这个监听必须补上。动态接线的完整逻辑分三步:信号里拿到新垫 → 判断新垫的媒体类型 → 对接到正确的下游支路。
// 装配器创建后立刻挂信号:回调参数三是预置的下游元件 g_signal_connect(decoder_bin, "pad-added", G_CALLBACK(on_pad_added), video_branch); static void on_pad_added(GstElement *dbin, GstPad *new_pad, gpointer user_data) { GstPad *sink_pad = gst_element_get_static_pad( GST_ELEMENT(user_data), "sink"); if (gst_pad_is_linked(sink_pad)) { // 已接则罢手 gst_object_unref(sink_pad); return; } GstCaps *new_caps = gst_pad_get_current_caps(new_pad); GstStructure *s = gst_caps_get_structure(new_caps, 0); const gchar *name = gst_structure_get_name(s); // 媒体类型名 if (!g_str_has_prefix(name, "video/x-raw")) { // 只接视频支 gst_caps_unref(new_caps); gst_object_unref(sink_pad); return; } if (gst_pad_link(new_pad, sink_pad) != GST_PAD_LINK_OK) { g_printerr("这一路接线失败 看能力集是否交集\n"); } gst_caps_unref(new_caps); gst_object_unref(sink_pad); }
三步各有讲究。第一步判已接:一次文件里同类型流可能出现多路,已接的支路直接放过;第二步看类型:音频流的新垫按媒体类型名转发给音频支路(真实播放器里这里是一张类型到支路的映射表);第三步接后查返回值:链接接口有明确的成败码,比"接上就不管"多一分保险。

动态接线解决"出生时不知道结构",热插拔解决"运行中要改结构"。两个典型场景:监控客户端要在多路摄像头之间切换画面源;录像分支要在播放中途随启随停。难点在于不能在数据还在管道里流动时直接动刀——正确姿势是先用阻塞垫把上游数据闸住,再动结构,最后放闸。
以"停止录像分支"为例,顺序是四步:阻塞分支入口的汇垫 → 收到阻塞确认 → 断开并移除整支(元件出箱、逐个减计)→ 解除上游阻塞。阻塞垫接口把"闸门"语义封装成一次调用加一个回调,官方教程的动态管线示例把这个流程走得很完整,照着敲一遍胜过读十遍。
// 阻塞上游源垫:回调里安全动刀 GstPad *srcpad = gst_element_get_static_pad(tee, "src_%u"); gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, block_cb, user_data, NULL); // block_cb 里执行 断链 出箱 减计 最后返回移除探针
增加分支的顺序相反:先把新支元件全部装箱链接好,再在阻塞保护下把它接到分流器上。先备好后开门,新支就不会接到一半被数据冲进来。
⚠️ 常见坑:增删分支不设阻塞保护。症状极具迷惑性——测试时一切正常,压测时随机死锁或崩溃。原因是在途数据恰好撞上结构变更窗口。动态结构操作必须走阻塞流程,这是硬规矩,不是优化项。
| 场景 | 触发方式 | 关键动作 | 顺序铁律 |
|---|---|---|---|
| 接偶发衬垫 | 衬垫新增信号 | 判已接查类型再接 | 挂信号要早 |
| 删运行分支 | 阻塞垫探针 | 断链出箱减计 | 先闸后拆 |
| 增运行分支 | 阻塞垫探针 | 备好整支再接 | 先备后接 |
| 换播放源 | 状态降级后改属性 | 换位置属性再升状态 | 降改升 |
💡 关键直觉:动态管线的心法是"结构变更当作事务"——有闸门、有确认、有顺序、有回滚路径。把它当随手改配置,压测会教你做人。
动态结构的正确性压测不出来就等于没有。三层测试各管一段。单元层:动态接线的回调函数单独测——构造假的新垫与假的能力集,断言类型分流与链接结果。管线层:把"换源、增删分支、反复播放"写成循环脚本,跑几百次断言零失败——8.2 节的概率性故障正是靠这类循环测试现形。压力层:在多路满载下做动态操作,验证阻塞保护在真实负载下同样成立——空载压测通过、满载偶发死锁的缺陷只有这层能抓到。
三层之外再记一条军规:动态操作一律经由同一个入口函数(封装"闸门、变更、放闸"三步),散落在各处的动态代码是维护期最大的隐患来源——入口统一,顺序铁律才有执行保证。
听与接都到手,下一章的合成节把全部机制浇筑成一个完整的播放器程序——主线项目的第一个里程碑。