mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-10 17:35:59 +00:00
gst/base/gstbasetransform.*: Make passthrough work using the bufferpools.
Original commit message from CVS: * gst/base/gstbasetransform.c: (gst_base_transform_init), (gst_base_transform_transform_caps), (gst_base_transform_getcaps), (gst_base_transform_configure_caps), (gst_base_transform_setcaps), (gst_base_transform_get_size), (gst_base_transform_buffer_alloc), (gst_base_transform_handle_buffer), (gst_base_transform_getrange), (gst_base_transform_chain), (gst_base_transform_change_state), (gst_base_transform_set_passthrough), (gst_base_transform_is_passthrough): * gst/base/gstbasetransform.h: Make passthrough work using the bufferpools. Changed API a bit, subclasses have to write into a buffer provided by the base class. More debug info in nego functions. * gst/elements/gstidentity.c: (gst_identity_init), (gst_identity_transform): Port to new base class.
This commit is contained in:
parent
a8d8310819
commit
7f4581d977
7 changed files with 658 additions and 128 deletions
20
ChangeLog
20
ChangeLog
|
@ -1,3 +1,23 @@
|
|||
2005-07-15 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/base/gstbasetransform.c: (gst_base_transform_init),
|
||||
(gst_base_transform_transform_caps), (gst_base_transform_getcaps),
|
||||
(gst_base_transform_configure_caps), (gst_base_transform_setcaps),
|
||||
(gst_base_transform_get_size), (gst_base_transform_buffer_alloc),
|
||||
(gst_base_transform_handle_buffer), (gst_base_transform_getrange),
|
||||
(gst_base_transform_chain), (gst_base_transform_change_state),
|
||||
(gst_base_transform_set_passthrough),
|
||||
(gst_base_transform_is_passthrough):
|
||||
* gst/base/gstbasetransform.h:
|
||||
Make passthrough work using the bufferpools.
|
||||
Changed API a bit, subclasses have to write into a buffer
|
||||
provided by the base class.
|
||||
More debug info in nego functions.
|
||||
|
||||
* gst/elements/gstidentity.c: (gst_identity_init),
|
||||
(gst_identity_transform):
|
||||
Port to new base class.
|
||||
|
||||
2005-07-15 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/gstmessage.c: (gst_message_new_state_changed):
|
||||
|
|
|
@ -88,6 +88,8 @@ static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
|
|||
gboolean active);
|
||||
static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
|
||||
gboolean active);
|
||||
static guint gst_base_transform_get_size (GstBaseTransform * trans);
|
||||
|
||||
static GstElementStateReturn gst_base_transform_change_state (GstElement *
|
||||
element);
|
||||
|
||||
|
@ -96,10 +98,10 @@ static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
|
|||
guint length, GstBuffer ** buffer);
|
||||
static GstFlowReturn gst_base_transform_chain (GstPad * pad,
|
||||
GstBuffer * buffer);
|
||||
static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans,
|
||||
GstBuffer * inbuf, GstBuffer ** outbuf);
|
||||
static GstCaps *gst_base_transform_getcaps (GstPad * pad);
|
||||
static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
|
||||
static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
|
||||
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
|
||||
|
||||
/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
|
@ -159,6 +161,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
|
|||
GST_DEBUG_FUNCPTR (gst_base_transform_chain));
|
||||
gst_pad_set_activatepush_function (trans->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
|
||||
gst_pad_set_bufferalloc_function (trans->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
|
||||
gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
|
||||
|
||||
pad_template =
|
||||
|
@ -174,6 +178,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
|
|||
gst_pad_set_activatepull_function (trans->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
|
||||
gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
|
||||
|
||||
trans->passthrough = FALSE;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
|
@ -187,10 +193,31 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
|
|||
|
||||
GST_DEBUG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (klass->transform_caps)
|
||||
ret = klass->transform_caps (trans, pad, caps);
|
||||
else
|
||||
/* if there is a custom transform function, use this */
|
||||
if (klass->transform_caps) {
|
||||
GstCaps *temp;
|
||||
gint i;
|
||||
|
||||
ret = gst_caps_new_empty ();
|
||||
|
||||
/* we send caps with just one structure to the transform
|
||||
* function as this is easier for the element */
|
||||
for (i = 0; i < gst_caps_get_size (caps); i++) {
|
||||
GstCaps *nth;
|
||||
|
||||
nth = gst_caps_copy_nth (caps, i);
|
||||
GST_DEBUG_OBJECT (trans, " from: %" GST_PTR_FORMAT, nth);
|
||||
temp = klass->transform_caps (trans, pad, nth);
|
||||
gst_caps_unref (nth);
|
||||
GST_DEBUG_OBJECT (trans, " to : %" GST_PTR_FORMAT, temp);
|
||||
|
||||
gst_caps_append (ret, temp);
|
||||
}
|
||||
gst_caps_do_simplify (ret);
|
||||
} else {
|
||||
/* else use the identity transform */
|
||||
ret = gst_caps_ref (caps);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
|
||||
|
||||
|
@ -210,25 +237,66 @@ gst_base_transform_getcaps (GstPad * pad)
|
|||
|
||||
/* we can do what the peer can */
|
||||
caps = gst_pad_peer_get_caps (otherpad);
|
||||
|
||||
if (caps) {
|
||||
GstCaps *temp;
|
||||
const GstCaps *templ;
|
||||
|
||||
temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (otherpad));
|
||||
GST_DEBUG ("peer caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
/* filtered against our padtemplate */
|
||||
templ = gst_pad_get_pad_template_caps (otherpad);
|
||||
GST_DEBUG ("our template %" GST_PTR_FORMAT, templ);
|
||||
temp = gst_caps_intersect (caps, templ);
|
||||
GST_DEBUG ("intersected %" GST_PTR_FORMAT, temp);
|
||||
gst_caps_unref (caps);
|
||||
/* then see what we can tranform this to */
|
||||
caps = gst_base_transform_transform_caps (trans, otherpad, temp);
|
||||
GST_DEBUG ("transformed %" GST_PTR_FORMAT, caps);
|
||||
gst_caps_unref (temp);
|
||||
temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
|
||||
if (caps == NULL)
|
||||
goto done;
|
||||
|
||||
/* and filter against the template again */
|
||||
templ = gst_pad_get_pad_template_caps (pad);
|
||||
GST_DEBUG ("our template %" GST_PTR_FORMAT, templ);
|
||||
temp = gst_caps_intersect (caps, templ);
|
||||
GST_DEBUG ("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 ("returning %" GST_PTR_FORMAT, caps);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
|
||||
GstCaps * out)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
GstBaseTransformClass *klass;
|
||||
|
||||
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
|
||||
/* no configure the element with the caps */
|
||||
if (klass->set_caps) {
|
||||
ret = klass->set_caps (trans, in, out);
|
||||
}
|
||||
|
||||
/* if all goes well, get the size of the output buffer */
|
||||
if (ret) {
|
||||
trans->out_size = gst_base_transform_get_size (trans);
|
||||
GST_DEBUG ("output buffer size %d", trans->out_size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
|
@ -252,11 +320,9 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
|||
/* see how we can transform the input caps */
|
||||
othercaps = gst_base_transform_transform_caps (trans, pad, caps);
|
||||
|
||||
if (!othercaps || gst_caps_is_empty (othercaps)) {
|
||||
GST_DEBUG ("transform returned useless %" GST_PTR_FORMAT, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
/* check if transform is empty */
|
||||
if (!othercaps || gst_caps_is_empty (othercaps))
|
||||
goto no_transform;
|
||||
|
||||
if (!gst_caps_is_fixed (othercaps)) {
|
||||
GstCaps *temp;
|
||||
|
@ -266,7 +332,7 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
|||
temp = gst_caps_intersect (othercaps, caps);
|
||||
GST_DEBUG ("intersect returned %" GST_PTR_FORMAT, temp);
|
||||
if (temp) {
|
||||
if (!gst_caps_is_empty (temp)) {
|
||||
if (!gst_caps_is_empty (temp) && otherpeer) {
|
||||
GST_DEBUG ("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)) {
|
||||
|
@ -312,39 +378,99 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
|||
GST_DEBUG ("after fixating %" GST_PTR_FORMAT, othercaps);
|
||||
}
|
||||
|
||||
g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
|
||||
/* caps should be fixed now */
|
||||
if (!gst_caps_is_fixed (othercaps))
|
||||
goto could_not_fixate;
|
||||
|
||||
if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps)) {
|
||||
GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
|
||||
" to accept %" GST_PTR_FORMAT, otherpad, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
/* and peer should accept */
|
||||
if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
|
||||
goto peer_no_accept;
|
||||
|
||||
GST_DEBUG ("got final caps %" GST_PTR_FORMAT, othercaps);
|
||||
|
||||
/* we know this will work, we implement the setcaps */
|
||||
gst_pad_set_caps (otherpad, othercaps);
|
||||
|
||||
/* success, let the element know */
|
||||
if (klass->set_caps) {
|
||||
trans->in_place = gst_caps_is_equal (caps, othercaps);
|
||||
GST_DEBUG ("in_place: %d", trans->in_place);
|
||||
|
||||
/* see if we have to configure the element now */
|
||||
if (!trans->delay_configure) {
|
||||
if (pad == trans->sinkpad)
|
||||
ret = klass->set_caps (trans, caps, othercaps);
|
||||
ret = gst_base_transform_configure_caps (trans, caps, othercaps);
|
||||
else
|
||||
ret = klass->set_caps (trans, othercaps, caps);
|
||||
ret = gst_base_transform_configure_caps (trans, othercaps, caps);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (otherpeer)
|
||||
gst_object_unref (otherpeer);
|
||||
|
||||
if (othercaps)
|
||||
gst_caps_unref (othercaps);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
no_transform:
|
||||
{
|
||||
GST_DEBUG ("transform returned useless %" GST_PTR_FORMAT, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
could_not_fixate:
|
||||
{
|
||||
GST_DEBUG ("FAILED to fixate %" GST_PTR_FORMAT, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
peer_no_accept:
|
||||
{
|
||||
GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
|
||||
" to accept %" GST_PTR_FORMAT, otherpad, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
static guint
|
||||
gst_base_transform_get_size (GstBaseTransform * trans)
|
||||
{
|
||||
guint res = -1;
|
||||
GstBaseTransformClass *bclass;
|
||||
|
||||
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
if (bclass->get_size) {
|
||||
res = bclass->get_size (trans);
|
||||
GST_DEBUG ("get size function returned %d", res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
|
||||
GstCaps * caps, GstBuffer ** buf)
|
||||
{
|
||||
GstBaseTransform *trans;
|
||||
GstFlowReturn res;
|
||||
|
||||
trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
|
||||
|
||||
if (trans->in_place) {
|
||||
/* we can only proxy the bufferpool if we do in_place transforms */
|
||||
res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
|
||||
} else {
|
||||
/* else let the default alloc function allocate a buffer */
|
||||
*buf = NULL;
|
||||
res = GST_FLOW_OK;
|
||||
}
|
||||
|
||||
gst_object_unref (trans);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_base_transform_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
|
@ -382,6 +508,92 @@ gst_base_transform_event (GstPad * pad, GstEvent * event)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||
GstBuffer ** outbuf)
|
||||
{
|
||||
GstBaseTransformClass *bclass;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
|
||||
if (trans->in_place) {
|
||||
if (bclass->transform_ip) {
|
||||
gst_buffer_ref (inbuf);
|
||||
|
||||
/* in place transform and subclass supports method */
|
||||
ret = bclass->transform_ip (trans, inbuf);
|
||||
|
||||
*outbuf = inbuf;
|
||||
} else {
|
||||
/* in place transform and subclass does not support method */
|
||||
if (bclass->transform) {
|
||||
/* make a copy of the buffer */
|
||||
*outbuf = inbuf;
|
||||
inbuf = gst_buffer_copy (inbuf);
|
||||
|
||||
ret = bclass->transform (trans, inbuf, *outbuf);
|
||||
} else {
|
||||
ret = GST_FLOW_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* figure out the output size */
|
||||
if (trans->out_size == -1) {
|
||||
/* ask subclass */
|
||||
if ((trans->out_size = gst_base_transform_get_size (trans)) == -1)
|
||||
/* else we have an error */
|
||||
goto no_size;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* no in place transform, get buffer, this might renegotiate. */
|
||||
ret = gst_pad_alloc_buffer (trans->srcpad,
|
||||
GST_BUFFER_OFFSET (inbuf), trans->out_size,
|
||||
GST_PAD_CAPS (trans->srcpad), outbuf);
|
||||
|
||||
trans->delay_configure = FALSE;
|
||||
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto no_buffer;
|
||||
|
||||
gst_buffer_stamp (*outbuf, inbuf);
|
||||
|
||||
if (bclass->transform)
|
||||
ret = bclass->transform (trans, inbuf, *outbuf);
|
||||
else
|
||||
ret = GST_FLOW_NOT_SUPPORTED;
|
||||
|
||||
if (ret)
|
||||
ret =
|
||||
gst_base_transform_configure_caps (trans,
|
||||
GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
|
||||
}
|
||||
gst_buffer_unref (inbuf);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
no_size:
|
||||
{
|
||||
gst_buffer_unref (inbuf);
|
||||
GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
|
||||
("subclass did not specify output size"),
|
||||
("subclass did not specify output size"));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
no_buffer:
|
||||
{
|
||||
gst_buffer_unref (inbuf);
|
||||
GST_DEBUG ("could not get buffer from pool");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_getrange (GstPad * pad, guint64 offset,
|
||||
guint length, GstBuffer ** buffer)
|
||||
|
@ -390,16 +602,14 @@ gst_base_transform_getrange (GstPad * pad, guint64 offset,
|
|||
GstFlowReturn ret;
|
||||
GstBuffer *inbuf;
|
||||
|
||||
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
|
||||
|
||||
ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
|
||||
}
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
gst_object_unref (trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -408,33 +618,17 @@ static GstFlowReturn
|
|||
gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBaseTransform *trans;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstFlowReturn ret;
|
||||
GstBuffer *outbuf;
|
||||
|
||||
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
|
||||
|
||||
ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
ret = gst_pad_push (trans->srcpad, outbuf);
|
||||
}
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||
GstBuffer ** outbuf)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstBaseTransformClass *bclass;
|
||||
|
||||
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
if (bclass->transform)
|
||||
ret = bclass->transform (trans, inbuf, outbuf);
|
||||
gst_object_unref (trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -524,6 +718,10 @@ gst_base_transform_change_state (GstElement * element)
|
|||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
GST_LOCK (trans);
|
||||
trans->in_place = trans->passthrough;
|
||||
trans->out_size = -1;
|
||||
GST_UNLOCK (trans);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
|
@ -548,3 +746,48 @@ gst_base_transform_change_state (GstElement * element)
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_base_transform_set_passthrough:
|
||||
* @trans: the #GstBaseTransform to set
|
||||
* @passthrough: boolean indicating passthrough mode.
|
||||
*
|
||||
* Set passthrough mode for this filter by default. This is mostly
|
||||
* usefull for filters that do not care about negotiation.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_base_transform_set_passthrough (GstBaseTransform * trans,
|
||||
gboolean passthrough)
|
||||
{
|
||||
g_return_if_fail (trans != NULL);
|
||||
|
||||
GST_LOCK (trans);
|
||||
trans->passthrough = passthrough;
|
||||
GST_UNLOCK (trans);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_base_transform_is_passthrough:
|
||||
* @trans: the #GstBaseTransform to query
|
||||
*
|
||||
* See if @trans is configured as a passthrough transform.
|
||||
*
|
||||
* Returns: TRUE is the transform is configured in passthrough mode.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_base_transform_is_passthrough (GstBaseTransform * trans)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
g_return_val_if_fail (trans != NULL, FALSE);
|
||||
|
||||
GST_LOCK (trans);
|
||||
result = trans->passthrough;
|
||||
GST_UNLOCK (trans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ struct _GstBaseTransform {
|
|||
/* source and sink pads */
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
gboolean passthrough;
|
||||
|
||||
gboolean in_place;
|
||||
guint out_size;
|
||||
gboolean delay_configure;
|
||||
};
|
||||
|
||||
struct _GstBaseTransformClass {
|
||||
|
@ -65,6 +71,9 @@ struct _GstBaseTransformClass {
|
|||
gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *incaps,
|
||||
GstCaps *outcaps);
|
||||
|
||||
/* get the size of the output buffer, -1 on error */
|
||||
guint (*get_size) (GstBaseTransform *trans);
|
||||
|
||||
/* start and stop processing, ideal for opening/closing the resource */
|
||||
gboolean (*start) (GstBaseTransform *trans);
|
||||
gboolean (*stop) (GstBaseTransform *trans);
|
||||
|
@ -73,9 +82,15 @@ struct _GstBaseTransformClass {
|
|||
|
||||
/* transform one incoming buffer to one outgoing buffer */
|
||||
GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf,
|
||||
GstBuffer **outbuf);
|
||||
GstBuffer *outbuf);
|
||||
|
||||
/* transform a buffer inplace */
|
||||
GstFlowReturn (*transform_ip) (GstBaseTransform *trans, GstBuffer *buf);
|
||||
};
|
||||
|
||||
void gst_base_transform_set_passthrough (GstBaseTransform *trans, gboolean passthrough);
|
||||
gboolean gst_base_transform_is_passthrough (GstBaseTransform *trans);
|
||||
|
||||
GType gst_base_transform_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
|
|
@ -98,7 +98,7 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
|
|||
|
||||
static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event);
|
||||
static GstFlowReturn gst_identity_transform (GstBaseTransform * trans,
|
||||
GstBuffer * inbuf, GstBuffer ** outbuf);
|
||||
GstBuffer * inbuf, GstBuffer * outbuf);
|
||||
static gboolean gst_identity_start (GstBaseTransform * trans);
|
||||
static gboolean gst_identity_stop (GstBaseTransform * trans);
|
||||
|
||||
|
@ -190,6 +190,8 @@ gst_identity_class_init (GstIdentityClass * klass)
|
|||
static void
|
||||
gst_identity_init (GstIdentity * identity)
|
||||
{
|
||||
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (identity), TRUE);
|
||||
|
||||
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
||||
identity->error_after = DEFAULT_ERROR_AFTER;
|
||||
identity->drop_probability = DEFAULT_DROP_PROBABILITY;
|
||||
|
@ -261,7 +263,7 @@ gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
|
|||
|
||||
static GstFlowReturn
|
||||
gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||
GstBuffer ** outbuf)
|
||||
GstBuffer * outbuf)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstIdentity *identity = GST_IDENTITY (trans);
|
||||
|
@ -274,7 +276,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
if (identity->error_after == 0) {
|
||||
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
||||
(_("Failed after iterations as requested.")), (NULL));
|
||||
gst_buffer_unref (inbuf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -294,7 +295,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
GST_BUFFER_FLAGS (inbuf), inbuf);
|
||||
GST_UNLOCK (identity);
|
||||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
gst_buffer_unref (inbuf);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
}
|
||||
|
@ -319,19 +319,16 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
}
|
||||
|
||||
*outbuf = gst_buffer_make_writable (inbuf);
|
||||
/* inbuf is no longer usable */
|
||||
|
||||
if (identity->datarate > 0) {
|
||||
GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
|
||||
|
||||
GST_BUFFER_TIMESTAMP (*outbuf) = time;
|
||||
GST_BUFFER_DURATION (*outbuf) =
|
||||
GST_BUFFER_SIZE (*outbuf) * GST_SECOND / identity->datarate;
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = time;
|
||||
GST_BUFFER_DURATION (outbuf) =
|
||||
GST_BUFFER_SIZE (outbuf) * GST_SECOND / identity->datarate;
|
||||
}
|
||||
|
||||
g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
|
||||
*outbuf);
|
||||
outbuf);
|
||||
|
||||
if (identity->sync) {
|
||||
GstClock *clock;
|
||||
|
@ -344,7 +341,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
/* FIXME: actually unlock this somewhere if the state changes */
|
||||
GST_LOCK (identity);
|
||||
identity->clock_id = gst_clock_new_single_shot_id (clock,
|
||||
GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time);
|
||||
GST_BUFFER_TIMESTAMP (outbuf) + GST_ELEMENT (identity)->base_time);
|
||||
GST_UNLOCK (identity);
|
||||
cret = gst_clock_id_wait (identity->clock_id, NULL);
|
||||
GST_LOCK (identity);
|
||||
|
@ -358,7 +355,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
}
|
||||
}
|
||||
|
||||
identity->offset += GST_BUFFER_SIZE (*outbuf);
|
||||
identity->offset += GST_BUFFER_SIZE (outbuf);
|
||||
|
||||
if (identity->sleep_time && ret == GST_FLOW_OK)
|
||||
g_usleep (identity->sleep_time);
|
||||
|
|
|
@ -88,6 +88,8 @@ static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
|
|||
gboolean active);
|
||||
static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
|
||||
gboolean active);
|
||||
static guint gst_base_transform_get_size (GstBaseTransform * trans);
|
||||
|
||||
static GstElementStateReturn gst_base_transform_change_state (GstElement *
|
||||
element);
|
||||
|
||||
|
@ -96,10 +98,10 @@ static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
|
|||
guint length, GstBuffer ** buffer);
|
||||
static GstFlowReturn gst_base_transform_chain (GstPad * pad,
|
||||
GstBuffer * buffer);
|
||||
static GstFlowReturn gst_base_transform_handle_buffer (GstBaseTransform * trans,
|
||||
GstBuffer * inbuf, GstBuffer ** outbuf);
|
||||
static GstCaps *gst_base_transform_getcaps (GstPad * pad);
|
||||
static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
|
||||
static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
|
||||
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
|
||||
|
||||
/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
|
@ -159,6 +161,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
|
|||
GST_DEBUG_FUNCPTR (gst_base_transform_chain));
|
||||
gst_pad_set_activatepush_function (trans->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
|
||||
gst_pad_set_bufferalloc_function (trans->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
|
||||
gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
|
||||
|
||||
pad_template =
|
||||
|
@ -174,6 +178,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
|
|||
gst_pad_set_activatepull_function (trans->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
|
||||
gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
|
||||
|
||||
trans->passthrough = FALSE;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
|
@ -187,10 +193,31 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
|
|||
|
||||
GST_DEBUG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (klass->transform_caps)
|
||||
ret = klass->transform_caps (trans, pad, caps);
|
||||
else
|
||||
/* if there is a custom transform function, use this */
|
||||
if (klass->transform_caps) {
|
||||
GstCaps *temp;
|
||||
gint i;
|
||||
|
||||
ret = gst_caps_new_empty ();
|
||||
|
||||
/* we send caps with just one structure to the transform
|
||||
* function as this is easier for the element */
|
||||
for (i = 0; i < gst_caps_get_size (caps); i++) {
|
||||
GstCaps *nth;
|
||||
|
||||
nth = gst_caps_copy_nth (caps, i);
|
||||
GST_DEBUG_OBJECT (trans, " from: %" GST_PTR_FORMAT, nth);
|
||||
temp = klass->transform_caps (trans, pad, nth);
|
||||
gst_caps_unref (nth);
|
||||
GST_DEBUG_OBJECT (trans, " to : %" GST_PTR_FORMAT, temp);
|
||||
|
||||
gst_caps_append (ret, temp);
|
||||
}
|
||||
gst_caps_do_simplify (ret);
|
||||
} else {
|
||||
/* else use the identity transform */
|
||||
ret = gst_caps_ref (caps);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
|
||||
|
||||
|
@ -210,25 +237,66 @@ gst_base_transform_getcaps (GstPad * pad)
|
|||
|
||||
/* we can do what the peer can */
|
||||
caps = gst_pad_peer_get_caps (otherpad);
|
||||
|
||||
if (caps) {
|
||||
GstCaps *temp;
|
||||
const GstCaps *templ;
|
||||
|
||||
temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (otherpad));
|
||||
GST_DEBUG ("peer caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
/* filtered against our padtemplate */
|
||||
templ = gst_pad_get_pad_template_caps (otherpad);
|
||||
GST_DEBUG ("our template %" GST_PTR_FORMAT, templ);
|
||||
temp = gst_caps_intersect (caps, templ);
|
||||
GST_DEBUG ("intersected %" GST_PTR_FORMAT, temp);
|
||||
gst_caps_unref (caps);
|
||||
/* then see what we can tranform this to */
|
||||
caps = gst_base_transform_transform_caps (trans, otherpad, temp);
|
||||
GST_DEBUG ("transformed %" GST_PTR_FORMAT, caps);
|
||||
gst_caps_unref (temp);
|
||||
temp = gst_caps_intersect (caps, gst_pad_get_pad_template_caps (pad));
|
||||
if (caps == NULL)
|
||||
goto done;
|
||||
|
||||
/* and filter against the template again */
|
||||
templ = gst_pad_get_pad_template_caps (pad);
|
||||
GST_DEBUG ("our template %" GST_PTR_FORMAT, templ);
|
||||
temp = gst_caps_intersect (caps, templ);
|
||||
GST_DEBUG ("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 ("returning %" GST_PTR_FORMAT, caps);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
|
||||
GstCaps * out)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
GstBaseTransformClass *klass;
|
||||
|
||||
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
|
||||
/* no configure the element with the caps */
|
||||
if (klass->set_caps) {
|
||||
ret = klass->set_caps (trans, in, out);
|
||||
}
|
||||
|
||||
/* if all goes well, get the size of the output buffer */
|
||||
if (ret) {
|
||||
trans->out_size = gst_base_transform_get_size (trans);
|
||||
GST_DEBUG ("output buffer size %d", trans->out_size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
|
@ -252,11 +320,9 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
|||
/* see how we can transform the input caps */
|
||||
othercaps = gst_base_transform_transform_caps (trans, pad, caps);
|
||||
|
||||
if (!othercaps || gst_caps_is_empty (othercaps)) {
|
||||
GST_DEBUG ("transform returned useless %" GST_PTR_FORMAT, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
/* check if transform is empty */
|
||||
if (!othercaps || gst_caps_is_empty (othercaps))
|
||||
goto no_transform;
|
||||
|
||||
if (!gst_caps_is_fixed (othercaps)) {
|
||||
GstCaps *temp;
|
||||
|
@ -266,7 +332,7 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
|||
temp = gst_caps_intersect (othercaps, caps);
|
||||
GST_DEBUG ("intersect returned %" GST_PTR_FORMAT, temp);
|
||||
if (temp) {
|
||||
if (!gst_caps_is_empty (temp)) {
|
||||
if (!gst_caps_is_empty (temp) && otherpeer) {
|
||||
GST_DEBUG ("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)) {
|
||||
|
@ -312,39 +378,99 @@ gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
|
|||
GST_DEBUG ("after fixating %" GST_PTR_FORMAT, othercaps);
|
||||
}
|
||||
|
||||
g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
|
||||
/* caps should be fixed now */
|
||||
if (!gst_caps_is_fixed (othercaps))
|
||||
goto could_not_fixate;
|
||||
|
||||
if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps)) {
|
||||
GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
|
||||
" to accept %" GST_PTR_FORMAT, otherpad, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
/* and peer should accept */
|
||||
if (otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
|
||||
goto peer_no_accept;
|
||||
|
||||
GST_DEBUG ("got final caps %" GST_PTR_FORMAT, othercaps);
|
||||
|
||||
/* we know this will work, we implement the setcaps */
|
||||
gst_pad_set_caps (otherpad, othercaps);
|
||||
|
||||
/* success, let the element know */
|
||||
if (klass->set_caps) {
|
||||
trans->in_place = gst_caps_is_equal (caps, othercaps);
|
||||
GST_DEBUG ("in_place: %d", trans->in_place);
|
||||
|
||||
/* see if we have to configure the element now */
|
||||
if (!trans->delay_configure) {
|
||||
if (pad == trans->sinkpad)
|
||||
ret = klass->set_caps (trans, caps, othercaps);
|
||||
ret = gst_base_transform_configure_caps (trans, caps, othercaps);
|
||||
else
|
||||
ret = klass->set_caps (trans, othercaps, caps);
|
||||
ret = gst_base_transform_configure_caps (trans, othercaps, caps);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (otherpeer)
|
||||
gst_object_unref (otherpeer);
|
||||
|
||||
if (othercaps)
|
||||
gst_caps_unref (othercaps);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
no_transform:
|
||||
{
|
||||
GST_DEBUG ("transform returned useless %" GST_PTR_FORMAT, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
could_not_fixate:
|
||||
{
|
||||
GST_DEBUG ("FAILED to fixate %" GST_PTR_FORMAT, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
peer_no_accept:
|
||||
{
|
||||
GST_DEBUG ("FAILED to get peer of %" GST_PTR_FORMAT
|
||||
" to accept %" GST_PTR_FORMAT, otherpad, othercaps);
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
static guint
|
||||
gst_base_transform_get_size (GstBaseTransform * trans)
|
||||
{
|
||||
guint res = -1;
|
||||
GstBaseTransformClass *bclass;
|
||||
|
||||
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
if (bclass->get_size) {
|
||||
res = bclass->get_size (trans);
|
||||
GST_DEBUG ("get size function returned %d", res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
|
||||
GstCaps * caps, GstBuffer ** buf)
|
||||
{
|
||||
GstBaseTransform *trans;
|
||||
GstFlowReturn res;
|
||||
|
||||
trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
|
||||
|
||||
if (trans->in_place) {
|
||||
/* we can only proxy the bufferpool if we do in_place transforms */
|
||||
res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
|
||||
} else {
|
||||
/* else let the default alloc function allocate a buffer */
|
||||
*buf = NULL;
|
||||
res = GST_FLOW_OK;
|
||||
}
|
||||
|
||||
gst_object_unref (trans);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_base_transform_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
|
@ -382,6 +508,92 @@ gst_base_transform_event (GstPad * pad, GstEvent * event)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||
GstBuffer ** outbuf)
|
||||
{
|
||||
GstBaseTransformClass *bclass;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
|
||||
if (trans->in_place) {
|
||||
if (bclass->transform_ip) {
|
||||
gst_buffer_ref (inbuf);
|
||||
|
||||
/* in place transform and subclass supports method */
|
||||
ret = bclass->transform_ip (trans, inbuf);
|
||||
|
||||
*outbuf = inbuf;
|
||||
} else {
|
||||
/* in place transform and subclass does not support method */
|
||||
if (bclass->transform) {
|
||||
/* make a copy of the buffer */
|
||||
*outbuf = inbuf;
|
||||
inbuf = gst_buffer_copy (inbuf);
|
||||
|
||||
ret = bclass->transform (trans, inbuf, *outbuf);
|
||||
} else {
|
||||
ret = GST_FLOW_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* figure out the output size */
|
||||
if (trans->out_size == -1) {
|
||||
/* ask subclass */
|
||||
if ((trans->out_size = gst_base_transform_get_size (trans)) == -1)
|
||||
/* else we have an error */
|
||||
goto no_size;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* no in place transform, get buffer, this might renegotiate. */
|
||||
ret = gst_pad_alloc_buffer (trans->srcpad,
|
||||
GST_BUFFER_OFFSET (inbuf), trans->out_size,
|
||||
GST_PAD_CAPS (trans->srcpad), outbuf);
|
||||
|
||||
trans->delay_configure = FALSE;
|
||||
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto no_buffer;
|
||||
|
||||
gst_buffer_stamp (*outbuf, inbuf);
|
||||
|
||||
if (bclass->transform)
|
||||
ret = bclass->transform (trans, inbuf, *outbuf);
|
||||
else
|
||||
ret = GST_FLOW_NOT_SUPPORTED;
|
||||
|
||||
if (ret)
|
||||
ret =
|
||||
gst_base_transform_configure_caps (trans,
|
||||
GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
|
||||
}
|
||||
gst_buffer_unref (inbuf);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
no_size:
|
||||
{
|
||||
gst_buffer_unref (inbuf);
|
||||
GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
|
||||
("subclass did not specify output size"),
|
||||
("subclass did not specify output size"));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
no_buffer:
|
||||
{
|
||||
gst_buffer_unref (inbuf);
|
||||
GST_DEBUG ("could not get buffer from pool");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_getrange (GstPad * pad, guint64 offset,
|
||||
guint length, GstBuffer ** buffer)
|
||||
|
@ -390,16 +602,14 @@ gst_base_transform_getrange (GstPad * pad, guint64 offset,
|
|||
GstFlowReturn ret;
|
||||
GstBuffer *inbuf;
|
||||
|
||||
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
|
||||
|
||||
ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
|
||||
}
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
gst_object_unref (trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -408,33 +618,17 @@ static GstFlowReturn
|
|||
gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBaseTransform *trans;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstFlowReturn ret;
|
||||
GstBuffer *outbuf;
|
||||
|
||||
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_STREAM_LOCK (pad);
|
||||
trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
|
||||
|
||||
ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
|
||||
if (ret == GST_FLOW_OK) {
|
||||
ret = gst_pad_push (trans->srcpad, outbuf);
|
||||
}
|
||||
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||
GstBuffer ** outbuf)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstBaseTransformClass *bclass;
|
||||
|
||||
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||
if (bclass->transform)
|
||||
ret = bclass->transform (trans, inbuf, outbuf);
|
||||
gst_object_unref (trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -524,6 +718,10 @@ gst_base_transform_change_state (GstElement * element)
|
|||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
GST_LOCK (trans);
|
||||
trans->in_place = trans->passthrough;
|
||||
trans->out_size = -1;
|
||||
GST_UNLOCK (trans);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
|
@ -548,3 +746,48 @@ gst_base_transform_change_state (GstElement * element)
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_base_transform_set_passthrough:
|
||||
* @trans: the #GstBaseTransform to set
|
||||
* @passthrough: boolean indicating passthrough mode.
|
||||
*
|
||||
* Set passthrough mode for this filter by default. This is mostly
|
||||
* usefull for filters that do not care about negotiation.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
void
|
||||
gst_base_transform_set_passthrough (GstBaseTransform * trans,
|
||||
gboolean passthrough)
|
||||
{
|
||||
g_return_if_fail (trans != NULL);
|
||||
|
||||
GST_LOCK (trans);
|
||||
trans->passthrough = passthrough;
|
||||
GST_UNLOCK (trans);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_base_transform_is_passthrough:
|
||||
* @trans: the #GstBaseTransform to query
|
||||
*
|
||||
* See if @trans is configured as a passthrough transform.
|
||||
*
|
||||
* Returns: TRUE is the transform is configured in passthrough mode.
|
||||
*
|
||||
* MT safe.
|
||||
*/
|
||||
gboolean
|
||||
gst_base_transform_is_passthrough (GstBaseTransform * trans)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
g_return_val_if_fail (trans != NULL, FALSE);
|
||||
|
||||
GST_LOCK (trans);
|
||||
result = trans->passthrough;
|
||||
GST_UNLOCK (trans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ struct _GstBaseTransform {
|
|||
/* source and sink pads */
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
gboolean passthrough;
|
||||
|
||||
gboolean in_place;
|
||||
guint out_size;
|
||||
gboolean delay_configure;
|
||||
};
|
||||
|
||||
struct _GstBaseTransformClass {
|
||||
|
@ -65,6 +71,9 @@ struct _GstBaseTransformClass {
|
|||
gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *incaps,
|
||||
GstCaps *outcaps);
|
||||
|
||||
/* get the size of the output buffer, -1 on error */
|
||||
guint (*get_size) (GstBaseTransform *trans);
|
||||
|
||||
/* start and stop processing, ideal for opening/closing the resource */
|
||||
gboolean (*start) (GstBaseTransform *trans);
|
||||
gboolean (*stop) (GstBaseTransform *trans);
|
||||
|
@ -73,9 +82,15 @@ struct _GstBaseTransformClass {
|
|||
|
||||
/* transform one incoming buffer to one outgoing buffer */
|
||||
GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf,
|
||||
GstBuffer **outbuf);
|
||||
GstBuffer *outbuf);
|
||||
|
||||
/* transform a buffer inplace */
|
||||
GstFlowReturn (*transform_ip) (GstBaseTransform *trans, GstBuffer *buf);
|
||||
};
|
||||
|
||||
void gst_base_transform_set_passthrough (GstBaseTransform *trans, gboolean passthrough);
|
||||
gboolean gst_base_transform_is_passthrough (GstBaseTransform *trans);
|
||||
|
||||
GType gst_base_transform_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
|
|
@ -98,7 +98,7 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
|
|||
|
||||
static gboolean gst_identity_event (GstBaseTransform * trans, GstEvent * event);
|
||||
static GstFlowReturn gst_identity_transform (GstBaseTransform * trans,
|
||||
GstBuffer * inbuf, GstBuffer ** outbuf);
|
||||
GstBuffer * inbuf, GstBuffer * outbuf);
|
||||
static gboolean gst_identity_start (GstBaseTransform * trans);
|
||||
static gboolean gst_identity_stop (GstBaseTransform * trans);
|
||||
|
||||
|
@ -190,6 +190,8 @@ gst_identity_class_init (GstIdentityClass * klass)
|
|||
static void
|
||||
gst_identity_init (GstIdentity * identity)
|
||||
{
|
||||
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (identity), TRUE);
|
||||
|
||||
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
||||
identity->error_after = DEFAULT_ERROR_AFTER;
|
||||
identity->drop_probability = DEFAULT_DROP_PROBABILITY;
|
||||
|
@ -261,7 +263,7 @@ gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf)
|
|||
|
||||
static GstFlowReturn
|
||||
gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||
GstBuffer ** outbuf)
|
||||
GstBuffer * outbuf)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstIdentity *identity = GST_IDENTITY (trans);
|
||||
|
@ -274,7 +276,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
if (identity->error_after == 0) {
|
||||
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
||||
(_("Failed after iterations as requested.")), (NULL));
|
||||
gst_buffer_unref (inbuf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -294,7 +295,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
GST_BUFFER_FLAGS (inbuf), inbuf);
|
||||
GST_UNLOCK (identity);
|
||||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
gst_buffer_unref (inbuf);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
}
|
||||
|
@ -319,19 +319,16 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
g_object_notify (G_OBJECT (identity), "last-message");
|
||||
}
|
||||
|
||||
*outbuf = gst_buffer_make_writable (inbuf);
|
||||
/* inbuf is no longer usable */
|
||||
|
||||
if (identity->datarate > 0) {
|
||||
GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
|
||||
|
||||
GST_BUFFER_TIMESTAMP (*outbuf) = time;
|
||||
GST_BUFFER_DURATION (*outbuf) =
|
||||
GST_BUFFER_SIZE (*outbuf) * GST_SECOND / identity->datarate;
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = time;
|
||||
GST_BUFFER_DURATION (outbuf) =
|
||||
GST_BUFFER_SIZE (outbuf) * GST_SECOND / identity->datarate;
|
||||
}
|
||||
|
||||
g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
|
||||
*outbuf);
|
||||
outbuf);
|
||||
|
||||
if (identity->sync) {
|
||||
GstClock *clock;
|
||||
|
@ -344,7 +341,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
/* FIXME: actually unlock this somewhere if the state changes */
|
||||
GST_LOCK (identity);
|
||||
identity->clock_id = gst_clock_new_single_shot_id (clock,
|
||||
GST_BUFFER_TIMESTAMP (*outbuf) + GST_ELEMENT (identity)->base_time);
|
||||
GST_BUFFER_TIMESTAMP (outbuf) + GST_ELEMENT (identity)->base_time);
|
||||
GST_UNLOCK (identity);
|
||||
cret = gst_clock_id_wait (identity->clock_id, NULL);
|
||||
GST_LOCK (identity);
|
||||
|
@ -358,7 +355,7 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
|
|||
}
|
||||
}
|
||||
|
||||
identity->offset += GST_BUFFER_SIZE (*outbuf);
|
||||
identity->offset += GST_BUFFER_SIZE (outbuf);
|
||||
|
||||
if (identity->sleep_time && ret == GST_FLOW_OK)
|
||||
g_usleep (identity->sleep_time);
|
||||
|
|
Loading…
Reference in a new issue