+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):
</para>
@parent_class:
+@transform_caps:
@set_caps:
@start:
@stop:
@queryfunc:
@intlinkfunc:
@bufferallocfunc:
-@emit_buffer_signals:
-@emit_event_signals:
+@do_buffer_signals:
+@do_event_signals:
<!-- ##### SIGNAL GstPad::have-data ##### -->
<para>
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 }; */
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,
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,
}
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
if (bclass->transform)
ret = bclass->transform (trans, inbuf, outbuf);
- gst_buffer_unref (inbuf);
-
return ret;
}
/*< 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);
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);
{
PROP_0,
PROP_SLEEP_TIME,
- PROP_DUPLICATE,
PROP_ERROR_AFTER,
PROP_DROP_PROBABILITY,
PROP_DATARATE,
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));
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;
{
GstFlowReturn ret = GST_FLOW_OK;
GstIdentity *identity = GST_IDENTITY (trans);
- guint i;
if (identity->check_perfect)
gst_identity_check_perfect (identity, 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;
}
}
GST_BUFFER_FLAGS (inbuf), inbuf);
GST_UNLOCK (identity);
g_object_notify (G_OBJECT (identity), "last-message");
+ gst_buffer_unref (inbuf);
return GST_FLOW_OK;
}
}
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");
+ }
- 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 */
- time = GST_BUFFER_TIMESTAMP (inbuf);
+ if (identity->datarate > 0) {
+ GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
- if (identity->datarate > 0) {
- 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 (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,
+ *outbuf);
- g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
- inbuf);
+ if (identity->sync) {
+ GstClock *clock;
+ GstClockReturn cret;
- if (i > 1)
- gst_buffer_ref (inbuf);
+ clock = GST_ELEMENT (identity)->clock;
- if (identity->sync) {
- if (GST_ELEMENT (identity)->clock) {
- /* gst_element_wait (GST_ELEMENT (identity), time); */
+ 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 (inbuf);
+ identity->offset += GST_BUFFER_SIZE (*outbuf);
- if (identity->sleep_time)
- g_usleep (identity->sleep_time);
-
- gst_buffer_ref (inbuf);
- *outbuf = inbuf;
- }
+ if (identity->sleep_time && ret == GST_FLOW_OK)
+ g_usleep (identity->sleep_time);
return ret;
}
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;
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;
struct _GstIdentity {
GstBaseTransform element;
- guint duplicate;
+ GstClockID clock_id;
gint error_after;
gfloat drop_probability;
gint datarate;
*
* 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;
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,
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
* 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;
}
/**
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)) {
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);
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 */
/* 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);
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 }; */
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,
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,
}
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
if (bclass->transform)
ret = bclass->transform (trans, inbuf, outbuf);
- gst_buffer_unref (inbuf);
-
return ret;
}
/*< 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);
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);
{
PROP_0,
PROP_SLEEP_TIME,
- PROP_DUPLICATE,
PROP_ERROR_AFTER,
PROP_DROP_PROBABILITY,
PROP_DATARATE,
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));
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;
{
GstFlowReturn ret = GST_FLOW_OK;
GstIdentity *identity = GST_IDENTITY (trans);
- guint i;
if (identity->check_perfect)
gst_identity_check_perfect (identity, 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;
}
}
GST_BUFFER_FLAGS (inbuf), inbuf);
GST_UNLOCK (identity);
g_object_notify (G_OBJECT (identity), "last-message");
+ gst_buffer_unref (inbuf);
return GST_FLOW_OK;
}
}
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");
+ }
- 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 */
- time = GST_BUFFER_TIMESTAMP (inbuf);
+ if (identity->datarate > 0) {
+ GstClockTime time = identity->offset * GST_SECOND / identity->datarate;
- if (identity->datarate > 0) {
- 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 (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,
+ *outbuf);
- g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
- inbuf);
+ if (identity->sync) {
+ GstClock *clock;
+ GstClockReturn cret;
- if (i > 1)
- gst_buffer_ref (inbuf);
+ clock = GST_ELEMENT (identity)->clock;
- if (identity->sync) {
- if (GST_ELEMENT (identity)->clock) {
- /* gst_element_wait (GST_ELEMENT (identity), time); */
+ 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 (inbuf);
+ identity->offset += GST_BUFFER_SIZE (*outbuf);
- if (identity->sleep_time)
- g_usleep (identity->sleep_time);
-
- gst_buffer_ref (inbuf);
- *outbuf = inbuf;
- }
+ if (identity->sleep_time && ret == GST_FLOW_OK)
+ g_usleep (identity->sleep_time);
return ret;
}
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;
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;
struct _GstIdentity {
GstBaseTransform element;
- guint duplicate;
+ GstClockID clock_id;
gint error_after;
gfloat drop_probability;
gint datarate;
;; 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:
;; 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: