📄 gstbasetransform.c
字号:
}done: if (out_caps) gst_caps_unref (out_caps); trans->delay_configure = FALSE; return ret;}/* Given @caps calcultate the size of one unit. * * For video caps, this is the size of one frame (and thus one buffer). * For audio caps, this is the size of one sample. * * These values are cached since they do not change and the calculation * potentially involves parsing caps and other expensive stuff. * * We have two cache locations to store the size, one for the source caps * and one for the sink caps. * * this function returns FALSE if no size could be calculated. */static gbooleangst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps, guint * size){ gboolean res = FALSE; GstBaseTransformClass *bclass; /* see if we have the result cached */ if (trans->cache_caps1 == caps) { *size = trans->cache_caps1_size; GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size); return TRUE; } if (trans->cache_caps2 == caps) { *size = trans->cache_caps2_size; GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size); return TRUE; } bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); if (bclass->get_unit_size) { res = bclass->get_unit_size (trans, caps, size); GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE"); if (res) { /* and cache the values */ if (trans->cache_caps1 == NULL) { gst_caps_replace (&trans->cache_caps1, caps); trans->cache_caps1_size = *size; GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size); } else if (trans->cache_caps2 == NULL) { gst_caps_replace (&trans->cache_caps2, caps); trans->cache_caps2_size = *size; GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size); } else { GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size"); } } } else { GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size"); } return res;}/* your upstream peer wants to send you a buffer * that buffer has the given offset, size and caps * you're requested to allocate a buffer */static GstFlowReturngst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf){ GstBaseTransform *trans; GstFlowReturn res; guint new_size; gboolean issinkcaps = TRUE; trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad)); /* we cannot run this when we are transforming data and as such doing * another negotiation in the transform method. */ g_mutex_lock (trans->transform_lock); *buf = NULL; GST_DEBUG_OBJECT (trans, "allocating a buffer of size %d ...", size); if (offset == GST_BUFFER_OFFSET_NONE) GST_DEBUG_OBJECT (trans, "... and offset NONE"); else GST_DEBUG_OBJECT (trans, "... and offset %" G_GUINT64_FORMAT, offset); /* if have_same_caps was previously set to TRUE we need to double check if it * hasn't changed */ if (trans->have_same_caps) { GstCaps *sinkcaps; GST_OBJECT_LOCK (trans->sinkpad); sinkcaps = GST_PAD_CAPS (trans->sinkpad); issinkcaps = sinkcaps && (gst_caps_is_equal (sinkcaps, caps)); GST_OBJECT_UNLOCK (trans->sinkpad); } /* before any buffers are pushed, have_same_caps is TRUE; allocating can trigger * a renegotiation and change that to FALSE */ /* bilboed: This seems wrong, from all debug logs, have_same_caps is * initialized to FALSE */ /* checking against trans->have_same_caps is not enough !! It should also * check to see if the requested caps are equal to the sink caps */ if (trans->have_same_caps && issinkcaps) { /* request a buffer with the same caps */ GST_DEBUG_OBJECT (trans, "requesting buffer with same caps, size %d", size); res = gst_pad_alloc_buffer_and_set_caps (trans->srcpad, offset, size, caps, buf); } else { /* if we are configured, request a buffer with the src caps */ GstCaps *srccaps; GstCaps *sinkcaps; gboolean configured; /* take lock, peek if the caps are ok */ GST_OBJECT_LOCK (trans->sinkpad); sinkcaps = GST_PAD_CAPS (trans->sinkpad); configured = (sinkcaps == NULL || gst_caps_is_equal (sinkcaps, caps)); GST_OBJECT_UNLOCK (trans->sinkpad); if (!configured) goto not_configured; /* take lock on srcpad to grab the caps, caps can change when pushing a * buffer. */ GST_OBJECT_LOCK (trans->srcpad); if ((srccaps = GST_PAD_CAPS (trans->srcpad))) gst_caps_ref (srccaps); GST_OBJECT_UNLOCK (trans->srcpad); if (!srccaps) goto not_configured; GST_DEBUG_OBJECT (trans, "calling transform_size"); if (!gst_base_transform_transform_size (trans, GST_PAD_DIRECTION (pad), caps, size, srccaps, &new_size)) { gst_caps_unref (srccaps); goto unknown_size; } res = gst_pad_alloc_buffer_and_set_caps (trans->srcpad, offset, new_size, srccaps, buf); gst_caps_unref (srccaps); } if (res == GST_FLOW_OK && !trans->have_same_caps) { /* note that we might have had same caps before, but calling the alloc_buffer caused setcaps to switch us out of in_place -- in any case the alloc_buffer served to transmit caps information but we can't use the buffer. fall through and allocate a buffer corresponding to our sink caps, if any */ GstCaps *sinkcaps; GstCaps *srccaps; GST_OBJECT_LOCK (trans->sinkpad); if ((sinkcaps = GST_PAD_CAPS (trans->sinkpad))) gst_caps_ref (sinkcaps); GST_OBJECT_UNLOCK (trans->sinkpad); if (!sinkcaps) goto not_configured; GST_OBJECT_LOCK (trans->srcpad); if ((srccaps = GST_PAD_CAPS (trans->srcpad))) gst_caps_ref (srccaps); GST_OBJECT_UNLOCK (trans->srcpad); if (!srccaps) { gst_caps_unref (sinkcaps); goto not_configured; } if (!gst_base_transform_transform_size (trans, GST_PAD_DIRECTION (trans->srcpad), srccaps, GST_BUFFER_SIZE (*buf), sinkcaps, &new_size)) { gst_caps_unref (srccaps); gst_caps_unref (sinkcaps); goto unknown_size; } /* don't need the caps anymore now */ gst_caps_unref (srccaps); gst_buffer_unref (*buf); *buf = gst_buffer_new_and_alloc (new_size); GST_BUFFER_OFFSET (*buf) = offset; /* set caps, gives away the ref */ GST_BUFFER_CAPS (*buf) = sinkcaps; res = GST_FLOW_OK; }done: g_mutex_unlock (trans->transform_lock); gst_object_unref (trans); return res;not_configured: { /* let the default allocator handle it... */ GST_DEBUG_OBJECT (trans, "not configured"); gst_buffer_replace (buf, NULL); if (trans->passthrough) { /* ...by calling alloc_buffer without setting caps on the src pad, which * will force negotiation in the chain function. */ res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf); } else { /* ...by letting the default handler create a buffer */ res = GST_FLOW_OK; } goto done; }unknown_size: { /* let the default allocator handle it... */ GST_DEBUG_OBJECT (trans, "unknown size"); gst_buffer_replace (buf, NULL); if (trans->passthrough) { /* ...by calling alloc_buffer without setting caps on the src pad, which * will force negotiation in the chain function. */ res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf); } else { /* ...by letting the default handler create a buffer */ res = GST_FLOW_OK; } goto done; }}static gbooleangst_base_transform_sink_event (GstPad * pad, GstEvent * event){ GstBaseTransform *trans; GstBaseTransformClass *bclass; gboolean ret = TRUE; gboolean forward = TRUE; trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad)); bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); if (bclass->event) forward = bclass->event (trans, event); /* FIXME, do this in the default event handler so the subclass can do * something different. */ if (forward) ret = gst_pad_push_event (trans->srcpad, event); gst_object_unref (trans); return ret;}static gbooleangst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event){ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: break; case GST_EVENT_FLUSH_STOP: GST_OBJECT_LOCK (trans); /* reset QoS parameters */ trans->priv->proportion = 1.0; trans->priv->earliest_time = -1; trans->priv->discont = FALSE; GST_OBJECT_UNLOCK (trans); /* we need new segment info after the flush. */ trans->have_newsegment = FALSE; gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED); break; case GST_EVENT_EOS: break; case GST_EVENT_TAG: break; case GST_EVENT_NEWSEGMENT: { GstFormat format; gdouble rate, arate; gint64 start, stop, time; gboolean update; gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, &start, &stop, &time); trans->have_newsegment = TRUE; gst_segment_set_newsegment_full (&trans->segment, update, rate, arate, format, start, stop, time); if (format == GST_FORMAT_TIME) { GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, GST_TIME_ARGS (trans->segment.start), GST_TIME_ARGS (trans->segment.stop), GST_TIME_ARGS (trans->segment.time), GST_TIME_ARGS (trans->segment.accum)); } else { GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, trans->segment.start, trans->segment.stop, trans->segment.time, trans->segment.accum); } break; } default: break; } return TRUE;}static gbooleangst_base_transform_src_event (GstPad * pad, GstEvent * event){ GstBaseTransform *trans; GstBaseTransformClass *bclass; gboolean ret = TRUE; trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad)); bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); if (bclass->src_event) ret = bclass->src_event (trans, event); gst_object_unref (trans); return ret;}static gbooleangst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event){ gboolean ret; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: break; case GST_EVENT_NAVIGATION: break; case GST_EVENT_QOS: { gdouble proportion; GstClockTimeDiff diff; GstClockTime timestamp; gst_event_parse_qos (event, &proportion, &diff, ×tamp); gst_base_transform_update_qos (trans, proportion, diff, timestamp); break; } default: break; } ret = gst_pad_push_event (trans->sinkpad, event); return ret;}static GstFlowReturngst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer ** outbuf){ GstBaseTransformClass *bclass; GstFlowReturn ret = GST_FLOW_OK; guint out_size; gboolean want_in_place; GstClockTime qostime; bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); if (GST_BUFFER_OFFSET_IS_VALID (inbuf)) GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset %" G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf), GST_BUFFER_OFFSET (inbuf)); else GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset NONE", inbuf, GST_BUFFER_SIZE (inbuf)); /* Don't allow buffer handling before negotiation, except in passthrough mode * or if the class doesn't implement a set_caps function (in which case it doesn't * care about caps) */ if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL)) goto not_negotiated; /* Set discont flag so we can mark the outgoing buffer */ if (GST_BUFFER_IS_DISCONT (inbuf)) { GST_LOG_OBJECT (trans, "got DISCONT buffer %p", inbuf); trans->priv->discont = TRUE; } /* can only do QoS if the segment is in TIME */ if (trans->segment.format != GST_FORMAT_TIME) goto no_qos; qostime = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (inbuf)); if (qostime != -1) { gboolean need_skip; GstClockTime earliest_time; GST_OBJECT_LOCK (trans); earliest_time = trans->priv->earliest_time; /* check for QoS, don't perform conversion for buffers * that are known to be late. */ need_skip = trans->priv->qos_enabled && earliest_time != -1 && qostime != -1 && qostime <= earliest_time; GST_OBJECT_UNLOCK (trans); if (need_skip) { GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %" GST_TIME_FORMAT " <= %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time)); /* mark discont for next buffer */ trans->priv->discont = TRUE; goto skip; } }no_qos: if (trans->passthrough) { /* In passthrough mode, give transform_ip a look at the * buffer, without making it writable, or just push the * data through */ GST_LOG_OBJECT (trans, "element is in passthrough mode"); if (bclass->transform_ip) ret = bclass->transform_ip (trans, inbuf); *outbuf = inbuf; goto done; } want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place; *outbuf = NULL; if (want_in_place) { /* If want_in_place is TRUE, we may need to prepare a new output buffer * Sub-classes can implement a prepare_output_buffer function as they * wish. */ GST_LOG_OBJECT (trans, "doing inplace transform"); ret = gst_base_transform_prepare_output_buffer (trans, inbuf, GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), outbuf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto no_buffer; ret = bclass->transform_ip (trans, *outbuf); } else { GST_LOG_OBJECT (trans, "doing non-inplace transform"); /* not transforming inplace, figure out the output size */ if (trans->always_in_place) { out_size = GST_BUFFER_SIZE (inbuf); } else { if (!gst_base_transform_transform_size (trans, GST_PAD_DIRECTION (trans->sinkpad), GST_PAD_CAPS (trans->sinkpad), GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), &out_size)) { /* we have an error */ goto no_size; } } /* no in place transform, get buffer, this might renegotiate. */ ret = gst_base_transform_prepare_output_buffer (trans, inbuf, out_size, GST_PAD_CAPS (trans->srcpad), outbuf); if (ret != GST_FLOW_OK) goto no_buffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -