📄 gstbasetransform.c
字号:
gboolean ret; klass = GST_BASE_TRANSFORM_GET_CLASS (trans); GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %" GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s", size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK"); /* if there is a custom transform function, use this */ if (klass->transform_size) { ret = klass->transform_size (trans, direction, caps, size, othercaps, othersize); } else { if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize)) goto no_in_size; GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size, inunitsize); if (inunitsize == 0 || (size % inunitsize != 0)) goto no_multiple; units = size / inunitsize; if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize)) goto no_out_size; *othersize = units * outunitsize; GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize); ret = TRUE; } return ret; /* ERRORS */no_in_size: { GST_DEBUG_OBJECT (trans, "could not get in_size"); g_warning ("could not get in_size"); return FALSE; }no_multiple: { GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size, inunitsize); g_warning ("Size %u is not a multiple of unit size %u", size, inunitsize); return FALSE; }no_out_size: { GST_DEBUG_OBJECT (trans, "could not get out_size"); g_warning ("could not get out_size"); return FALSE; }}static GstCaps *gst_base_transform_getcaps (GstPad * pad){ GstBaseTransform *trans; GstPad *otherpad; GstCaps *caps; trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad)); otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad; /* we can do what the peer can */ caps = gst_pad_peer_get_caps (otherpad); if (caps) { GstCaps *temp; const GstCaps *templ; GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps); /* filtered against our padtemplate */ templ = gst_pad_get_pad_template_caps (otherpad); GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ); temp = gst_caps_intersect (caps, templ); GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp); gst_caps_unref (caps); /* then see what we can transform this to */ caps = gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (otherpad), temp); GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps); gst_caps_unref (temp); if (caps == NULL) goto done; /* and filter against the template again */ templ = gst_pad_get_pad_template_caps (pad); GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ); temp = gst_caps_intersect (caps, templ); GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp); gst_caps_unref (caps); /* this is what we can do */ caps = temp; } else { /* no peer, our padtemplate is enough then */ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); }done: GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps); gst_object_unref (trans); return caps;}/* function triggered when the in and out caps are negotiated and need * to be configured in the subclass. */static gbooleangst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out){ gboolean ret = TRUE; GstBaseTransformClass *klass; klass = GST_BASE_TRANSFORM_GET_CLASS (trans); /* clear the cache */ gst_caps_replace (&trans->cache_caps1, NULL); gst_caps_replace (&trans->cache_caps2, NULL); /* If we've a transform_ip method and same input/output caps, set in_place * by default. If for some reason the sub-class prefers using a transform * function, it can clear the in place flag in the set_caps */ gst_base_transform_set_in_place (trans, klass->transform_ip && trans->have_same_caps); /* Set the passthrough if the class wants passthrough_on_same_caps * and we have the same caps on each pad */ if (klass->passthrough_on_same_caps) gst_base_transform_set_passthrough (trans, trans->have_same_caps); /* now configure the element with the caps */ if (klass->set_caps) { GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps"); ret = klass->set_caps (trans, in, out); } trans->negotiated = ret; return ret;}/* called when new caps arrive on the sink or source pad */static gbooleangst_base_transform_setcaps (GstPad * pad, GstCaps * caps){ GstBaseTransform *trans; GstBaseTransformClass *klass; GstPad *otherpad, *otherpeer; GstCaps *othercaps = NULL; gboolean ret = TRUE; gboolean peer_checked = FALSE; trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad)); klass = GST_BASE_TRANSFORM_GET_CLASS (trans); otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad; otherpeer = gst_pad_get_peer (otherpad); /* if we get called recursively, we bail out now to avoid an * infinite loop. */ if (GST_PAD_IS_IN_SETCAPS (otherpad)) goto done; /* caps must be fixed here */ if (!gst_caps_is_fixed (caps)) goto unfixed_caps; /* see how we can transform the input caps. */ othercaps = gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), caps); /* The caps we can actually output is the intersection of the transformed * caps with the pad template for the pad */ if (othercaps) { GstCaps *intersect; const GstCaps *templ_caps; templ_caps = gst_pad_get_pad_template_caps (otherpad); intersect = gst_caps_intersect (othercaps, templ_caps); gst_caps_unref (othercaps); othercaps = intersect; } /* check if transform is empty */ if (!othercaps || gst_caps_is_empty (othercaps)) goto no_transform; /* if the othercaps are not fixed, we need to fixate them, first attempt * is by attempting passthrough if the othercaps are a superset of caps. */ if (!gst_caps_is_fixed (othercaps)) { GstCaps *temp; GST_DEBUG_OBJECT (trans, "transform returned non fixed %" GST_PTR_FORMAT, othercaps); /* see if the target caps are a superset of the source caps, in this * case we can try to perform passthrough */ temp = gst_caps_intersect (othercaps, caps); GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp); if (temp) { if (!gst_caps_is_empty (temp) && otherpeer) { GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps); /* try passthrough. we know it's fixed, because caps is fixed */ if (gst_pad_accept_caps (otherpeer, caps)) { GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps); /* peer accepted unmodified caps, we free the original non-fixed * caps and work with the passthrough caps */ gst_caps_unref (othercaps); othercaps = gst_caps_ref (caps); /* mark that we checked othercaps with the peer, this * makes sure we don't call accept_caps again with these same * caps */ peer_checked = TRUE; } else { GST_DEBUG_OBJECT (trans, "peer did not accept %" GST_PTR_FORMAT, caps); } } gst_caps_unref (temp); } } /* second attempt at fixation is done by intersecting with * the peer caps */ if (!gst_caps_is_fixed (othercaps) && otherpeer) { /* intersect against what the peer can do */ GstCaps *peercaps; GstCaps *intersect; GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps); peercaps = gst_pad_get_caps (otherpeer); intersect = gst_caps_intersect (peercaps, othercaps); gst_caps_unref (peercaps); gst_caps_unref (othercaps); othercaps = intersect; peer_checked = FALSE; GST_DEBUG_OBJECT (trans, "filtering against peer yields %" GST_PTR_FORMAT, othercaps); } if (gst_caps_is_empty (othercaps)) goto no_transform_possible; /* third attempt at fixation, call the fixate vmethod and * ultimately call the pad fixate function. */ if (!gst_caps_is_fixed (othercaps)) { GstCaps *temp; GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s", othercaps, GST_DEBUG_PAD_NAME (otherpad)); /* since we have no other way to fixate left, we might as well just take * the first of the caps list and fixate that */ /* FIXME: when fixating using the vmethod, it might make sense to fixate * each of the caps; but Wim doesn't see a use case for that yet */ temp = gst_caps_copy_nth (othercaps, 0); gst_caps_unref (othercaps); othercaps = temp; peer_checked = FALSE; if (klass->fixate_caps) { GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT " using caps %" GST_PTR_FORMAT " on pad %s:%s using fixate_caps vmethod", othercaps, caps, GST_DEBUG_PAD_NAME (otherpad)); klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps); } /* if still not fixed, no other option but to let the default pad fixate * function do its job */ if (!gst_caps_is_fixed (othercaps)) { GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s using gst_pad_fixate_caps", othercaps, GST_DEBUG_PAD_NAME (otherpad)); gst_pad_fixate_caps (otherpad, othercaps); } GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps); } /* caps should be fixed now, if not we have to fail. */ if (!gst_caps_is_fixed (othercaps)) goto could_not_fixate; /* and peer should accept, don't check again if we already checked the * othercaps against the peer. */ if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps)) goto peer_no_accept; GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT ", and got final caps %" GST_PTR_FORMAT, caps, othercaps); trans->have_same_caps = gst_caps_is_equal (caps, othercaps); GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps); /* see if we have to configure the element now */ if (!trans->delay_configure) { GstCaps *incaps, *outcaps; /* make sure in and out caps are correct */ if (pad == trans->sinkpad) { incaps = caps; outcaps = othercaps; } else { incaps = othercaps; outcaps = caps; } /* call configure now */ if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps))) goto failed_configure; } else { /* set pending configure, the configure will happen later with the * caps we set on the pads above. */ trans->pending_configure = TRUE; } /* we know this will work, we implement the setcaps */ gst_pad_set_caps (otherpad, othercaps); if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) { ret &= gst_pad_set_caps (otherpeer, othercaps); if (!ret) { GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed", othercaps); } }done: if (otherpeer) gst_object_unref (otherpeer); if (othercaps) gst_caps_unref (othercaps); trans->negotiated = ret; gst_object_unref (trans); return ret; /* ERRORS */unfixed_caps: { GST_DEBUG_OBJECT (trans, "caps are not fixed %" GST_PTR_FORMAT, caps); ret = FALSE; goto done; }no_transform: { GST_DEBUG_OBJECT (trans, "transform returned useless %" GST_PTR_FORMAT, othercaps); ret = FALSE; goto done; }no_transform_possible: { GST_DEBUG_OBJECT (trans, "transform could not transform %" GST_PTR_FORMAT " in anything we support", caps); ret = FALSE; goto done; }could_not_fixate: { GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps); ret = FALSE; goto done; }peer_no_accept: { GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT " to accept %" GST_PTR_FORMAT, otherpad, othercaps); ret = FALSE; goto done; }failed_configure: { GST_DEBUG_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT " to accept %" GST_PTR_FORMAT, otherpad, othercaps); ret = FALSE; goto done; }}/* Allocate a buffer using gst_pad_alloc_buffer * * This function does not do renegotiation on the source pad * * The output buffer is always writable. outbuf can be equal to * inbuf, the caller should be prepared for this and perform * appropriate refcounting. */static GstFlowReturngst_base_transform_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * in_buf, gint out_size, GstCaps * out_caps, GstBuffer ** out_buf){ GstBaseTransformClass *bclass; GstFlowReturn ret = GST_FLOW_OK; gboolean copy_inbuf = FALSE; bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); /* we cannot reconfigure the element yet as we are still processing * the old buffer. We will therefore delay the reconfiguration of the * element until we have processed this last buffer. */ trans->delay_configure = TRUE; /* out_caps is the caps of the src pad gathered through the GST_PAD_CAPS macro. If a set_caps occurs during this function this caps will become invalid. We want to keep them during preparation of the output buffer. */ if (out_caps) gst_caps_ref (out_caps); /* see if the subclass wants to alloc a buffer */ if (bclass->prepare_output_buffer) { ret = bclass->prepare_output_buffer (trans, in_buf, out_size, out_caps, out_buf); if (ret != GST_FLOW_OK) goto done; /* decrease refcount again if vmethod returned refcounted in_buf. This * is because we need to make sure that the buffer is writable for the * in_place transform. The docs of the vmethod say that you should return * a reffed inbuf, which is exactly what we don't want :), oh well.. */ if (in_buf == *out_buf) gst_buffer_unref (in_buf); } /* See if we want to prepare the buffer for in place output */ if (*out_buf == NULL && GST_BUFFER_SIZE (in_buf) == out_size && bclass->transform_ip) { if (gst_buffer_is_writable (in_buf)) { if (trans->have_same_caps) { /* Input buffer is already writable and caps are the same, return input as * output buffer. We don't take an additional ref since that would make the * output buffer not writable anymore. Caller should be prepared to deal * with proper refcounting of input/output buffers. */ *out_buf = in_buf; GST_LOG_OBJECT (trans, "reuse input buffer"); } else { /* Writable buffer, but need to change caps => subbuffer */ *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf)); gst_caps_replace (&GST_BUFFER_CAPS (*out_buf), out_caps); GST_LOG_OBJECT (trans, "created sub-buffer of input buffer"); } /* we are done now */ goto done; } else { /* Make a writable buffer below and copy the data */ copy_inbuf = TRUE; GST_LOG_OBJECT (trans, "need to copy input buffer to new output buffer"); } } if (*out_buf == NULL) { /* Sub-class didn't already provide a buffer for us. Make one */ ret = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET (in_buf), out_size, out_caps, out_buf); if (ret != GST_FLOW_OK || *out_buf == NULL) goto done; /* allocated buffer could be of different caps than what we requested */ if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) { /* FIXME, it is possible we can reconfigure the transform with new caps at this * point but for now we just create a buffer ourselves */ gst_buffer_unref (*out_buf); *out_buf = gst_buffer_new_and_alloc (out_size); gst_buffer_set_caps (*out_buf, out_caps); } } /* If the output buffer metadata is modifiable, copy timestamps and * buffer flags */ if (*out_buf != in_buf && gst_buffer_is_metadata_writable (*out_buf)) { if (copy_inbuf && gst_buffer_is_writable (*out_buf)) memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size); gst_buffer_copy_metadata (*out_buf, in_buf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -