gs--源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/evsqiezi/article/details/82949034

个人理解,仅供参考。

分析gst_buffer_make_metadata_writable,gst_base_transform_buffer_alloc,gst_base_transform_getcaps,gst_base_transform_transform_caps,gst_caps_can_intersect,gst_pad_configure_sink,gst_pad_push_data,gst_pad_push,make_template_caps

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;
}

gst_base_transform_buffer_alloc

gst_pad_set_bufferalloc_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));

gst_pad_push—》GST_PAD_CHAINFUNC (peer) (peer, buffer);(也就是下个的chain函数)-》gst_base_transform_prepare_output_buffer-〉bclass->prepare_output_buffer(如果存在)-》
子类的分配函数-〉gst_pad_alloc_buffer_and_set_caps-》gst_pad_alloc_buffer_full(最厚一个参数secaps为false,gst_pad_configure_src只检查不setcaps,也就是对先获取分配buf的caps,再检查pad能不能接受)-〉gst_pad_buffer_alloc_unchecked (peer。。。)-》gst_base_transform_buffer_alloc(bufferallocfunc (pad, offset, size, caps, buf,bufferallocfunc为peer的分配函数,如果分配函数为空,执行gst_buffer_try_new_and_alloc做真正的malloc)-》gst_pad_alloc_buffer-〉gst_pad_alloc_buffer_full-》。。。。。。一直递归下去。

gst_base_transform_getcaps

gst_pad_get_caps_unlocked会调此函数,为pad为src为例。

static GstCaps *
gst_base_transform_getcaps (GstPad * pad)
{
  GstBaseTransform *trans;
  GstPad *otherpad;
  const GstCaps *templ;
  GstCaps *peercaps, *caps, *temp;
  gboolean samecaps;
  int cache_index;

    
  trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
    //得到同一element的pad。
  otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
  cache_index = (pad == trans->srcpad) ? 0 : 1;

  /* we can do what the peer can */
  //得到对端pad的caps。
  peercaps = gst_pad_peer_get_caps_reffed (otherpad);
  GST_OBJECT_LOCK (trans);
  samecaps = (peercaps && trans->priv->cached_peer_caps[cache_index]
      && gst_caps_is_strictly_equal (peercaps,
          trans->priv->cached_peer_caps[cache_index]));
  if (!samecaps) {
    if (trans->priv->cached_peer_caps[cache_index]) {
      gst_caps_unref (trans->priv->cached_peer_caps[cache_index]);
      trans->priv->cached_peer_caps[cache_index] = NULL;
    }
    if (trans->priv->cached_transformed_caps[cache_index]) {
      gst_caps_unref (trans->priv->cached_transformed_caps[cache_index]);
      trans->priv->cached_transformed_caps[cache_index] = NULL;
    }
  } else {
    //跟旧的一样,就返回。
    GST_DEBUG_OBJECT (trans,
        "Returning cached transformed caps (index = %d)", cache_index);
    caps = gst_caps_ref (trans->priv->cached_transformed_caps[cache_index]);
    goto done;
  }
  GST_OBJECT_UNLOCK (trans);

  if (peercaps) {
    GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, peercaps);

    /* filtered against our padtemplate on the other side */
    //获取pad的模版caps。
    templ = gst_pad_get_pad_template_caps (otherpad);
    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
    //把对端的caps跟src的caps进行交织。
    temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
  } else {
    temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
    GST_DEBUG_OBJECT (pad, "no peer, using our template caps %" GST_PTR_FORMAT,
        temp);
  }

  /* then see what we can transform this to */
  //根据输入,得到转换caps。
  caps = gst_base_transform_transform_caps (trans,
      GST_PAD_DIRECTION (otherpad), temp);
  GST_WARNING_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
  gst_caps_unref (temp);
  if (caps == NULL)
    goto done_update_cache;

  /* and filter against the template of this pad */
  //得到此pad的模版caps。
  templ = gst_pad_get_pad_template_caps (pad);
  GST_WARNING_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
  /* We keep the caps sorted like the returned caps */
  //将输出跟模版caps进行交织。
  temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
  GST_WARNING_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
  gst_caps_unref (caps);
  caps = temp;

  if (peercaps) {
    /* Now try if we can put the untransformed downstream caps first */
    将输出跟模版caps进行交织,优先选择不转换。
    temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
    if (!gst_caps_is_empty (temp)) {
      gst_caps_merge (temp, caps);
      caps = temp;
    } else {
      gst_caps_unref (temp);
    }
  }

done_update_cache:
  GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);

  GST_OBJECT_LOCK (trans);
  if (peercaps) {
    trans->priv->cached_peer_caps[cache_index] = gst_caps_ref (peercaps);
  }
  if (caps) {
    trans->priv->cached_transformed_caps[cache_index] = gst_caps_ref (caps);
  }

done:
  GST_OBJECT_UNLOCK (trans);

  if (peercaps)
    gst_caps_unref (peercaps);

  gst_object_unref (trans);

  return caps;
}

gst_base_transform_transform_caps

/* given @caps on the src or sink pad (given by @direction)
 * calculate the possible caps on the other pad.
 *
 * Returns new caps, unref after usage.
 */
static GstCaps *
gst_base_transform_transform_caps (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * caps)
{
  GstCaps *ret;
  GstBaseTransformClass *klass;
    char* st = NULL;
  if (caps == NULL)
    return NULL;

  klass = GST_BASE_TRANSFORM_GET_CLASS (trans); //获取基类

  /* if there is a custom transform function, use this */
  if (klass->transform_caps) { //是否重写了虚函数
    GstCaps *temp;
    gint i;

    /* start with empty caps */
    ret = gst_caps_new_empty ();  //创建个空的caps,新的值可以append。
    GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);

    if (gst_caps_is_any (caps)) {
      /* for any caps we still have to call the transform function */
      GST_DEBUG_OBJECT (trans, "from: ANY");
      temp = klass->transform_caps (trans, direction, caps);
      GST_DEBUG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, temp);

      temp = gst_caps_make_writable (temp);
      gst_caps_append (ret, temp);
    } else {
      gint n = gst_caps_get_size (caps);  //获取个数
      /* we send caps with just one structure to the transform
       * function as this is easier for the element */
      for (i = 0; i < n; i++) {
        GstCaps *nth;

        nth = gst_caps_copy_nth (caps, i);
        GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
        temp = klass->transform_caps (trans, direction, nth);   //是个虚函数,比如会调用gst_video_rate_transform_caps,这是videorate中的一个实现。
        gst_caps_unref (nth);
        GST_LOG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);

        temp = gst_caps_make_writable (temp);

        /* here we need to only append those structures, that are not yet
         * in there, we use the merge function for this */
        gst_caps_merge (ret, temp);

        GST_LOG_OBJECT (trans, "  merged[%d]: %" GST_PTR_FORMAT, i, ret);
      }
      GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
      /* FIXME: we can't do much simplification here because we don't really want to
       * change the caps order
       gst_caps_do_simplify (ret);
       GST_DEBUG_OBJECT (trans, "simplified: (%d)", gst_caps_get_size (ret));
       */
    }
  } else {
    GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
    /* no transform function, use the identity transform */
    ret = gst_caps_ref (caps);
  }

  GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
      ret);

  return ret;
}

gst_caps_can_intersect

例子:

(char *) s1 = 0x00007ff9c984d000 "
\video/x-raw-yuv, format=(fourcc)UYVY, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)[ 0/1, 29/1 ];\nvideo/x-raw-yuv, format=(fourcc)UYVY, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)[ 0/1, 29/1 ];\nvideo/x-raw-yuv, format=(fourcc)UYVY, width=(int)480, height=(int)360, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)[ 0/1, 29/1 ];\nvideo/x-raw-yuv, format=(fourcc)UYVY, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)[ 0/1, 29/1 ];\nvideo/x-raw-yuv, format=(fourcc)UYVY, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)[ 0/1, 29/1 ];\n"

(char *) s2 = 0x00006000006ec200 "
video/x-raw-yuv, width=(int)1280, height=(int)720, framerate=(fraction)29/1;\n"

相交得到:
video/x-raw-yuv, format=(fourcc)UYVY, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)29/1;\n"

