Gstreamer中的pad根据输入输出方向,有src和sink两种。根据pad创建的时机,有always pad、sometimes pad、request pad,这样不同的pad,链接方式就不同。
pad相当与element的接口,element间的连接,实质上就是pad间的连接,所以这里总结下pad的链接。
always pad
gst_bin_add()
将element添加到bin或者pipeline里面。sometimes pad
pad-added
signal触发,调用回调函数才行。request pad
filter link
初始时没有pad的element(如uridecodebin),pad会在数据流到element时才会创建,这种pad被成为Sometimes Pad
,不同于Always Pad
,sometimes pad不能通过gst_element_link_many直接将两个element link起来,需要根据pad-added
信号,在pad创建后,在对应的回调函数里面链接pad到对应的pad之上才可以。
// gst-plugins-good/tests/examples/equalizer/demo.c
/* Uri decoding */
decodebin = gst_element_factory_make ("uridecodebin", "decoder");
g_object_set (G_OBJECT (decodebin), "uri", argv[1], NULL);
/* Force float32 samples */
decconvert = gst_element_factory_make ("audioconvert", "decconvert");
/* Handle dynamic pads */
g_signal_connect (G_OBJECT (decodebin), "pad-added",
G_CALLBACK (dynamic_link), gst_element_get_static_pad (decconvert, "sink"));
// pad-added的回调函数
static void
dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer user_data)
{
GstPad *target = GST_PAD (user_data);
gst_pad_link (newpad, target);
gst_object_unref (target);
}
// subprojects/gst-plugins-good/tests/examples/equalizer/demo.c
gst_bin_add_many (GST_BIN (bin), decodebin, decconvert, capsfilter, equalizer, spectrum, sinkconvert, sink, NULL);
if (!gst_element_link_many (decconvert, capsfilter, equalizer, spectrum, sinkconvert, sink, NULL)) {
fprintf (stderr, "can't link elements\n");
exit (1);
}
/* Handle dynamic pads */
g_signal_connect (G_OBJECT (decodebin), "pad-added",
G_CALLBACK (dynamic_link), gst_element_get_static_pad (decconvert,
"sink"));
pipeline原型:
uridecodebin! parsebin ! decodebin
代码:
uridecodebin_ = gst_element_factory_make("uridecodebin", "uridec");
parsebin_ = gst_element_factory_make("parsebin", "parser");
decodebin_ = gst_element_factory_make("decodebin", "decodebin");
gst_bin_add_many (GST_BIN(pipeline_), uridecodebin_, parsebin_, decodebin_, NULL);
g_signal_connect (G_OBJECT (uridecodebin_), "pad-added",
G_CALLBACK (link_uridec_parsebin_cb), gst_element_get_static_pad (parsebin_, "sink"));
g_signal_connect (G_OBJECT (parsebin_), "pad-added",
G_CALLBACK (link_parsebin_decbin_cb), gst_element_get_static_pad (decodebin_, "sink"));
g_signal_connect (G_OBJECT (parsebin_), "pad-added",
G_CALLBACK (link_decbin_aconv_cb),
gst_element_get_static_pad (audioconv_, "sink"));
下面这样是不行的,因为uridecodebin/parsebin/decodebin都不是awlays pad
:
if (!gst_element_link_many(uridecodebin_, parsebin_, NULL) ||
!gst_element_link_many(parsebin_, decodebin_, NULL) ||
!gst_element_link_many(decodebin_, audioconv_, NULL)) {
GST_ERROR("link many got error");
}
这段代码可以在gstreamer教程中找到,路径:
gst-docs/examples/tutorials/basic-tutorial-7.c
代码:
/* Manually link the Tee, which has "Request" pads */
tee_audio_pad = gst_element_request_pad_simple (tee, "src_%u");
g_print ("Obtained request pad %s for audio branch.\n",
gst_pad_get_name (tee_audio_pad));
queue_audio_pad = gst_element_get_static_pad (audio_queue, "sink");
tee_video_pad = gst_element_request_pad_simple (tee, "src_%u");
g_print ("Obtained request pad %s for video branch.\n",
gst_pad_get_name (tee_video_pad));
queue_video_pad = gst_element_get_static_pad (video_queue, "sink");
if (gst_pad_link (tee_audio_pad, queue_audio_pad) != GST_PAD_LINK_OK ||
gst_pad_link (tee_video_pad, queue_video_pad) != GST_PAD_LINK_OK) {
g_printerr ("Tee could not be linked.\n");
gst_object_unref (pipeline);
return -1;
}
gst_object_unref (queue_audio_pad);
gst_object_unref (queue_video_pad);
搜索gst_element_link_filtered,可以看到源码中很多地方都有用到,比较简单:
aresample_ = gst_element_factory_make("audioresample", "aresample");
aconv_ = gst_element_factory_make("audioconvert", "aconv");
GstCaps* filter;
filter = gst_caps_from_string
("audio/x-raw, format=(string)S16LE, rate=(int)16000");
if(!gst_element_link_filtered(aresample_, aconv_, filter)) {
GST_ERROR("failed to link audioresample and audioconvert !");
}
gst_caps_unref (filter);