个人理解,仅供参考。
分析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。