GStreamer一个多媒体框架,用来做多媒体播放器以及一些与之相关的应用都是一个不错的选择,当然这里指的多是Linux平台。如果你的平台是windows那不防可以考虑一下DirectShow等其它一些框架。
好吧,关于框架我先说到这里,先点到为止吧。如果后期时间允许我会单独的说说这些东西的。
开始说说gstreamer的caps协商过程吧。
说到gstreamer其实主要有两部分组成,element和pad。当然说到caps的协商就与它们两有着不可回避的联系了。
对于element:
在创建element时,你可以先定义一个模板,它会对你的element的caps有一个大致的约束,代码如下:
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",GST_PAD_SINK,GST_PAD_ALWAYS,GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb; image/jpeg; image/png"));static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",GST_PAD_SRC,GST_PAD_ALWAYS,GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb; image/jpeg; image/png"));static void
gst_xxx_class_init (GstxxxClass * klass)gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory));gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory));
}static void
gst_xxx_init (Gstxxx * filter,GstxxxClass * gclass)
{filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");gst_pad_set_event_function(filter->sinkpad, gst_xxx_event);
// gst_pad_set_getcaps_function (filter->sinkpad, gst_pad_proxy_getcaps);gst_pad_set_setcaps_function (filter->sinkpad, gst_xxx_set_caps);gst_pad_set_getcaps_function (filter->sinkpad, gst_xxx_get_caps);gst_pad_set_chain_function (filter->sinkpad, gst_xxx_chain);gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");gst_pad_set_getcaps_function (filter->srcpad, gst_xxx_query);gst_pad_set_setcaps_function (filter->srcpad, gst_xxx_set_caps);gst_pad_set_getcaps_function (filter->srcpad, gst_xxx_get_caps);gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);GST_DEBUG_FUNCPTR(gst_xxx_set_caps);GST_DEBUG_FUNCPTR(gst_xxx_get_caps);GST_DEBUG_FUNCPTR(gst_xxx_chain);GST_DEBUG_FUNCPTR(gst_xxx_event);
}
其中关于caps协商的主要函数有gst_xxx_set_caps()、gst_xxx_get_caps()和gst_xxx_chain()
先说这个_set_caps()和_get_caps():
这两个函数属于基础层的函数,当你调用gst_pad_set_caps()和gst_pad_get_caps()这两个函数时,最后都会在你设置的这两个函数中使用。
所以注意初学者,在写plugin的时候请谨慎的调用gst_pad_set_caps()和gst_pad_get_caps()。
当程序运行时(这里只针对Downstream的模式)
你的sink_pad中的set_caps函数将会率先被上游模块调用:
gst_xxx_set_caps()实现细节:获取本element的src_pad并获取其中的caps然后和sink_pad的caps做一次交叉,将交叉结果继续往下游发送;当然其中你的element如果对其中的任何信息有兴趣,便可以在这个地方获取了;
主要用的函数有:
in_templ = gst_pad_get_pad_template_caps (in_pad);gst_pad_get_caps (opeer);intersect = gst_caps_intersect (peercaps, transform);caps = gst_caps_copy_nth (intersect, 0);gst_caps_unref (intersect);structure = gst_caps_get_structure (caps, 0);gst_structure_fixate_field_nearest_fraction (structure, "framerate", rate_numerator, rate_denominator);gst_structure_get_fraction (structure, "framerate", &rate_numerator, &rate_denominator);
gst_xxx_get_caps()实现细节:这个函数主要是在两个element link获取其pad的caps时被调用,所以一般返回的属性的范围。
主要调用的函数有:
gst_pad_peer_get_caps (otherpad);in_templ = gst_pad_get_pad_template_caps (in_pad);gst_pad_get_caps (opeer);intersect = gst_caps_intersect (peercaps, transform);gst_caps_unref (caps);caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
注:一般的caps可以先用capsfile先做约束
最后一步就是要设置在gst_xxx_chain()中的buffer的caps了,如果不去设定程序一般回出现一些不可预知的问题,如程序hung住不动。
gst_xxx_chain()的简单实现:
static GstFlowReturn
gst_xxx_chain (GstPad * pad, GstBuffer * buf)
{GstFlowReturn ret;Gstxxx *filter;GstBuffer *outbuf;filter = GST_XXX (GST_OBJECT_PARENT (pad));if (filter->silent == TRUE)return gst_pad_push (filter->srcpad, buf);outbuf = gst_buffer_make_metadata_writable(buf);gst_buffer_set_caps(outbuf, filter->srcpad->caps);ret = gst_pad_push (filter->srcpad, outbuf);return ret;
}
其中注意函数gst_buffer_make_metadata_writable()它的实现是:
GstBuffer *
gst_buffer_make_metadata_writable (GstBuffer * buf)
{GstBuffer *ret;if (gst_buffer_is_metadata_writable (buf)) { //这个地方很有意思,它实际判断buf->refcount == 1ret = buf;} else {ret = gst_buffer_create_sub (buf, 0, GST_BUFFER_SIZE (buf)); //这个函数的意思是根据buf的信息创建一个新的bufgst_buffer_unref (buf); //注意它已经把原始的buf释放了,我们在外面就不需要再做什么了}return ret;
}
