好吧,關於框架我先說到這裏,先點到爲止吧。如果後期時間允許我會單獨的說說這些東西的。
開始說說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;
}