首先说明,这是自己的一些笔记,比较凌乱,还没有好好整理,不要留言骂人啊,我会慢慢整理出来,我本人是做gsrremer插件工作,所以明白gstreamer真的很难,不是看一些博客就能了解的,看了了解到的大部分也是错的,所以你真的想要学习gstreamer的话,一定要把gstreamer代码结构先看明白,那些是基础代码,那些是插件代码,当然还要多多少少了解一些meson的构建方式。
达到这个程度后,最好在linux下编译一个最简单的gstreamer库,然后准备一个非常简单的案例,打开gstreamer的log,当你跑通一个案例的时候,跟着日志看代码的流程,不要怕麻烦,一点一点来,先从最简单的插件加载方式看,然后看add,然后link,然后看state的改变,中途如果对某些代码调用步确定,可以用gdb跟踪下代码,这一套流程下来,你就会对gstreamer的整个框架有个非常宏观的了解了。

所以与其翻各种错误百出的帖子还不如自己静下心来好好看看代码,看看官方文档

gstreamer关键步骤有下面三个:

 gst_bin_add_many(GST_BIN(data.pipeline), data.source, data.h264parse, data.omx264dec, data.convert, data.sink, nullptr);gst_element_link_many(data.source, data.h264parse, data.omx264dec, data.convert, data.sink, nullptr)gst_element_set_state(data.pipeline, GST_STATE_PLAYING);
  • add最简单,主要将element添加到pipeline中,但是这里还有一个操作,就是将pipeline的child bus设置为所有element中的bus,各个element的parent设置为pipeline.

  • link阶段核心就是将上下element的sinkpad和srcpad通过peerpad连接在一起,但是连接之前会查询双方pad的caps,并且进行交集计算,如果有交集才进行link.查询的时候发送的是caps query

  • gst_element_set_state(data.pipeline, GST_STATE_PLAYING)这是pipeline状态改变的重点函数,这里,状态首先从NULl改变到READY,然后再把状态从READY改变为PAUSED,其中到PAUSED的过程中会触发激活函数,比如src element的loop线程开始启动,解码器开始打开等动作。注意的是这个过程中的element是link状态下element倒着来的,比如先是sink,接着covert,然后omx264dec,然后。。。,

  • 当pipeline的t状态改变为AREADY的时候,会从source发送一个STREAM_START的event,这个event一直传递到最后的sink element,每个element接收到STREAM_START后会做一些事情。
    下图就是event从上床底到下的一个流程图,不一定每个event都从上传递到下,个别event可能从中途就返回了。
    当sink element收到一个stream-start event后会发送给一个msg到bus总线。

  • 协商就发生在stream start之后,发起者是source element就是第一个element,所以当你还没有了解到整个gstreamer运转机制的时候,先写一个简单的pipeline,然后从第一个element开始看协商函数。

下面函数是整个pipeline的动力起源:


/* Called with STREAM_LOCK */
static void
gst_base_src_loop (GstPad * pad)
{GstBaseSrc *src;GstBuffer *buf = NULL;GstFlowReturn ret;gint64 position;gboolean eos;guint blocksize;GList *pending_events = NULL, *tmp;eos = FALSE;src = GST_BASE_SRC (GST_OBJECT_PARENT (pad));/* Just leave immediately if we're flushing */GST_LIVE_LOCK (src);if (G_UNLIKELY (src->priv->flushing || GST_PAD_IS_FLUSHING (pad)))goto flushing;GST_LIVE_UNLOCK (src);/* Just return if EOS is pushed again, as the app might be unaware that an* EOS have been sent already */if (GST_PAD_IS_EOS (pad)) {GST_DEBUG_OBJECT (src, "Pad is marked as EOS, pause the task");gst_pad_pause_task (pad);goto done;}//首先发送一个stream start的eventgst_base_src_send_stream_start (src);/* The stream-start event could've caused something to flush us */GST_LIVE_LOCK (src);if (G_UNLIKELY (src->priv->flushing || GST_PAD_IS_FLUSHING (pad)))goto flushing;GST_LIVE_UNLOCK (src);/* check if we need to renegotiate */if (gst_pad_check_reconfigure (pad)) {//这里进行第一次协商if (!gst_base_src_negotiate_unlocked (src)) {gst_pad_mark_reconfigure (pad);if (GST_PAD_IS_FLUSHING (pad)) {GST_LIVE_LOCK (src);goto flushing;} else {goto negotiate_failed;}}}GST_LIVE_LOCK (src);if (G_UNLIKELY (src->priv->flushing || GST_PAD_IS_FLUSHING (pad)))goto flushing;blocksize = src->blocksize;/* if we operate in bytes, we can calculate an offset */if (src->segment.format == GST_FORMAT_BYTES) {position = src->segment.position;/* for negative rates, start with subtracting the blocksize */if (src->segment.rate < 0.0) {/* we cannot go below segment.start */if (position > src->segment.start + blocksize)position -= blocksize;else {/* last block, remainder up to segment.start */blocksize = position - src->segment.start;position = src->segment.start;}}} elseposition = -1;GST_LOG_OBJECT (src, "next_ts %" GST_TIME_FORMAT " size %u",GST_TIME_ARGS (position), blocksize);/* clean up just in case we got interrupted or so last time round */if (src->priv->pending_bufferlist != NULL) {gst_buffer_list_unref (src->priv->pending_bufferlist);src->priv->pending_bufferlist = NULL;}ret = gst_base_src_get_range (src, position, blocksize, &buf);if (G_UNLIKELY (ret != GST_FLOW_OK)) {GST_INFO_OBJECT (src, "pausing after gst_base_src_get_range() = %s",gst_flow_get_name (ret));GST_LIVE_UNLOCK (src);goto pause;}}

下面先看:gst_base_src_negotiate_unlocked()

static gboolean
gst_base_src_negotiate_unlocked (GstBaseSrc * basesrc)
{GstBaseSrcClass *bclass;gboolean result;bclass = GST_BASE_SRC_GET_CLASS (basesrc);GST_DEBUG_OBJECT (basesrc, "starting negotiation");if (G_LIKELY (bclass->negotiate))result = bclass->negotiate (basesrc);elseresult = TRUE;if (G_LIKELY (result)) {GstCaps *caps;
//首先查询capscaps = gst_pad_get_current_caps (basesrc->srcpad);
//开始分配bufresult = gst_base_src_prepare_allocation (basesrc, caps);if (caps)gst_caps_unref (caps);}return result;
}

首先看第一个:

caps = gst_pad_get_current_caps (basesrc->srcpad);

下面是日志:

[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbasesrc.c:gst_base_src_negotiate_unlocked:3439  starting negotiation
[Level:5] ../subprojects/gstreamer/gst/gstutils.c:gst_pad_query_caps:3102  get pad caps with filter (NULL)
[Level:5] ../subprojects/gstreamer/gst/gstquery.c:gst_query_new_custom:679  creating new query 0x5630fc4bf6d0 caps
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4170  doing query 0x5630fc4bf6d0 (caps)
[Level:5] ../subprojects/gst-plugins-base/gst-libs/gst/app/gstappsrc.c:gst_app_src_internal_get_caps:860  caps: (NULL)
[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbasesrc.c:gst_base_src_default_query:1381  query caps returns 0
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4193  sent query 0x5630fc4bf6d0 (caps), result 0
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4239  query failed
[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbasesrc.c:gst_base_src_default_negotiate:3369  caps of src: ANY
[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbasesrc.c:gst_base_src_default_negotiate:3415  no negotiation needed
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_get_current_caps:2734  get current pad caps (NULL)

从日志可以看到,source app返回的是ANY。
接着看如何allocation:

result = gst_base_src_prepare_allocation (basesrc, caps);//这个函数总体就发送了一个caps的event,然后根据decoder返回的allocation来创建了一个bufpool,然后启动部分pool;
static gboolean
gst_base_src_prepare_allocation (GstBaseSrc * basesrc, GstCaps * caps)
{GstBaseSrcClass *bclass;gboolean result = TRUE;GstQuery *query;GstBufferPool *pool = NULL;GstAllocator *allocator = NULL;GstAllocationParams params;bclass = GST_BASE_SRC_GET_CLASS (basesrc);/* make query and let peer pad answer, we don't really care if it worked or* not, if it failed, the allocation query would contain defaults and the* subclass would then set better values if needed *///发送了一个allocation event ,下一个element是h264parse,所以接下来看h264中关于allocation的query处理,query = gst_query_new_allocation (caps, TRUE);if (!gst_pad_peer_query (basesrc->srcpad, query)) {/* not a problem, just debug a little */GST_DEBUG_OBJECT (basesrc, "peer ALLOCATION query failed");}g_assert (bclass->decide_allocation != NULL);result = bclass->decide_allocation (basesrc, query);GST_DEBUG_OBJECT (basesrc, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, result,query);if (!result)goto no_decide_allocation;/* we got configuration from our peer or the decide_allocation method,* parse them */if (gst_query_get_n_allocation_params (query) > 0) {gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);} else {allocator = NULL;gst_allocation_params_init (&params);}if (gst_query_get_n_allocation_pools (query) > 0)gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
//这里把pool激活result = gst_base_src_set_allocation (basesrc, pool, allocator, &params);if (allocator)gst_object_unref (allocator);if (pool)gst_object_unref (pool);gst_query_unref (query);return result;/* Errors */
no_decide_allocation:{GST_WARNING_OBJECT (basesrc, "Subclass failed to decide allocation");gst_query_unref (query);return result;}
}

下面看如何发送allocation的event:

Level:5] ../subprojects/gstreamer/gst/gstquery.c:gst_query_new_custom:679  creating new query 0x5630fc4bf770 allocation
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_peer_query:4297  peer query 0x5630fc4bf770 (allocation)
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4170  doing query 0x5630fc4bf770 (allocation)
[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbaseparse.c:gst_base_parse_sink_query:1637  allocation query
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_default:3511  forwarding 0x5630fc4bf770 (allocation) query
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_iterate_internal_links_default:2965  Making iterator//h264parse不处理,直接向下转发
[Level:6] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_forward:3074  calling forward function on pad h264-parse:src
[Level:6] ../subprojects/gstreamer/gst/gstpad.c:query_forward_func:3447  query peer 0x5630fc4bf770 (allocation) of h264-parse:src
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_peer_query:4297  peer query 0x5630fc4bf770 (allocation)
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4170  doing query 0x5630fc4bf770 (allocation)
//videodecoder处理这个query,然后直接返回
[Level:5] ../subprojects/gst-plugins-base/gst-libs/gst/video/gstvideodecoder.c:gst_video_decoder_sink_query:2178  received query 35846, allocation
[Level:6] ../subprojects/gst-plugins-base/gst-libs/gst/video/gstvideodecoder.c:gst_video_decoder_sink_query_default:2087  handling query: allocation query: 0x5630fc4bf770, GstQueryAllocation, caps=(GstCaps)"NULL", need-pool=(boolean)true;
//这里返回了allocation
[Level:5] ../subprojects/gst-omx/omx/gstomxvideodec.c:gst_omx_video_dec_propose_allocation:3517  request at least 3 buffers of size 32768[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4193  sent query 0x5630fc4bf770 (allocation), result 1
[Level:2] ../subprojects/gstreamer/gst/gststructure.c:priv_gst_structure_append_to_gstring:2091  No value transform to serialize field 'pool' of type 'GArray'
[Level:6] ../subprojects/gstreamer/libs/gst/base/gstbaseparse.c:gst_base_parse_sink_query:1644  allocation query result: 1 allocation query: 0x5630fc4bf770, GstQueryAllocation, caps=(GstCaps)"NULL", need-pool=(boolean)true, pool=(GArray)NULL;
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4193  sent query 0x5630fc4bf770 (allocation), result 1

接着执行:

  g_assert (bclass->decide_allocation != NULL);result = bclass->decide_allocation (basesrc, query);

下面是decide_allocation日志:


[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbasesrc.c:gst_base_src_decide_allocation_default:3235  no pool, making new pool
[Level:5] ../subprojects/gstreamer/gst/gstpoll.c:gst_poll_new:681  0x7f3478003000: new controllable : 1
[Level:5] ../subprojects/gstreamer/gst/gstpoll.c:gst_poll_add_fd_unlocked:848  0x7f3478003000: fd (fd:9, idx:0)
[Level:5] ../subprojects/gstreamer/gst/gstpoll.c:gst_poll_fd_ctl_read_unlocked:1014  0x7f3478003000: fd (fd:9, idx:0), active : 1
[Level:6] ../subprojects/gstreamer/gst/gstpoll.c:raise_wakeup:290  0x7f3478003000: raise
[Level:5] ../subprojects/gstreamer/gst/gstbufferpool.c:gst_buffer_pool_init:179  created
[Level:5] ../subprojects/gstreamer/gst/gstbufferpool.c:gst_buffer_pool_new:231  created new buffer pool
[Level:2] ../subprojects/gstreamer/gst/gststructure.c:priv_gst_structure_append_to_gstring:2091  No value transform to serialize field 'params' of type 'GstAllocationParams'[Level:5] ../subprojects/gstreamer/gst/gstbufferpool.c:default_set_config:622  config GstBufferPoolConfig, caps=(GstCaps)"NULL", size=(uint)32768, min-buffers=(uint)3, max-buffers=(uint)0, allocator=(GstAllocator)"NULL", params=(GstAllocationParams)NULL;
[Level:2] ../subprojects/gstreamer/gst/gststructure.c:priv_gst_structure_append_to_gstring:2091  No value transform to serialize field 'pool' of type 'GArray'
[Level:2] ../subprojects/gstreamer/gst/gststructure.c:priv_gst_structure_append_to_gstring:2091  No value transform to serialize field 'allocator' of type 'GArray'
[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbasesrc.c:gst_base_src_prepare_allocation:3315  ALLOCATION (1) params: allocation query: 0x5630fc4bf770, GstQueryAllocation, caps=(GstCaps)"NULL", need-pool=(boolean)true, pool=(GArray)NULL, allocator=(GArray)NULL;
[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbasesrc.c:gst_base_src_set_allocation:3143  activate pool
[Level:6] ../subprojects/gstreamer/gst/gstbufferpool.c:gst_buffer_pool_set_active:514  active 1

gst_base_src_decide_allocation_default()

static gboolean
gst_base_src_decide_allocation_default (GstBaseSrc * basesrc, GstQuery * query)
{GstCaps *outcaps;GstBufferPool *pool;guint size, min, max;GstAllocator *allocator;GstAllocationParams params;GstStructure *config;gboolean update_allocator;
//首先解析querygst_query_parse_allocation (query, &outcaps, NULL);/* we got configuration from our peer or the decide_allocation method,* parse them */* //解析allocation paramsif (gst_query_get_n_allocation_params (query) > 0) {/* try the allocator */gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);update_allocator = TRUE;} else {allocator = NULL;gst_allocation_params_init (&params);update_allocator = FALSE;}//解析allocation poolif (gst_query_get_n_allocation_pools (query) > 0) {gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);if (pool == NULL) {/* no pool, we can make our own */GST_DEBUG_OBJECT (basesrc, "no pool, making new pool");//创建poolpool = gst_buffer_pool_new ();}} else {pool = NULL;size = min = max = 0;}/* now configure */if (pool) {config = gst_buffer_pool_get_config (pool);gst_buffer_pool_config_set_params (config, outcaps, size, min, max);gst_buffer_pool_config_set_allocator (config, allocator, &params);/* buffer pool may have to do some changes */if (!gst_buffer_pool_set_config (pool, config)) {config = gst_buffer_pool_get_config (pool);/* If change are not acceptable, fallback to generic pool */if (!gst_buffer_pool_config_validate_params (config, outcaps, size, min,max)) {GST_DEBUG_OBJECT (basesrc, "unsupported pool, making new pool");gst_object_unref (pool);pool = gst_buffer_pool_new ();gst_buffer_pool_config_set_params (config, outcaps, size, min, max);gst_buffer_pool_config_set_allocator (config, allocator, &params);}if (!gst_buffer_pool_set_config (pool, config))goto config_failed;}}if (update_allocator)gst_query_set_nth_allocation_param (query, 0, allocator, &params);elsegst_query_add_allocation_param (query, allocator, &params);if (allocator)gst_object_unref (allocator);if (pool) {gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);gst_object_unref (pool);}return TRUE;config_failed:GST_ELEMENT_ERROR (basesrc, RESOURCE, SETTINGS,("Failed to configure the buffer pool"),("Configuration is most likely invalid, please report this issue."));gst_object_unref (pool);return FALSE;
}

接下来看协商,最难的协商也是发生在这里,下面是调用栈,可以看到发生在gst_app_src_create()这里

今天继续,我们从gst_app_src_create()开始吧,


gst_app_src_create ()gst_app_src_do_negotiate (bsrc)gst_base_src_set_caps (basesrc, caps);current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (src))gst_pad_push_event (src->srcpad, gst_event_new_caps (caps))

所以整个pipeline的协商起始位置在这里,发送了一个caps event,下面看日志,可以看出创建的event发送到了下方的peerpad h264-parse:sink,对于gst_pad_push_event()这个函数,这里不展开,请单独看,非常简单的,同时也能解决你的一个疑问,sticky event.

[Level:5] ../subprojects/gstreamer/gst/gstpad.c:ginf:2734  get current pad caps (NULL)
[Level:4] ../subprojects/gstreamer/gst/gstevent.c:gst_event_new_caps:892  creating caps event video/x-h264, alignment=(string)au, stream-format=(string)byte-stream, width=(int)176, height=(int)144
[Level:5] ../subprojects/gstreamer/gst/gstevent.c:gst_event_new_custom:310  creating new event 0x5630fc4c3560 caps 12814
[Level:6] ../subprojects/gstreamer/gst/gstpad.c:store_sticky_event:5354  stored sticky event caps
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:store_sticky_event:5360  notify caps
[Level:6] ../subprojects/gstreamer/gst/gstobject.c:gst_object_dispatch_properties_changed:472  deep notification from src (caps)
[Level:6] ../subprojects/gstreamer/gst/gstobject.c:gst_object_dispatch_properties_changed:472  deep notification from src (caps)
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:check_sticky:4102  pushing all sticky events
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:push_sticky:4031  event stream-start was already received[Level:6] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_push_event_unchecked:5538  sending event 0x5630fc4c3560 (caps) to peerpad <h264-parse:sink>
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_send_event_unchecked:5827  have event type caps event: 0x5630fc4c3560, time 99:99:99.999999999, seq-num 31, GstEventCaps, caps=(GstCaps)"video/x-h264\,\ alignment\=\(string\)au\,\ stream-format\=\(string\)byte-stream\,\ width\=\(int\)176\,\ height\=\(int\)144";

大致调用流程是:

gst_pad_push_event_unchecked()gst_pad_send_event_unchecked (peerpad, event, type)pre_eventfunc_check (pad, event);eventfunc (pad, parent, event)

上面pre_eventfunc_check (pad, event)做了很多事情:

static GstFlowReturn
pre_eventfunc_check (GstPad * pad, GstEvent * event)
{GstCaps *caps;switch (GST_EVENT_TYPE (event)) {case GST_EVENT_CAPS:{/* backwards compatibility mode for caps */gst_event_parse_caps (event, &caps);//这里查询,也就是发送caps事件的时候先发送caps query//如果有accept caps,才可以发送caps eventif (!gst_pad_query_accept_caps (pad, caps))goto not_accepted;break;}default:break;}return GST_FLOW_OK;
}

下面日志可以看出先构建了一个accept-capsquery,然后查询

[Level:5] ../subprojects/gstreamer/gst/gstutils.c:gst_pad_query_accept_caps:3185  accept caps of video/x-h264, alignment=(string)au, stream-format=(string)byte-stream, width=(int)176, height=(int)144
[Level:5] ../subprojects/gstreamer/gst/gstquery.c:gst_query_new_custom:679  creating new query 0x7f3478003050 accept-caps
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4170  doing query 0x7f3478003050 (accept-caps)

source element发送了查询后,接下来肯定是h264parse接受到了啊,下面是日志,

//h264parese接收到这个查询
[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbaseparse.c:gst_base_parse_sink_query:1637  accept-caps query[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_accept_caps_default:3197  query accept-caps accept-caps query: 0x7f3478003050, GstQueryAcceptCaps, caps=(GstCaps)"video/x-h264\,\ alignment\=\(string\)au\,\ stream-format\=\(string\)byte-stream\,\ width\=\(int\)176\,\ height\=\(int\)144", result=(boolean)false;
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_accept_caps_default:3222  allowed caps intersect video/x-h264, caps video/x-h264, alignment=(string)au, stream-format=(string)byte-stream, width=(int)176, height=(int)144
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_default:3511  not forwarding 0x7f3478003050 (accept-caps) query[Level:6] ../subprojects/gstreamer/libs/gst/base/gstbaseparse.c:gst_base_parse_sink_query:1644  accept-caps query result: 1 accept-caps query: 0x7f3478003050, GstQueryAcceptCaps, caps=(GstCaps)"video/x-h264\,\ alignment\=\(string\)au\,\ stream-format\=\(string\)byte-stream\,\ width\=\(int\)176\,\ height\=\(int\)144", result=(boolean)true;
[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4193  sent query 0x7f3478003050 (accept-caps), result 1
[Level:5] ../subprojects/gstreamer/gst/gstutils.c:gst_pad_query_accept_caps:3191  query returned 1

根据日志提示,我们来看gst_base_parse_sink_query()函数:

gst_base_parse_sink_query()gst_base_parse_sink_query_default()gst_pad_query_default (pad, GST_OBJECT_CAST (parse), query)gst_pad_query_accept_caps_default (pad, query)st_query_parse_accept_caps (query, &caps)gst_caps_can_intersect (caps, allowed)gst_query_set_accept_caps_result (query, result)
gst_base_parse_sink_query()//最终返回到这里

接下来到了eventfunc (pad, parent, event)函数:


static GstFlowReturn
gst_pad_send_event_unchecked (GstPad * pad, GstEvent * event,GstPadProbeType type)
{//也就是pre函数成功了才开发送事件函数,根据上面我们日志和代码的跟踪,发现本次pre就是查看了
//source srcpad和h264parse sinkpad是否有交集,如果有交集才发送event caps。ret = pre_eventfunc_check (pad, event);if (G_UNLIKELY (ret != GST_FLOW_OK))goto precheck_failed;if (sticky)gst_event_ref (event);if (eventfullfunc) {ret = eventfullfunc (pad, parent, event);} else if (eventfunc (pad, parent, event)) {ret = GST_FLOW_OK;} else {/* something went wrong */switch (event_type) {case GST_EVENT_CAPS:ret = GST_FLOW_NOT_NEGOTIATED;break;default:ret = GST_FLOW_ERROR;break;}}

这里开始eventfunc()函数:

static gboolean
gst_base_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{GstBaseParse *parse = GST_BASE_PARSE (parent);GstBaseParseClass *bclass = GST_BASE_PARSE_GET_CLASS (parse);gboolean ret;ret = bclass->sink_event (parse, event);return ret;
}//起始内部执行的是这个函数
static gboolean
gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
{GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);gboolean ret = FALSE;gboolean forward_immediate = FALSE;GST_DEBUG_OBJECT (parse, "handling event %d, %s", GST_EVENT_TYPE (event),GST_EVENT_TYPE_NAME (event));switch (GST_EVENT_TYPE (event)) {case GST_EVENT_CAPS:{GstCaps *caps;gst_event_parse_caps (event, &caps);GST_DEBUG_OBJECT (parse, "caps: %" GST_PTR_FORMAT, caps);if (klass->set_sink_caps)ret = klass->set_sink_caps (parse, caps);elseret = TRUE;/* will send our own caps downstream */gst_event_unref (event);event = NULL;break;}}

接着是set_sink_caps (parse, caps),实际执行的是gst_h264_parse_set_caps,这个函数太长了,大致做了一些解析query的工作,然后

static gboolean
gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
{GstH264Parse *h264parse;GstStructure *str;const GValue *codec_data_value;GstBuffer *codec_data = NULL;gsize size;guint format, align, off;GstH264NalUnit nalu;GstH264ParserResult parseres;GstCaps *old_caps;h264parse = GST_H264_PARSE (parse);/* reset */h264parse->push_codec = FALSE;old_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));if (old_caps) {if (!gst_caps_is_equal (old_caps, caps))gst_h264_parse_reset_stream_info (h264parse);gst_caps_unref (old_caps);}str = gst_caps_get_structure (caps, 0);/* accept upstream info if provided */gst_structure_get_int (str, "width", &h264parse->width);gst_structure_get_int (str, "height", &h264parse->height);gst_structure_get_fraction (str, "framerate", &h264parse->fps_num,&h264parse->fps_den);gst_structure_get_fraction (str, "pixel-aspect-ratio",&h264parse->upstream_par_n, &h264parse->upstream_par_d);/* get upstream format and align from caps */gst_h264_parse_format_from_caps (caps, &format, &align);codec_data_value = gst_structure_get_value (str, "codec_data");/* fix up caps without stream-format for max. backwards compatibility */if (format == GST_H264_PARSE_FORMAT_NONE) {/* codec_data implies avc */if (codec_data_value != NULL) {GST_ERROR ("video/x-h264 caps with codec_data but no stream-format=avc");format = GST_H264_PARSE_FORMAT_AVC;} else {/* otherwise assume bytestream input */GST_ERROR ("video/x-h264 caps without codec_data or stream-format");format = GST_H264_PARSE_FORMAT_BYTE;}}.../* bytestream caps sanity checks */if (format == GST_H264_PARSE_FORMAT_BYTE) {/* should have SPS/PSS in-band (and/or oob in streamheader field) */if (codec_data_value != NULL)goto bytestream_caps_with_codec_data;}if (codec_data_value != NULL) {...
}else if (format == GST_H264_PARSE_FORMAT_BYTE) {GST_DEBUG_OBJECT (h264parse, "have bytestream h264");/* nothing to pre-process */h264parse->packetized = FALSE;/* we have 4 sync bytes */h264parse->nal_length_size = 4;} {GstCaps *in_caps;/* prefer input type determined above */in_caps = gst_caps_new_simple ("video/x-h264","parsed", G_TYPE_BOOLEAN, TRUE,"stream-format", G_TYPE_STRING,gst_h264_parse_get_string (h264parse, TRUE, format),"alignment", G_TYPE_STRING,gst_h264_parse_get_string (h264parse, FALSE, align), NULL);/* negotiate with downstream, sets ->format and ->align *///继续向下协商,h264parse里面有前面解析到的width,hight,framerate等gst_h264_parse_negotiate (h264parse, format, in_caps);gst_caps_unref (in_caps);}
}

gst_h264_parse_negotiate (h264parse, format, in_caps);做了些什么呢:

tatic void
gst_h264_parse_negotiate (GstH264Parse * h264parse, gint in_format,GstCaps * in_caps)
{GstCaps *caps;guint format = h264parse->format;guint align = h264parse->align;g_return_if_fail ((in_caps == NULL) || gst_caps_is_fixed (in_caps));//这里是个重点GST_BASE_PARSE_SRC_PAD (h264parse)获取到了src padcaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (h264parse));GST_DEBUG_OBJECT (h264parse, "allowed caps: %" GST_PTR_FORMAT, caps);/* concentrate on leading structure, since decodebin parser* capsfilter always includes parser template caps */if (caps) {caps = gst_caps_truncate (caps);GST_DEBUG_OBJECT (h264parse, "negotiating with caps: %" GST_PTR_FORMAT,caps);}h264parse->can_passthrough = FALSE;if (in_caps && caps) {if (gst_caps_can_intersect (in_caps, caps)) {GST_DEBUG_OBJECT (h264parse, "downstream accepts upstream caps");gst_h264_parse_format_from_caps (in_caps, &format, &align);gst_caps_unref (caps);caps = NULL;h264parse->can_passthrough = TRUE;}}/* FIXME We could fail the negotiation immediately if caps are empty */if (caps && !gst_caps_is_empty (caps)) {/* fixate to avoid ambiguity with lists when parsing */caps = gst_caps_fixate (caps);gst_h264_parse_format_from_caps (caps, &format, &align);}/* default */if (!format)format = GST_H264_PARSE_FORMAT_BYTE;if (!align)align = GST_H264_PARSE_ALIGN_AU;GST_DEBUG_OBJECT (h264parse, "selected format %s, alignment %s",gst_h264_parse_get_string (h264parse, TRUE, format),gst_h264_parse_get_string (h264parse, FALSE, align));h264parse->format = format;h264parse->align = align;h264parse->transform = in_format != h264parse->format ||align == GST_H264_PARSE_ALIGN_AU;if (caps)gst_caps_unref (caps);
}

接着继续看gst_pad_get_allowed_caps():

GstCaps *gst_pad_get_allowed_caps (GstPad * pad)
{GstCaps *mycaps;GstCaps *caps = NULL;GstQuery *query;g_return_val_if_fail (GST_IS_PAD (pad), NULL);GST_OBJECT_LOCK (pad);if (G_UNLIKELY (GST_PAD_PEER (pad) == NULL))goto no_peer;GST_OBJECT_UNLOCK (pad);GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "getting allowed caps");
//查询src pad的caps
//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_get_allowed_caps:2819  getting allowed caps
//[Level:5] ../subprojects/gstreamer/gst/gstutils.c:gst_pad_query_caps:3102  get pad caps with filter (NULL)
//[Level:5] ../subprojects/gstreamer/gst/gstquery.c:gst_query_new_custom:679  creating new query 0x7f34780030f0 caps
//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4170  doing query 0x7f34780030f0 (caps)
//[Level:5] ../subprojects/gstreamer/libs/gst/base/gstbaseparse.c:gst_base_parse_src_query:1660  caps query: caps query: 0x7f34780030f0, GstQueryCaps, filter=(GstCaps)"NULL", caps=(GstCaps)"NULL";
//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_caps_default:3256  query caps caps query: 0x7f34780030f0, GstQueryCaps, filter=(GstCaps)"NULL", caps=(GstCaps)"NULL";//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_caps_default:3274  fixed pad caps: trying pad caps
//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_caps_default:3280  trying pad template caps
//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_caps_default:3309  using caps 0x5630fc4a2a30 video/x-h264, parsed=(boolean)true, stream-format=(string){ avc, avc3, byte-stream }, alignment=(string){ au, nal }
//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query_default:3511  not forwarding 0x7f34780030f0 (caps) query
//[Level:6] ../subprojects/gstreamer/libs/gst/base/gstbaseparse.c:gst_base_parse_src_query:1668  caps query result: 1 caps query: 0x7f34780030f0, GstQueryCaps, filter=(GstCaps)"NULL", caps=(GstCaps)"video/x-h264\,\ parsed\=\(boolean\)true\,\ stream-format\=\(string\)\{\ avc\,\ avc3\,\ byte-stream\ \}\,\ alignment\=\(string\)\{\ au\,\ nal\ \}";
//[Level:5] ../subprojects/gstreamer/gst/gstpad.c:gst_pad_query:4193  sent query 0x7f34780030f0 (caps), result 1
//[Level:5] ../subprojects/gstreamer/gst/gstutils.c:gst_pad_query_caps:3109  query returned video/x-h264, parsed=(boolean)true, stream-format=(string){ avc, avc3, byte-stream }, alignment=(string){ au, nal }mycaps = gst_pad_query_caps (pad, NULL);/* Query peer caps *///继续向下查询query = gst_query_new_caps (mycaps);if (!gst_pad_peer_query (pad, query)) {GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "Caps query failed");goto end;}gst_query_parse_caps_result (query, &caps);if (caps == NULL) {g_warn_if_fail (caps != NULL);goto end;}gst_caps_ref (caps);GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "allowed caps %" GST_PTR_FORMAT,caps);end:gst_query_unref (query);gst_caps_unref (mycaps);return caps;no_peer:{GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "no peer");GST_OBJECT_UNLOCK (pad);return NULL;}
}

gst_pad_peer_query()这个函数,会从h264parse开始查询,逐步进入:

gst_video_decoder_sink_getcaps()st_video_decoder_proxy_getcaps (decoder, NULL, filter)__gst_video_element_proxy_getcaps()gst_pad_peer_query_caps (srcpad, NULL);//这里查询covert的sink了

(未完待续)

h264parse srcpad查询,应该是decoder的sinkpad 收到这个pad

所以接下来我们直接看h264-parse:sink pad的event函数就可以了,

  parse_class->sink_event = GST_DEBUG_FUNCPTR (gst_h264_parse_event);parse_class->src_event = GST_DEBUG_FUNCPTR (gst_h264_parse_src_event);

总结:gstbasesrc从gst_app_src_do_negotiate (bsrc),发送caps event结束后,再次进入到gst_app_src_create()函数,
接着到:gst_app_src_emit_need_data()告诉app用户需要数据,用户开始发送数据。

gstreamer协商negoation相关推荐

  1. Gstreamer 内存分配协商机制

    在两个衬垫的caps协商完成之后,元件之间需要确认如何分配buffer.本文梳理Gstreamer 内存协商机制,比如当某元件不能自己分配内存时,如何使用其他元件的分配器. 场景和目的 一般而言,内存 ...

  2. 什么是GStreamer?

    什么是GStreamer? GStreamer是用于创建流媒体应用程序的框架.基本设计来自俄勒冈大学研究生院的视频管道以及DirectShow的一些想法. GStreamer的开发框架使编写任何类型的 ...

  3. GStreamer跨平台多媒体框架

    GStreamer跨平台多媒体框架 Gstreamer基本概念 GStreamer是用于构造媒体处理组件图的库.它支持的应用程序范围从简单的Ogg / Vorbis回放,音频/视频流到复杂的音频(混合 ...

  4. GStreamer 的调试工具

    目标 有时一些事情没有按照预期的运行,但从总线(bus)获得的错误消息也没有提供足够的信息.幸运地是,GStreamer 带有大量的调试信息,它们通常可以对哪里出了问题给出一些提示.这里将介绍: 如何 ...

  5. [转]详细的GStreamer开发教程

    详细的GStreamer开发教程 文章目录 详细的GStreamer开发教程 1. 什么是GStreamer? 2. GStreamer架构 2.1 Media Applications 2.2 Co ...

  6. GStreamer开发介绍

    https://blog.csdn.net/liu_xiao_cheng/article/details/43017491#section-bin-ghost-img 发Chat 转载 2015年01 ...

  7. GStreamer教程-基础教程2:GStreamer概念

    目标 上一篇教程展示了如何自动构建管道.现在,我们将通过实例化每个元素并将它们链接在一起来手动构建管道.在这个过程中,我们会学到: 什么是GStreamer元素以及如何创建它. 如何将元素相互连接. ...

  8. 二、什么是GStreamer

    GStreamer是一个用于创建流媒体应用程序的框架.基本的设计来自俄勒冈研究生院的视频管道,还有一些来自DirectShow的想法. GStreamer的开发框架使编写任何类型的流媒体应用程序成为可 ...

  9. Gstreamer说明

    http://general.blog.51cto.com/927298/294928 http://general.blog.51cto.com/927298/294931 ============ ...

  10. gstreamer插件开发指南(一)

    翻译自:https://gstreamer.freedesktop.org/documentation/plugin-development/index.html 1 简介 GStreamer是一个非 ...

最新文章

  1. SpringBoot实现Redis分布式锁
  2. XStream – XStreamely使用Java中的XML数据的简便方法
  3. java类加载过程_java类的加载过程
  4. python爬虫框架Scrapy采集数据,并制作词云图分析!
  5. Collections带有的排序方法 传入的元素类型 需是子类或者这个类的实例
  6. JQuery Ajax 在asp.net中使用总结
  7. .class与.java_Java中Class类的作用与深入理解
  8. 数据库学习--MySQL锁
  9. paip.chrome使用ACTIVX 的总结
  10. C语言经典游戏开发,零基础也能打造微信飞机大战
  11. MemReduct内存自动清理工具
  12. hbase时间同步造成region severs的问题
  13. 计算机木材染色 配色技术的应用技术,木材怎么染色?木材染色剂电脑配色方法...
  14. linux设置法语键盘布局,法语键盘布局图;
  15. java线程游戏之随机小球游戏V1
  16. mysql操作基础知识
  17. 按关键词搜索商品 淘宝API
  18. linux awl***程序说明
  19. 设置切换输入法按键ctrl+shift
  20. python编程心得体会800字_Python学习心得体会

热门文章

  1. c语言初步经典题4----求圆柱体的表面积
  2. 算法题 高斯消元解线性方程组(Python)
  3. 史上最详细教你制作“U盘启动盘”重装Windows10系统
  4. 使用Diskgenius将U盘分区,分为启动盘和文件存储两大功能详解
  5. 如果让markdown的图片变清晰/改变大小
  6. mysql rownum写法_mysql类似oracle rownum写法
  7. 在method方法被调用之后,仅打印出a=100,b=200,请写出method方法的代码
  8. 计算机主板大小性能区别,电脑主板是大板好还是小板好 主板中大板和小板的区别介绍...
  9. 网易云升级服务(云函数)
  10. 特征选择:嵌入法---《菜菜机器学习笔记》