Gstreamer 内存分配协商机制

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

场景和目的

一般而言,内存分配的协商是在caps协商之后。根据需求匹配到对应的参数,获取到分配器和内存池,然后才能开始数据传输。
在sink_event函数的GST_EVENT_CAPS分支,通过解析到上游的caps信息,来设置自己的caps。紧接着就会发起内存分配的协商。
因此我们在Gstreamer 源码中,很多协商都是在元件的gst_xxx_set_caps函数中进行的。

对于很多基础类,我们会看到两个相关的虚函数:

  • propose_allocation
    在收到GST_QUERY_ALLOCATION问询时,一般时候直接调用该函数来处理,为上游元件提供建议值。
  • decide_allocation
    根据下游的建议参数,来决定最终的参数值。一般会判断当前query是否具有有效值,补齐query中的参数。该函数可能在默认的negotiate函数中调用,也可能在set caps之后调用(通常的element)。
    在这里插入图片描述

发起问询

协商总是由源衬垫src pad来发起,srcpad给出想要的参数,最终由下游节点判断是否能满足要求。
下游的sinkpad可以返回以下三类信息:

  • GstAllocator
  • GstBufferPool
  • GstMeta

请求端——创建问询

首先创建一个问询:GST_QUERY_ALLOCATION,携带需要存放的caps格式 。如果需要使用内存池,可以把need-pool的标志位置一。
和其他问询一样,在实际代码中,并不直接调用GST_QUERY_ALLOCATION ,而是通过封装的接口gst_query_new_allocation来进行的:

  GstQuery *query;
  query = gst_query_new_allocation (outcaps, TRUE);

gst_query_new_allocation 其实现如下:

GstQuery *
gst_query_new_allocation (GstCaps * caps, gboolean need_pool)
{
  GstQuery *query;
  GstStructure *structure;
  
  structure = gst_structure_new_id (GST_QUARK (QUERY_ALLOCATION),
      GST_QUARK (CAPS), GST_TYPE_CAPS, caps,
      GST_QUARK (NEED_POOL), G_TYPE_BOOLEAN, need_pool, NULL);
  query = gst_query_new_custom (GST_QUERY_ALLOCATION, structure);
  return query;
}

请求端——发送问询

之后我们往对等节点发送这个问询:

  if (!gst_pad_peer_query (scope->priv->srcpad, query)) {
    /* not a problem, we use the query defaults */
    GST_DEBUG_OBJECT (scope, "allocation query failed");
  }

请求端——检查问询结果

接下来解析结果,获取分配器、参数、pool信息:

  GstAllocator *allocator;
  GstAllocationParams params;
  GstBufferPool *pool = NULL;
  
  //获取params和allocator
  if (gst_query_get_n_allocation_params (query) > 0) {
    gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
  }
  //获取pool
  if (gst_query_get_n_allocation_pools (query) > 0)
    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);

  //接下来可以按正常流程使用pool和allocator
  config = gst_buffer_pool_get_config (pool);
  //查询meta,并在buffer中添加video meta选项
  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
     gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
  //设置并激活pool
  gst_buffer_pool_config_set_params (config, caps, size, min, max);
  gst_buffer_pool_config_set_allocator (config, allocator, &params);
  gst_buffer_pool_set_config (pool, config);
  /* and activate */
  gst_buffer_pool_set_active (pool, TRUE);

响应问询

和其他问询一样,问询的响应都是在sink_query函数中完成的。一般是调用propose_allocation函数来直接处理。

响应端——解析问询

我们可以通过gst_query_parse_allocation来解析问询结果,拿到caps和pool的需求信息。

    GstCaps *outcaps;
    gboolean need_pool;
    gst_query_parse_allocation (query, &caps, &need_pool);

响应端——配置问询

根据解析到信息,创建对应资源,并添加到query:

//1. 添加allocator和params:
gst_query_add_allocation_param(query, priv->propose_allocator, &priv->propose_allocation_params);
//2. 创建pool
  if (need_pool) {
    pool = gst_video_buffer_pool_new ();
    config = gst_buffer_pool_get_config (pool);
    gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
    if (!gst_buffer_pool_set_config (pool, config))
      goto config_failed;
//添加pool
   gst_query_add_allocation_pool (query, pool, size, 2, 0);
  }
//3. 添加meta,可以添加多个meta */
  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);

之后,src端就可以在自己的decide_allocation函数来解析这些设定值了。

重协商

当配置发生变化的时候,可能会执行再协商一个新的pool,比如视频分辨率发生变化。

上游变化

上游发生变化时,这时候我们不能马上把当前的pool重新配置,因为pipeline中可能还在使用其中的buffer,所以需要创建新的pool。当然也可以等待当前pool耗尽之后,重新配置当前的pool。
重新协商的过程和之前一样,在协商caps之后发起同样的流程。

下游变化

当下游想要修改配置时,需要发送一个GST_EVENT_RECONFIGURE的事件,命令上游重新协商格式和pool。
当pipeline出现元件的增删,或者拓扑结构变化时,会触发RECONFIGURE事件。pipeline的重新配置也会触发caps和pool的重新协商。
GST_EVENT_RECONFIGURE事件标记每一个需要重新配置的pad。然后,下一次缓冲区分配将需要重新协商或重新配置pool。
对于GST_EVENT_RECONFIGURE的caps相关流程可以参考《capabilities negociation 规格协商》。

参考

插件开发教程之内存分配
Gstreamer 设计文档之bufferpool
Gstreamer API之bufferpool

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值