gboolean gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
检测两个caps有没有相同的struct(会调用gst_structure_can_intersect,gst_structure_foreach进行检测)。
gboolean
gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
{
    。。。。。。
  len1 = caps1->structs->len;
  len2 = caps2->structs->len;
  //检测的方法是:先遍历caps1的struct,看caps2里有没有相同的struct;再遍历caps2的strum,看caps里有没有相同的。
  for (i = 0; i < len1 + len2 - 1; i++) {
    /* superset index goes from 0 to sgst_caps_structure_intersectuperset->structs->len-1 */
    j = MIN (i, len1 - 1);
    /* subset index stays 0 until i reaches superset->structs->len, then it
     * counts up from 1 to subset->structs->len - 1 */
    k = (i > j) ? (i - j) : 0;  /* MAX (0, i - j) */

    /* now run the diagonal line, end condition is the left or bottom
     * border */
    while (k < len2) {
      struct1 = gst_caps_get_structure_unchecked (caps1, j);
      struct2 = gst_caps_get_structure_unchecked (caps2, k);

      if (gst_structure_can_intersect (struct1, struct2)) {
        return TRUE;
      }
        /* move down left */
        k++;
      if (G_UNLIKELY (j == 0))
        break;                  /* so we don't roll back to G_MAXUINT */
      j--;
    }
  }
  return FALSE;
}

gst_pad_configure_sink

//用到达数据的caps给sink设置属性。

static gboolean
gst_pad_configure_sink (GstPad * pad, GstCaps * caps)
{
  gboolean res;

  /* See if pad accepts the caps */

  //看pad的定义的caps能否接收传入的caps。
  if (!gst_caps_can_intersect (caps, gst_pad_get_pad_template_caps (pad)))
    goto not_accepted;

  /* set caps on pad if call succeeds */
  res = gst_pad_set_caps (pad, caps);  //会调虚函数setcaps,例如gst_base_transform_setcaps-》gst_base_transform_configure_caps(trans, incaps, outcaps)(设置进出的caps)。
  /* no need to unref the caps here, set_caps takes a ref and
   * our ref goes away when we leave this function. */

  return res;

not_accepted:
  {
    GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
        "caps %" GST_PTR_FORMAT " not accepted", caps);
    return FALSE;
  }
}

gst_pad_push_data

static GstFlowReturn
gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data,
    GstPadPushCache * cache){

caps = gst_pad_data_get_caps (is_buffer, data);

  caps_changed = caps && caps != GST_PAD_CAPS (pad);

//先检测buf的属性跟pad属性是否一致,得到caps_changed
......
* Before pushing the buffer to the peer pad, ensure that caps
   * are set on this pad */
  //推之前,要确保pad上设置了caps。
  caps = gst_pad_data_get_caps (is_buffer, data);
  caps_changed = caps && caps != GST_PAD_CAPS (pad);

  /* we got a new datatype from the pad, it had better handle it */
  if (G_UNLIKELY (caps_changed)) {
    /* unlock before setting */
    GST_OBJECT_UNLOCK (pad);
    GST_DEBUG_OBJECT (pad,
        "caps changed from %" GST_PTR_FORMAT " to %p %" GST_PTR_FORMAT,
        GST_PAD_CAPS (pad), caps, caps);
    if (G_UNLIKELY (!gst_pad_set_caps (pad, caps)))
      goto not_negotiated;
    GST_OBJECT_LOCK (pad);
  }

......
}

gst_pad_push

GstFlowReturn gst_pad_push (GstPad * pad, GstBuffer * buffer)
gst_pad_push-》gst_pad_push_data->gst_pad_chain_data_unchecked (peer, is_buffer, data, cache); -》gst_pad_chain_data_unchecked(先gst_pad_configure_sink,也就是为pad设置buf的caps)-〉gst_base_transform_chain(包含buf处理,比如:gst_base_transform_handle_buffer)-》最后再push出去,如:gst_pad_push (trans->srcpad, outbuf);

make_template_caps

available_caps
(char *) s1 = 0x00007fab1d8bb000 "
video/x-raw-yuv, format=(fourcc)UYVY, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)[ 0/1, 29/1 ];\n
video/x-raw-yuv, format=(fourcc)UYVY, width=(int)352, height=(int)288, pixel-aspect-ratio=(fraction)1/1, AVCaptureVideoOrientation=(int)1, OriginalMediaSubType=(int)4, framerate=(fraction)[ 0/1, 29/1 ];\n"
调用:make_template_caps (available_caps,
      "width", G_TYPE_INT, width,
      "height", G_TYPE_INT, height,
      "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
      NULL);
输出:(char *) s2 = 0x00006000006e4180 "video/x-raw-yuv, width=(int)1280, height=(int)720, framerate=(fraction)29/1;\n",也就是只取了第一个的NAME,如video/x-raw-yuv。

猜你喜欢

转载自blog.csdn.net/evsqiezi/article/details/82949034
gs
今日推荐