Gstreamer之Caps协商

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 == 1
    ret = buf;
  } else {
    ret = gst_buffer_create_sub (buf, 0, GST_BUFFER_SIZE (buf)); //这个函数的意思是根据buf的信息创建一个新的buf
    gst_buffer_unref (buf); //注意它已经把原始的buf释放了,我们在外面就不需要再做什么了
  }


  return ret;
}


-流媒体-
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值