搜尋此網誌

2011年1月5日 星期三

gstreamer caps negotiation

协商过程中主要函数:
gst_pad_get_caps/gst_pad_set_getcaps_function, gst_pad_set_caps/gst_pad_set_setcaps_function。

gst_pad_get_caps 函数用来返回该pad能接受的caps。首先检查getcaps函数指针是否为NULL,如果不是则调用getcaps函数,这是一个函数指针,我们可以通过gst_pad_set_getcaps_function来给这个函数指针赋值,从而实现自定义的get_caps函数的逻辑。完成后函数返回;如果getcaps函数指针为NULL,则gst_pad_get_caps函数从该pad的pad template中列出所有的caps,返回;如果该pad没有pad template,则gst_pad_get_caps函数检查该GstPad的caps成员是否为NULL,如果不为NULL,则返回这个 member;最后,如果前面的都不成立,则gst_pad_get_caps创建一个empty的GstCaps并返回,表示该pad目前没有caps。

get_pad_set_caps 函数用来设置指定pad的caps。该函数首先检查参数中给出的caps是否已经和目前该pad中的caps相同,如果是,则直接返回。如果不相同,则检查setcaps函数指针是否为NULL,如果不为NULL则调用setcaps函数。我们可以通过 gst_pad_set_setcaps_function函数来给setcaps这个函数指针赋值,这样就在gst_pad_set_caps函数中实现了自定义的逻辑。注意,gst_pad_set_caps函数会判断setcaps函数的返回值,如果是FALSE,则会直接报错return FALSE,这样的结果就是gst_pad_set_caps函数执行失败,caps negotiation失败。当setcaps函数执行完毕后,gst_pad_set_caps函数执行gst_caps_replace,将保存在该pad中的caps member替换成参数中指定的caps,然后函数结束。

PUSH MODE:   
              src              sink
              |                 |
              |  accepts?       |
  type A      |---------------->|
              |      yes        |
              |<----------------|
              |                 |
 get buffer   |  alloc_buf      |
 from pool    |---------------->| 
 with type A  |                 | Create buffer of type A.
              |                 |
 check type   |<----------------|
 and use A    |                 |
              |  push           |
 push buffer  |---------------->| Receive type A, reconfigure to
 with new type|                 | process type A.
              |                 |
PUSH MODE下,总是由src pad发起negotiation,为了让src pad和peer sink pad都能接受的caps来,src pad会将自己的caps和peer sink pad的caps做intersect,这时就会调用函数gst_pad_get_caps,参数就是peer sink pad(一般直接使用gst_pad_peer_get_caps函数一步完成)。如果 peer sink pad没有设置getcaps函数指针的话,那就会直接返回peer sink pad template中的所有caps。接下去就是src pad调用gst_pad_set_caps,把自己的caps确定下来,再然后就是申请并分配buffer

PULL MODE
src              sink
              |                 |
              |  accepts?       |
              |<----------------| type B
              |      yes        |
              |---------------->|
              |                 |
 get buffer   |  alloc_buf      |
 from pool    |---------------->| 
 with type A  |                 | Create buffer of new type B.
              |                 |
 check type   |<----------------|
 and          |                 |
 reconfigure  |                 |
              | pull            |
              |<----------------| Pull buffer from the peer src pad 
              |                 |
PULL MODE下,由于是sink element的sink pad来drive pipeline,所以,caps negotiation要在pull thread启动之前就完成。首先,sink pad将自己的caps和peer src pad的caps做intersect(需调用peer src pad上的gst_pad_get_caps),之后调用gst_pad_set_caps将sink pad caps确定下来。调用gst_pad_set_caps,设置peer src pad,如果成功,那么表示src pad和自己一样,都具备了相同的caps,这样negotiation就成功了。最后,可以使用gst_pad_pull_range来获取数据,这个函数会为我们检查buffer中的caps和当前sink pad中的caps是否一致,如果不一致,就会return GST_FLOW_NOT_NEGOTIATED。

gst_pad_set_caps 被调用的时机。当在_chain函数中收到一个buffer之后,一般需要检查该buffer中的caps是否和当前pad中的caps相同,以防止数据在运行过程中改变caps。如果这两个caps不相同,那么,_chain函数应该返回GST_FLOW_NOT_NEGOTIATED,这样,gstreamer core就会用buffer中这个新的caps,去调用gst_pad_set_caps,这样做的目的是gstreamer要知道pad能否接受这个 caps,如果函数返回TRUE,表示接受该caps,而且pad已经更新了自己的caps为目前这个,如果函数返回FALSE,表示caps negotiation failed,pipeline就无法正常运行了。

在 PUSH模式下,_chain函数返回GST_FLOW_NOT_NEGOTIATED,gstreamer core就会自动为我们调用gst_pad_set_caps;但是在PULL模式下,虽然gst_pad_pull_range也会返回 GST_FLOW_NOT_NEGOTIATED,但是gst_pad_set_caps并不会自动被调用,gstramer不支持在pull thread中做set caps的动作。所以,在PULL模式下,我们需要自己处理这种GST_FLOW_NOT_NEGOTIATED的情况。回想pull thread没有启动之前,为什么我们需要设置setcaps函数呢?这是因为我们需要在这个函数中,使用gst_pad_set_caps来给peer src pad设置caps来完成caps negotiation,而这个动作在PUSH模式下,只要peer element的_chain函数返回GST_FLOW_NOT_NEGOTIATED,gstreamer core就会自动为我们调用peer src pad上的gst_pad_set_caps,所以,PUSH模式下,我们不需要去设置setcaps函数指针。

沒有留言:

張貼留言