tests/network-clock.scm: Commentary update.

Original commit message from CVS:
2005-07-01  Andy Wingo  <wingo@pobox.com>

* tests/network-clock.scm: Commentary update.

* gst/elements/gstidentity.c (PROP_DUPLICATE): Gone daddy gone.
Didn't really make sense, not implementable with basetransform,
etc.
(gst_identity_transform): Unref inbuf via make_writable. Feeble
attempt at implementing the sync property, needs an unlock method.

* gst/base/gstbasetransform.c (gst_base_transform_transform_caps):
New func, by default returns the same caps (the identity
transformation).
(gst_base_transform_getcaps): Uses transform_caps to return
something sensible.
(gst_base_transform_setcaps): Complicated logic to get caps on
both pads, even if they are different, and to call set_caps once
for every time both pads get their caps set.
(gst_base_transform_handle_buffer): Give the ref to the transform
function. Allows in-place modification of the buffer.

* gst/base/gstbasetransform.h (transform_caps): New class method.
Given caps on one side, what can I do on the other.
(set_caps): Take two caps, one for each side of the element.

* gst/gstpad.h:
* gst/gstpad.c (gst_pad_fixate_caps): Change prototype to modify
caps in place. This is safe because we can check the mutability of
the caps, and a good idea because fixate functions are just called
as a matter of last resort. (Not actually implemented.)
(gst_pad_set_caps): If the caps we're setting is actually the same
as the existing pad caps, just update the pointer without calling
setcaps. Assert that caps is either NULL or fixed, as per the
docs.

* gst/gstghostpad.c: Update for fixate changes.
This commit is contained in:
Andy Wingo 2005-07-01 16:46:59 +00:00
parent e762446852
commit c1d34b8acf
18 changed files with 440 additions and 197 deletions

View file

@ -1,3 +1,46 @@
2005-07-01 Andy Wingo <wingo@pobox.com>
* tests/network-clock.scm: Commentary update.
* gst/elements/gstidentity.c (PROP_DUPLICATE): Gone daddy gone.
Didn't really make sense, not implementable with basetransform,
etc.
(gst_identity_transform): Unref inbuf via make_writable. Feeble
attempt at implementing the sync property, needs an unlock method.
* gst/base/gstbasetransform.c (gst_base_transform_transform_caps):
New func, by default returns the same caps (the identity
transformation).
(gst_base_transform_getcaps): Uses transform_caps to return
something sensible.
(gst_base_transform_setcaps): Complicated logic to get caps on
both pads, even if they are different, and to call set_caps once
for every time both pads get their caps set.
(gst_base_transform_handle_buffer): Give the ref to the transform
function. Allows in-place modification of the buffer.
* gst/base/gstbasetransform.h (transform_caps): New class method.
Given caps on one side, what can I do on the other.
(set_caps): Take two caps, one for each side of the element.
* gst/gstpad.h:
* gst/gstpad.c (gst_pad_fixate_caps): Change prototype to modify
caps in place. This is safe because we can check the mutability of
the caps, and a good idea because fixate functions are just called
as a matter of last resort. (Not actually implemented.)
(gst_pad_set_caps): If the caps we're setting is actually the same
as the existing pad caps, just update the pointer without calling
setcaps. Assert that caps is either NULL or fixed, as per the
docs.
* gst/gstghostpad.c: Update for fixate changes.
2005-07-02 Andy Wingo <wingo@pobox.com>
* gst/gstcaps.c:
* gst/gstcaps.h (gst_static_caps_get): Not const return, having
two refcounts makes it immutable, which is enough. Doc more.
2005-07-02 Jan Schmidt <thaytan@mad.scientist.com>
* gst/gstpad.c: (gst_pad_emit_have_data_signal):

View file

@ -26,6 +26,7 @@ GstBaseTransform
</para>
@parent_class:
@transform_caps:
@set_caps:
@start:
@stop:

View file

@ -90,8 +90,8 @@ Last reviewed on December 13th, 2002 (0.5.0.1)
@queryfunc:
@intlinkfunc:
@bufferallocfunc:
@emit_buffer_signals:
@emit_event_signals:
@do_buffer_signals:
@do_event_signals:
<!-- ##### SIGNAL GstPad::have-data ##### -->
<para>

View file

@ -98,7 +98,7 @@ 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_proxy_getcaps (GstPad * pad);
static GstCaps *gst_base_transform_getcaps (GstPad * pad);
static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
@ -150,7 +150,7 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
g_return_if_fail (pad_template != NULL);
trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
gst_pad_set_getcaps_function (trans->sinkpad,
GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
gst_pad_set_setcaps_function (trans->sinkpad,
GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
gst_pad_set_event_function (trans->sinkpad,
@ -166,7 +166,9 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
g_return_if_fail (pad_template != NULL);
trans->srcpad = gst_pad_new_from_template (pad_template, "src");
gst_pad_set_getcaps_function (trans->srcpad,
GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
gst_pad_set_setcaps_function (trans->srcpad,
GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
gst_pad_set_getrange_function (trans->srcpad,
GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
gst_pad_set_activatepull_function (trans->srcpad,
@ -175,46 +177,135 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
}
static GstCaps *
gst_base_transform_proxy_getcaps (GstPad * pad)
gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
GstCaps * caps)
{
GstBaseTransformClass *klass;
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (klass->transform_caps)
return klass->transform_caps (trans, pad, caps);
else
return gst_caps_ref (caps);
}
static GstCaps *
gst_base_transform_getcaps (GstPad * pad)
{
GstPad *otherpad;
GstBaseTransform *trans;
GstPad *otherpad;
GstCaps *caps;
const GstCaps *templcaps;
trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad;
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
/* we can do whatever the peer can do */
/* we can do what the peer can */
caps = gst_pad_peer_get_caps (otherpad);
templcaps = gst_pad_get_pad_template_caps (pad);
if (caps == NULL) {
/* no peer, then the padtemplate is enough */
return gst_caps_copy (templcaps);
} else {
GstCaps *ret = gst_caps_intersect (caps, templcaps);
if (caps) {
GstCaps *temp;
temp = gst_base_transform_transform_caps (trans, otherpad, caps);
gst_caps_unref (caps);
return ret;
caps = gst_caps_intersect (temp, gst_pad_get_pad_template_caps (pad));
gst_caps_unref (temp);
} else {
/* no peer, our padtemplate is enough then */
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
}
return caps;
}
static gboolean
gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
{
GstBaseTransform *trans;
GstBaseTransformClass *bclass;
gboolean result = TRUE;
GstBaseTransformClass *klass;
GstStructure *structure;
GstPad *otherpad, *otherpeer;
gboolean ret = TRUE;
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (bclass->set_caps)
result = bclass->set_caps (trans, caps);
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
otherpeer = gst_pad_get_peer (otherpad);
return result;
if (GST_PAD_IS_IN_SETCAPS (otherpad))
goto done;
if (otherpeer == NULL || gst_pad_accept_caps (otherpeer, caps)) {
/* the peer accepts the caps as they are */
gst_pad_set_caps (otherpad, caps);
/* let the element know */
if (klass->set_caps)
klass->set_caps (trans, caps, caps);
ret = TRUE;
} else {
GstCaps *peercaps;
GstCaps *intersect;
GstCaps *transform = NULL;
GstCaps *othercaps;
ret = FALSE;
/* other pad has a peer, so we have to figure out how to do the conversion
*/
/* see how we can transform the input caps */
transform = gst_base_transform_transform_caps (trans, pad, caps);
if (!transform)
goto done;
/* see what the peer can do */
peercaps = gst_pad_get_caps (otherpeer);
GST_DEBUG ("icaps %" GST_PTR_FORMAT, peercaps);
GST_DEBUG ("transform %" GST_PTR_FORMAT, transform);
/* filter against our possibilities */
intersect = gst_caps_intersect (peercaps, transform);
gst_caps_unref (peercaps);
gst_caps_unref (transform);
GST_DEBUG ("intersect %" GST_PTR_FORMAT, intersect);
/* take first possibility */
othercaps = gst_caps_copy_nth (intersect, 0);
gst_caps_unref (intersect);
structure = gst_caps_get_structure (othercaps, 0);
/* and fixate if necessary */
gst_pad_fixate_caps (otherpad, othercaps);
g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
gst_pad_set_caps (otherpad, othercaps);
/* let the element know */
if (klass->set_caps) {
if (pad == trans->sinkpad) {
klass->set_caps (trans, caps, othercaps);
} else {
klass->set_caps (trans, othercaps, caps);
}
}
ret = TRUE;
}
done:
if (otherpeer)
gst_object_unref (otherpeer);
return ret;
}
static gboolean
@ -308,8 +399,6 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
if (bclass->transform)
ret = bclass->transform (trans, inbuf, outbuf);
gst_buffer_unref (inbuf);
return ret;
}

View file

@ -57,9 +57,13 @@ struct _GstBaseTransformClass {
/*< public >*/
/* virtual methods for subclasses */
/* given caps on one pad, what can I do on the other pad */
GstCaps* (*transform_caps) (GstBaseTransform *trans, GstPad *pad,
GstCaps *caps);
/* notify the subclass of new caps */
gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *caps);
gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *incaps,
GstCaps *outcaps);
/* start and stop processing, ideal for opening/closing the resource */
gboolean (*start) (GstBaseTransform *trans);
@ -68,7 +72,8 @@ struct _GstBaseTransformClass {
gboolean (*event) (GstBaseTransform *trans, GstEvent *event);
/* transform one incoming buffer to one outgoing buffer */
GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf);
GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf,
GstBuffer **outbuf);
};
GType gst_base_transform_get_type (void);

View file

@ -73,7 +73,6 @@ enum
{
PROP_0,
PROP_SLEEP_TIME,
PROP_DUPLICATE,
PROP_ERROR_AFTER,
PROP_DROP_PROBABILITY,
PROP_DATARATE,
@ -147,10 +146,6 @@ gst_identity_class_init (GstIdentityClass * klass)
g_param_spec_uint ("sleep-time", "Sleep time",
"Microseconds to sleep between processing", 0, G_MAXUINT,
DEFAULT_SLEEP_TIME, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE,
g_param_spec_uint ("duplicate", "Duplicate Buffers",
"Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER,
g_param_spec_int ("error_after", "Error After", "Error after N buffers",
G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE));
@ -196,7 +191,6 @@ static void
gst_identity_init (GstIdentity * identity)
{
identity->sleep_time = DEFAULT_SLEEP_TIME;
identity->duplicate = DEFAULT_DUPLICATE;
identity->error_after = DEFAULT_ERROR_AFTER;
identity->drop_probability = DEFAULT_DROP_PROBABILITY;
identity->datarate = DEFAULT_DATARATE;
@ -271,7 +265,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
{
GstFlowReturn ret = GST_FLOW_OK;
GstIdentity *identity = GST_IDENTITY (trans);
guint i;
if (identity->check_perfect)
gst_identity_check_perfect (identity, inbuf);
@ -281,6 +274,7 @@ 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;
}
}
@ -300,6 +294,7 @@ 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;
}
}
@ -308,56 +303,66 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
}
for (i = identity->duplicate; i; i--) {
GstClockTime time;
if (!identity->silent) {
GST_LOCK (identity);
g_free (identity->last_message);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %"
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
GST_BUFFER_FLAGS (inbuf), inbuf);
GST_UNLOCK (identity);
g_object_notify (G_OBJECT (identity), "last-message");
}
time = GST_BUFFER_TIMESTAMP (inbuf);
if (identity->datarate > 0) {
time = identity->offset * GST_SECOND / identity->datarate;
GST_BUFFER_TIMESTAMP (inbuf) = time;
GST_BUFFER_DURATION (inbuf) =
GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate;
}
g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
inbuf);
if (i > 1)
gst_buffer_ref (inbuf);
if (identity->sync) {
if (GST_ELEMENT (identity)->clock) {
/* gst_element_wait (GST_ELEMENT (identity), time); */
}
}
identity->offset += GST_BUFFER_SIZE (inbuf);
if (identity->sleep_time)
g_usleep (identity->sleep_time);
gst_buffer_ref (inbuf);
*outbuf = inbuf;
if (!identity->silent) {
GST_LOCK (identity);
g_free (identity->last_message);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %"
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
GST_BUFFER_FLAGS (inbuf), inbuf);
GST_UNLOCK (identity);
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;
}
g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
*outbuf);
if (identity->sync) {
GstClock *clock;
GstClockReturn cret;
clock = GST_ELEMENT (identity)->clock;
if (clock) {
/* save id if we need to unlock */
/* 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_UNLOCK (identity);
cret = gst_clock_id_wait (identity->clock_id, NULL);
GST_LOCK (identity);
if (identity->clock_id) {
gst_clock_id_unref (identity->clock_id);
identity->clock_id = NULL;
}
GST_UNLOCK (identity);
if (cret == GST_CLOCK_UNSCHEDULED)
ret = GST_FLOW_UNEXPECTED;
}
}
identity->offset += GST_BUFFER_SIZE (*outbuf);
if (identity->sleep_time && ret == GST_FLOW_OK)
g_usleep (identity->sleep_time);
return ret;
}
@ -376,9 +381,6 @@ gst_identity_set_property (GObject * object, guint prop_id,
case PROP_SILENT:
identity->silent = g_value_get_boolean (value);
break;
case PROP_DUPLICATE:
identity->duplicate = g_value_get_uint (value);
break;
case PROP_DUMP:
identity->dump = g_value_get_boolean (value);
break;
@ -415,9 +417,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_SLEEP_TIME:
g_value_set_uint (value, identity->sleep_time);
break;
case PROP_DUPLICATE:
g_value_set_uint (value, identity->duplicate);
break;
case PROP_ERROR_AFTER:
g_value_set_int (value, identity->error_after);
break;

View file

@ -48,7 +48,7 @@ typedef struct _GstIdentityClass GstIdentityClass;
struct _GstIdentity {
GstBaseTransform element;
guint duplicate;
GstClockID clock_id;
gint error_after;
gfloat drop_probability;
gint datarate;

View file

@ -347,9 +347,11 @@ gst_caps_unref (GstCaps * caps)
*
* Converts a #GstStaticCaps to a #GstCaps.
*
* Returns: the new #GstCaps
* Returns: A pointer to the #GstCaps. Although you do not have a reference on
* the caps, the core will never drop its references. (The core has two
* references on the caps so it will be immutable.)
*/
const GstCaps *
GstCaps *
gst_static_caps_get (GstStaticCaps * static_caps)
{
GstCaps *caps = (GstCaps *) static_caps;

View file

@ -98,7 +98,7 @@ GstCaps * gst_caps_copy (const GstCaps * caps);
GstCaps * gst_caps_make_writable (GstCaps *caps);
void gst_caps_unref (GstCaps* caps);
G_CONST_RETURN GstCaps * gst_static_caps_get (GstStaticCaps *static_caps);
GstCaps * gst_static_caps_get (GstStaticCaps *static_caps);
/* manipulation */
void gst_caps_append (GstCaps *caps1,

View file

@ -279,14 +279,14 @@ gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
return gst_pad_accept_caps (target, caps);
}
static GstCaps *
static void
gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
{
GstPad *target = GST_PROXY_PAD_TARGET (pad);
g_return_val_if_fail (target != NULL, NULL);
g_return_if_fail (target != NULL);
return gst_pad_fixate_caps (target, caps);
gst_pad_fixate_caps (target, caps);
}
static gboolean

View file

@ -1748,15 +1748,13 @@ was_dispatching:
* gst_pad_fixate_caps:
* @pad: a #GstPad to fixate
*
* Fixate a caps on the given pad.
*
* Returns: a fixated #GstCaps.
* Fixate a caps on the given pad. Modifies the caps in place, so you should be
* that the caps are actually writable (see gst_caps_make_writable()).
*/
GstCaps *
void
gst_pad_fixate_caps (GstPad * pad, GstCaps * caps)
{
/* FIXME, implement me, call the fixate function for the pad */
return caps;
}
/**
@ -1857,12 +1855,20 @@ gboolean
gst_pad_set_caps (GstPad * pad, GstCaps * caps)
{
GstPadSetCapsFunction setcaps;
GstCaps *existing;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (caps == NULL || gst_caps_is_fixed (caps), FALSE);
GST_LOCK (pad);
setcaps = GST_PAD_SETCAPSFUNC (pad);
existing = GST_PAD_CAPS (pad);
if (caps == existing)
goto setting_same_caps;
else if (caps && existing && gst_caps_is_equal (caps, existing))
goto setting_same_caps;
/* call setcaps function to configure the pad */
if (setcaps != NULL && caps) {
if (!GST_PAD_IS_IN_SETCAPS (pad)) {
@ -1887,6 +1893,15 @@ gst_pad_set_caps (GstPad * pad, GstCaps * caps)
return TRUE;
setting_same_caps:
{
GST_UNLOCK (pad);
gst_caps_replace (&GST_PAD_CAPS (pad), caps);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"caps %" GST_PTR_FORMAT " same as existing, updating ptr only", caps);
return TRUE;
}
/* errors */
could_not_set:
{
GST_LOCK (pad);

View file

@ -117,7 +117,7 @@ typedef void (*GstPadUnlinkFunction) (GstPad *pad);
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad);
typedef gboolean (*GstPadSetCapsFunction) (GstPad *pad, GstCaps *caps);
typedef gboolean (*GstPadAcceptCapsFunction) (GstPad *pad, GstCaps *caps);
typedef GstCaps* (*GstPadFixateCapsFunction) (GstPad *pad, GstCaps *caps);
typedef void (*GstPadFixateCapsFunction) (GstPad *pad, GstCaps *caps);
typedef GstFlowReturn (*GstPadBufferAllocFunction) (GstPad *pad, guint64 offset, guint size,
GstCaps *caps, GstBuffer **buf);
/* misc */
@ -414,7 +414,7 @@ G_CONST_RETURN GstCaps* gst_pad_get_pad_template_caps (GstPad *pad);
/* capsnego function for connected/unconnected pads */
GstCaps * gst_pad_get_caps (GstPad * pad);
GstCaps* gst_pad_fixate_caps (GstPad * pad, GstCaps *caps);
void gst_pad_fixate_caps (GstPad * pad, GstCaps *caps);
gboolean gst_pad_accept_caps (GstPad * pad, GstCaps *caps);
gboolean gst_pad_set_caps (GstPad * pad, GstCaps *caps);

View file

@ -98,7 +98,7 @@ 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_proxy_getcaps (GstPad * pad);
static GstCaps *gst_base_transform_getcaps (GstPad * pad);
static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
@ -150,7 +150,7 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
g_return_if_fail (pad_template != NULL);
trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
gst_pad_set_getcaps_function (trans->sinkpad,
GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
gst_pad_set_setcaps_function (trans->sinkpad,
GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
gst_pad_set_event_function (trans->sinkpad,
@ -166,7 +166,9 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
g_return_if_fail (pad_template != NULL);
trans->srcpad = gst_pad_new_from_template (pad_template, "src");
gst_pad_set_getcaps_function (trans->srcpad,
GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps));
GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
gst_pad_set_setcaps_function (trans->srcpad,
GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
gst_pad_set_getrange_function (trans->srcpad,
GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
gst_pad_set_activatepull_function (trans->srcpad,
@ -175,46 +177,135 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class)
}
static GstCaps *
gst_base_transform_proxy_getcaps (GstPad * pad)
gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
GstCaps * caps)
{
GstBaseTransformClass *klass;
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (klass->transform_caps)
return klass->transform_caps (trans, pad, caps);
else
return gst_caps_ref (caps);
}
static GstCaps *
gst_base_transform_getcaps (GstPad * pad)
{
GstPad *otherpad;
GstBaseTransform *trans;
GstPad *otherpad;
GstCaps *caps;
const GstCaps *templcaps;
trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
otherpad = pad == trans->srcpad ? trans->sinkpad : trans->srcpad;
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
/* we can do whatever the peer can do */
/* we can do what the peer can */
caps = gst_pad_peer_get_caps (otherpad);
templcaps = gst_pad_get_pad_template_caps (pad);
if (caps == NULL) {
/* no peer, then the padtemplate is enough */
return gst_caps_copy (templcaps);
} else {
GstCaps *ret = gst_caps_intersect (caps, templcaps);
if (caps) {
GstCaps *temp;
temp = gst_base_transform_transform_caps (trans, otherpad, caps);
gst_caps_unref (caps);
return ret;
caps = gst_caps_intersect (temp, gst_pad_get_pad_template_caps (pad));
gst_caps_unref (temp);
} else {
/* no peer, our padtemplate is enough then */
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
}
return caps;
}
static gboolean
gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
{
GstBaseTransform *trans;
GstBaseTransformClass *bclass;
gboolean result = TRUE;
GstBaseTransformClass *klass;
GstStructure *structure;
GstPad *otherpad, *otherpeer;
gboolean ret = TRUE;
trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (bclass->set_caps)
result = bclass->set_caps (trans, caps);
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
otherpeer = gst_pad_get_peer (otherpad);
return result;
if (GST_PAD_IS_IN_SETCAPS (otherpad))
goto done;
if (otherpeer == NULL || gst_pad_accept_caps (otherpeer, caps)) {
/* the peer accepts the caps as they are */
gst_pad_set_caps (otherpad, caps);
/* let the element know */
if (klass->set_caps)
klass->set_caps (trans, caps, caps);
ret = TRUE;
} else {
GstCaps *peercaps;
GstCaps *intersect;
GstCaps *transform = NULL;
GstCaps *othercaps;
ret = FALSE;
/* other pad has a peer, so we have to figure out how to do the conversion
*/
/* see how we can transform the input caps */
transform = gst_base_transform_transform_caps (trans, pad, caps);
if (!transform)
goto done;
/* see what the peer can do */
peercaps = gst_pad_get_caps (otherpeer);
GST_DEBUG ("icaps %" GST_PTR_FORMAT, peercaps);
GST_DEBUG ("transform %" GST_PTR_FORMAT, transform);
/* filter against our possibilities */
intersect = gst_caps_intersect (peercaps, transform);
gst_caps_unref (peercaps);
gst_caps_unref (transform);
GST_DEBUG ("intersect %" GST_PTR_FORMAT, intersect);
/* take first possibility */
othercaps = gst_caps_copy_nth (intersect, 0);
gst_caps_unref (intersect);
structure = gst_caps_get_structure (othercaps, 0);
/* and fixate if necessary */
gst_pad_fixate_caps (otherpad, othercaps);
g_return_val_if_fail (gst_caps_is_fixed (othercaps), FALSE);
gst_pad_set_caps (otherpad, othercaps);
/* let the element know */
if (klass->set_caps) {
if (pad == trans->sinkpad) {
klass->set_caps (trans, caps, othercaps);
} else {
klass->set_caps (trans, othercaps, caps);
}
}
ret = TRUE;
}
done:
if (otherpeer)
gst_object_unref (otherpeer);
return ret;
}
static gboolean
@ -308,8 +399,6 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
if (bclass->transform)
ret = bclass->transform (trans, inbuf, outbuf);
gst_buffer_unref (inbuf);
return ret;
}

View file

@ -57,9 +57,13 @@ struct _GstBaseTransformClass {
/*< public >*/
/* virtual methods for subclasses */
/* given caps on one pad, what can I do on the other pad */
GstCaps* (*transform_caps) (GstBaseTransform *trans, GstPad *pad,
GstCaps *caps);
/* notify the subclass of new caps */
gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *caps);
gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *incaps,
GstCaps *outcaps);
/* start and stop processing, ideal for opening/closing the resource */
gboolean (*start) (GstBaseTransform *trans);
@ -68,7 +72,8 @@ struct _GstBaseTransformClass {
gboolean (*event) (GstBaseTransform *trans, GstEvent *event);
/* transform one incoming buffer to one outgoing buffer */
GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer **outbuf);
GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf,
GstBuffer **outbuf);
};
GType gst_base_transform_get_type (void);

View file

@ -73,7 +73,6 @@ enum
{
PROP_0,
PROP_SLEEP_TIME,
PROP_DUPLICATE,
PROP_ERROR_AFTER,
PROP_DROP_PROBABILITY,
PROP_DATARATE,
@ -147,10 +146,6 @@ gst_identity_class_init (GstIdentityClass * klass)
g_param_spec_uint ("sleep-time", "Sleep time",
"Microseconds to sleep between processing", 0, G_MAXUINT,
DEFAULT_SLEEP_TIME, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE,
g_param_spec_uint ("duplicate", "Duplicate Buffers",
"Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER,
g_param_spec_int ("error_after", "Error After", "Error after N buffers",
G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE));
@ -196,7 +191,6 @@ static void
gst_identity_init (GstIdentity * identity)
{
identity->sleep_time = DEFAULT_SLEEP_TIME;
identity->duplicate = DEFAULT_DUPLICATE;
identity->error_after = DEFAULT_ERROR_AFTER;
identity->drop_probability = DEFAULT_DROP_PROBABILITY;
identity->datarate = DEFAULT_DATARATE;
@ -271,7 +265,6 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
{
GstFlowReturn ret = GST_FLOW_OK;
GstIdentity *identity = GST_IDENTITY (trans);
guint i;
if (identity->check_perfect)
gst_identity_check_perfect (identity, inbuf);
@ -281,6 +274,7 @@ 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;
}
}
@ -300,6 +294,7 @@ 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;
}
}
@ -308,56 +303,66 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
gst_util_dump_mem (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
}
for (i = identity->duplicate; i; i--) {
GstClockTime time;
if (!identity->silent) {
GST_LOCK (identity);
g_free (identity->last_message);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %"
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
GST_BUFFER_FLAGS (inbuf), inbuf);
GST_UNLOCK (identity);
g_object_notify (G_OBJECT (identity), "last-message");
}
time = GST_BUFFER_TIMESTAMP (inbuf);
if (identity->datarate > 0) {
time = identity->offset * GST_SECOND / identity->datarate;
GST_BUFFER_TIMESTAMP (inbuf) = time;
GST_BUFFER_DURATION (inbuf) =
GST_BUFFER_SIZE (inbuf) * GST_SECOND / identity->datarate;
}
g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
inbuf);
if (i > 1)
gst_buffer_ref (inbuf);
if (identity->sync) {
if (GST_ELEMENT (identity)->clock) {
/* gst_element_wait (GST_ELEMENT (identity), time); */
}
}
identity->offset += GST_BUFFER_SIZE (inbuf);
if (identity->sleep_time)
g_usleep (identity->sleep_time);
gst_buffer_ref (inbuf);
*outbuf = inbuf;
if (!identity->silent) {
GST_LOCK (identity);
g_free (identity->last_message);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %"
GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (inbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
GST_BUFFER_FLAGS (inbuf), inbuf);
GST_UNLOCK (identity);
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;
}
g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
*outbuf);
if (identity->sync) {
GstClock *clock;
GstClockReturn cret;
clock = GST_ELEMENT (identity)->clock;
if (clock) {
/* save id if we need to unlock */
/* 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_UNLOCK (identity);
cret = gst_clock_id_wait (identity->clock_id, NULL);
GST_LOCK (identity);
if (identity->clock_id) {
gst_clock_id_unref (identity->clock_id);
identity->clock_id = NULL;
}
GST_UNLOCK (identity);
if (cret == GST_CLOCK_UNSCHEDULED)
ret = GST_FLOW_UNEXPECTED;
}
}
identity->offset += GST_BUFFER_SIZE (*outbuf);
if (identity->sleep_time && ret == GST_FLOW_OK)
g_usleep (identity->sleep_time);
return ret;
}
@ -376,9 +381,6 @@ gst_identity_set_property (GObject * object, guint prop_id,
case PROP_SILENT:
identity->silent = g_value_get_boolean (value);
break;
case PROP_DUPLICATE:
identity->duplicate = g_value_get_uint (value);
break;
case PROP_DUMP:
identity->dump = g_value_get_boolean (value);
break;
@ -415,9 +417,6 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_SLEEP_TIME:
g_value_set_uint (value, identity->sleep_time);
break;
case PROP_DUPLICATE:
g_value_set_uint (value, identity->duplicate);
break;
case PROP_ERROR_AFTER:
g_value_set_int (value, identity->error_after);
break;

View file

@ -48,7 +48,7 @@ typedef struct _GstIdentityClass GstIdentityClass;
struct _GstIdentity {
GstBaseTransform element;
guint duplicate;
GstClockID clock_id;
gint error_after;
gfloat drop_probability;
gint datarate;

View file

@ -54,9 +54,7 @@ exec guile --debug -l $0 -e main -- "$@"
;; second argument, rather deferring that calculation until stream-cdr
;; is called. In that way all times are actually infinite series.
;;
;; Knobs: sample rate, send delay, receive delay, send noise, receive
;; noise, queue length, rate of remote clock, rate of local clock. See
;; network-clock.scm --help.
;; Usage: See network-clock.scm --help.
;;
;;; Code:

View file

@ -54,9 +54,7 @@ exec guile --debug -l $0 -e main -- "$@"
;; second argument, rather deferring that calculation until stream-cdr
;; is called. In that way all times are actually infinite series.
;;
;; Knobs: sample rate, send delay, receive delay, send noise, receive
;; noise, queue length, rate of remote clock, rate of local clock. See
;; network-clock.scm --help.
;; Usage: See network-clock.scm --help.
;;
;;; Code: