GStreamer一个多媒体框架,用来做多媒体播放器以及一些与之相关的应用都是一个不错的选择,当然这里指的多是Linux平台。如果你的平台是windows那不防可以考虑一下DirectShow等其它一些框架。
好吧,关于框架我先说到这里,先点到为止吧。如果后期时间允许我会单独的说说这些东西的。
开始说说gstreamer的caps协商过程吧。
说到gstreamer其实主要有两部分组成,element和pad。当然说到caps的协商就与它们两有着不可回避的联系了。
对于element:
在创建element时,你可以先定义一个模板,它会对你的element的caps有一个大致的约束,代码如下:
其中关于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如果对其中的任何信息有兴趣,便可以在这个地方获取了;
主要用的函数有:
gst_xxx_get_caps()实现细节:这个函数主要是在两个element link获取其pad的caps时被调用,所以一般返回的属性的范围。
主要调用的函数有:
最后一步就是要设置在gst_xxx_chain()中的buffer的caps了,如果不去设定程序一般回出现一些不可预知的问题,如程序hung住不动。
gst_xxx_chain()的简单实现:
其中注意函数gst_buffer_make_metadata_writable()它的实现是:
好吧,关于框架我先说到这里,先点到为止吧。如果后期时间允许我会单独的说说这些东西的。
开始说说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 == 1
ret = buf;
} else {
ret = gst_buffer_create_sub (buf, 0, GST_BUFFER_SIZE (buf)); //这个函数的意思是根据buf的信息创建一个新的buf
gst_buffer_unref (buf); //注意它已经把原始的buf释放了,我们在外面就不需要再做什么了
}
return ret;
}