概述
gstreamer提供了gst-launch工具,使用该工具我们可以很方便的搭建各种管道,比如gst-launc-1.0 videotestsrc ! autovideosink
输入上述命令,我们就能测试视频通路是否OK。但有些场景需要我们提供代码形式,而在gst-launch的管道转换为代码时,经常会遇到管道间连接失败的问题。本文主要总结gst元素不同pad类型间如何连接。
Always pad类型
以videotestsrc元素为例,该元素的Pad Templates类型为Always,该类型表示此gst元素一直存在pad,无需动态创建。同是这种类型的两个元素连接时,直接使用gst_element_link
或gst_element_link_many
进行连接即可。
Sometimes Pad类型
这种类型的pad我们以rtspsrc元素为例,如下是该元素的pad信息。这种类型的元素在连接时则不能直接使用gst_element_link
等接口,而是需要用到该元素的pad-added
的signal来实现。
比如管道命令:
gst-launch-1.0 rtspsrc location="rtsp://b1.dnsdojo.com:1935/live/sys3.stream" ! rtph264depay ! video/x-h264, stream-format=avc ! h264parse ! avdec_h264 ! video/x-raw,formate=NV12,width=1280,height=720 ! videoconvert ! autovideosink
如果使用gst_element_link(rtspsrc, rtph264depay)
,则会连接失败。此时应该用rtspsrc元素的pad-added
Signal处理函数通过Pad进行连接。
rtsp_source = gst_element_factory_make ("rtspsrc", "rtsp_source");
rtp_h264depay = gst_element_factory_make ("rtph264depay", "rtp_h264depay");
......
g_object_set (rtsp_source, "location", "rtsp://b1.dnsdojo.com:1935/live/sys3.stream", NULL);
......
g_signal_connect(rtsp_source, "pad-added", G_CALLBACK(cb_new_rtspsrc_pad), rtp_h264depay);
cb_new_rtspsrc_pad
的实现如下两种方式均可行:
方式一:
static void cb_new_rtspsrc_pad(GstElement *element, GstPad *pad, gpointer data)
{
gchar *name;
GstCaps * p_caps;
gchar * description;
GstElement *p_rtph264depay;
g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
name = gst_pad_get_name(pad);
p_caps = gst_pad_get_pad_template_caps (pad);
description = gst_caps_to_string(p_caps);
g_print("%s\n", description);
g_free(description);
p_rtph264depay = GST_ELEMENT(data);
// try to link the pads then ...
if(!gst_element_link_pads(element, name, p_rtph264depay, "sink")) {
g_print("Failed to link elements 3\n");
}
g_free(name);
}
方式二:
static void cb_new_rtspsrc_pad(GstElement *element, GstPad *pad, gpointer data)
{
GstPad *sink_pad = gst_element_get_static_pad (GST_ELEMENT(data), "sink");
GstPadLinkReturn ret;
GstCaps *pad_caps = NULL;
GstStructure *pad_caps_struct = NULL;
const gchar *pad_caps_type = NULL;
g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
/* If our converter is already linked, we have nothing to do here */
if (gst_pad_is_linked (sink_pad)) {
g_print ("We are already linked. Ignoring.\n");
goto exit;
}
/* Get the new pad's type */
pad_caps = gst_pad_get_current_caps (pad);
pad_caps_struct = gst_caps_get_structure (pad_caps, 0);
pad_caps_type = gst_structure_get_name (pad_caps_struct);
/* Attempt the link */
ret = gst_pad_link (pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret)) {
g_print ("Type is '%s' but link failed.\n", pad_caps_type);
} else {
g_print ("Link succeeded (type '%s').\n", pad_caps_type);
}
exit:
/* Unreference the new pad's caps, if we got them */
if (pad_caps != NULL)
gst_caps_unref (pad_caps);
/* Unreference the sink pad */
gst_object_unref (sink_pad);
}
Request Pad类型
典型的gst元素就是tee。获取元素的Request Pad接口为gst_element_get_request_pad
,而获取Always Pad的接口为gst_element_get_static_pad
。如下展示了tee元素与后端的两个queue元素的连接方法。
tee = gst_element_factory_make ("tee", "tee");
play_queue = gst_element_factory_make ("queue", "play_queue");
file_queue = gst_element_factory_make ("queue", "file_queue");
.........
/* Manually link the Tee, which has "Request" pads */
tee_play_pad = gst_element_get_request_pad (tee, "src_%u");
g_print ("Obtained request pad %s for play branch.\n", gst_pad_get_name (tee_play_pad));
queue_play_pad = gst_element_get_static_pad (play_queue, "sink");
tee_file_pad = gst_element_get_request_pad (tee, "src_%u");
g_print ("Obtained request pad %s for video branch.\n", gst_pad_get_name (tee_file_pad));
queue_file_pad = gst_element_get_static_pad (file_queue, "sink");
/* Begin to connect */
if (gst_pad_link (tee_play_pad, queue_play_pad) != GST_PAD_LINK_OK ||
gst_pad_link (tee_file_pad, queue_file_pad) != GST_PAD_LINK_OK) {
g_printerr ("Tee could not be linked.\n");
gst_object_unref (pipeline);
return -1;
}
Caps Filter 的创建
管道命令:gst-launch-1.0 rtspsrc location="rtsp://b1.dnsdojo.com:1935/live/sys3.stream" ! rtph264depay ! video/x-h264, stream-format=avc ! h264parse ! avdec_h264 ! video/x-raw,formate=NV12,width=1280,height=720 ! videoconvert ! autovideosink
上述管道命令中的video/x-h264, stream-format=avc
是一个过滤器,该过滤器仅允许满足需求的数据通过。过滤器创建和连接的方法如下:
caps_h264_byte = gst_caps_new_simple("video/x-h264", "stream-format", G_TYPE_STRING, "avc", NULL);
caps_video_format = gst_caps_new_simple("video/x-raw", "stream-format", G_TYPE_STRING,"NV12",
"alignment", G_TYPE_STRING, "au",
"width", G_TYPE_INT, 1280,
"height", G_TYPE_INT, 720, NULL);
if (!gst_element_link_filtered (rtp_h264depay, h264_parse, caps_h264_byte)) {
g_warning ("Failed to link rtp_h264depay and h264_parse!");
}
if (!gst_element_link_filtered (play_queue, video_convert, caps_video_format)) {
g_warning ("Failed to link play_queue and video_convert!");
}