GST_STATIC_CAPS (CAPS)
);
-GST_BOILERPLATE (GstAdder, gst_adder, GstElement, GST_TYPE_ELEMENT);
+#define gst_adder_parent_class parent_class
+G_DEFINE_TYPE (GstAdder, gst_adder, GST_TYPE_ELEMENT);
static void gst_adder_dispose (GObject * object);
static void gst_adder_set_property (GObject * object, guint prop_id,
static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
static GstPad *gst_adder_request_new_pad (GstElement * element,
- GstPadTemplate * temp, const gchar * unused);
+ GstPadTemplate * temp, const gchar * unused, const GstCaps * caps);
static void gst_adder_release_pad (GstElement * element, GstPad * pad);
static GstStateChangeReturn gst_adder_change_state (GstElement * element,
* if we have filtercaps set, use those to constrain the target caps.
*/
static GstCaps *
-gst_adder_sink_getcaps (GstPad * pad)
+gst_adder_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstAdder *adder;
GstCaps *result, *peercaps, *sinkcaps, *filter_caps;
GST_OBJECT_LOCK (adder);
/* take filter */
- if ((filter_caps = adder->filter_caps))
- gst_caps_ref (filter_caps);
+ if ((filter_caps = adder->filter_caps)) {
+ if (filter)
+ filter_caps =
+ gst_caps_intersect_full (filter, filter_caps,
+ GST_CAPS_INTERSECT_FIRST);
+ else
+ gst_caps_ref (filter_caps);
+ } else {
+ filter_caps = gst_caps_ref (filter);
+ }
GST_OBJECT_UNLOCK (adder);
+ if (filter_caps && gst_caps_is_empty (filter_caps)) {
+ GST_WARNING_OBJECT (pad, "Empty filter caps");
+ return filter_caps;
+ }
+
/* get the downstream possible caps */
- peercaps = gst_pad_peer_get_caps (adder->srcpad);
+ peercaps = gst_pad_peer_get_caps (adder->srcpad, filter_caps);
+
+ /* get the allowed caps on this sinkpad */
+ sinkcaps = gst_pad_get_current_caps (pad);
+ if (sinkcaps == NULL) {
+ sinkcaps = gst_pad_get_pad_template_caps (pad);
+ if (!sinkcaps)
+ sinkcaps = gst_caps_new_any ();
+ }
- /* get the allowed caps on this sinkpad, we use the fixed caps function so
- * that it does not call recursively in this function. */
- sinkcaps = gst_pad_get_fixed_caps_func (pad);
if (peercaps) {
- /* restrict with filter-caps if any */
- if (filter_caps) {
- GST_DEBUG_OBJECT (adder, "filtering peer caps");
- result = gst_caps_intersect (peercaps, filter_caps);
- gst_caps_unref (peercaps);
- peercaps = result;
- }
/* if the peer has caps, intersect */
GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
- result = gst_caps_intersect (peercaps, sinkcaps);
+ result =
+ gst_caps_intersect_full (peercaps, sinkcaps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (peercaps);
gst_caps_unref (sinkcaps);
} else {
/* restrict with filter-caps if any */
if (filter_caps) {
GST_DEBUG_OBJECT (adder, "no peer caps, using filtered sinkcaps");
- result = gst_caps_intersect (sinkcaps, filter_caps);
+ result =
+ gst_caps_intersect_full (filter_caps, sinkcaps,
+ GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (sinkcaps);
} else {
GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
return result;
}
+typedef struct
+{
+ GstPad *pad;
+ GstCaps *caps;
+} IterData;
+
+static void
+setcapsfunc (const GValue * item, IterData * data)
+{
+ GstPad *otherpad = g_value_get_object (item);
+
+ if (otherpad != data->pad)
+ gst_pad_set_caps (data->pad, data->caps);
+}
+
/* the first caps we receive on any of the sinkpads will define the caps for all
* the other sinkpads because we can only mix streams with the same caps.
*/
gst_adder_setcaps (GstPad * pad, GstCaps * caps)
{
GstAdder *adder;
- GList *pads;
GstStructure *structure;
const char *media_type;
+ GstIterator *it;
+ GstIteratorResult ires;
+ IterData idata;
+ gboolean done;
adder = GST_ADDER (GST_PAD_PARENT (pad));
GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
GST_PAD_NAME (pad), caps);
+ it = gst_element_iterate_pads (GST_ELEMENT_CAST (adder));
+
/* FIXME, see if the other pads can accept the format. Also lock the
* format on the other pads to this new format. */
- GST_OBJECT_LOCK (adder);
- pads = GST_ELEMENT (adder)->pads;
- while (pads) {
- GstPad *otherpad = GST_PAD (pads->data);
+ idata.caps = caps;
+ idata.pad = pad;
+
+ done = FALSE;
+ while (!done) {
+ ires = gst_iterator_foreach (it, (GstIteratorForeachFunction) setcapsfunc,
+ &idata);
- if (otherpad != pad) {
- gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
+ switch (ires) {
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (it);
+ break;
+ default:
+ done = TRUE;
+ break;
}
- pads = g_list_next (pads);
}
- GST_OBJECT_UNLOCK (adder);
/* parse caps now */
structure = gst_caps_get_structure (caps, 0);
GstFormat format;
GstIterator *it;
gboolean done;
+ GValue item = { 0, };
/* parse format */
gst_query_parse_duration (query, &format, NULL);
while (!done) {
GstIteratorResult ires;
- gpointer item;
-
ires = gst_iterator_next (it, &item);
switch (ires) {
case GST_ITERATOR_DONE:
break;
case GST_ITERATOR_OK:
{
- GstPad *pad = GST_PAD_CAST (item);
-
+ GstPad *pad = g_value_get_object (&item);
gint64 duration;
/* ask sink peer for duration */
else if (duration > max)
max = duration;
}
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (it);
if (res) {
gboolean res;
GstIterator *it;
gboolean done;
+ GValue item = { 0, };
res = TRUE;
done = FALSE;
while (!done) {
GstIteratorResult ires;
- gpointer item;
-
ires = gst_iterator_next (it, &item);
switch (ires) {
case GST_ITERATOR_DONE:
break;
case GST_ITERATOR_OK:
{
- GstPad *pad = GST_PAD_CAST (item);
+ GstPad *pad = g_value_get_object (&item);
GstQuery *peerquery;
GstClockTime min_cur, max_cur;
gboolean live_cur;
}
gst_query_unref (peerquery);
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (it);
if (res) {
switch (format) {
case GST_FORMAT_TIME:
/* FIXME, bring to stream time, might be tricky */
- gst_query_set_position (query, format, adder->timestamp);
+ gst_query_set_position (query, format, adder->segment.position);
res = TRUE;
break;
case GST_FORMAT_DEFAULT:
} EventData;
static gboolean
-forward_event_func (GstPad * pad, GValue * ret, EventData * data)
+forward_event_func (const GValue * val, GValue * ret, EventData * data)
{
+ GstPad *pad = g_value_get_object (val);
GstEvent *event = data->event;
gst_event_ref (event);
GST_LOG_OBJECT (pad, "Sent event %p (%s).",
event, GST_EVENT_TYPE_NAME (event));
}
- gst_object_unref (pad);
/* continue on other pads, even if one failed */
return TRUE;
g_value_set_boolean (&vret, FALSE);
it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
while (TRUE) {
- ires = gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
+ ires =
+ gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
&vret, &data);
switch (ires) {
case GST_ITERATOR_RESYNC:
case GST_EVENT_SEEK:
{
GstSeekFlags flags;
+ gdouble rate;
GstSeekType curtype, endtype;
gint64 cur, end;
gboolean flush;
/* parse the seek parameters */
- gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
+ gst_event_parse_seek (event, &rate, NULL, &flags, &curtype,
&cur, &endtype, &end);
if ((curtype != GST_SEEK_TYPE_NONE) && (curtype != GST_SEEK_TYPE_SET)) {
* segment. After we have the lock, no collect function is running and no
* new collect function will be called for as long as we're flushing. */
GST_OBJECT_LOCK (adder->collect);
+ adder->segment.rate = rate;
if (curtype == GST_SEEK_TYPE_SET)
- adder->segment_start = cur;
+ adder->segment.start = cur;
else
- adder->segment_start = 0;
+ adder->segment.start = 0;
if (endtype == GST_SEEK_TYPE_SET)
- adder->segment_end = end;
+ adder->segment.stop = end;
else
- adder->segment_end = GST_CLOCK_TIME_NONE;
+ adder->segment.stop = GST_CLOCK_TIME_NONE;
/* make sure we push a new segment, to inform about new basetime
* see FIXME in gst_adder_collected() */
adder->segment_pending = TRUE;
}
static void
-gst_adder_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_adder_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_adder_sink_template));
- gst_element_class_set_details_simple (gstelement_class, "Adder",
- "Generic/Audio",
- "Add N audio channels together",
- "Thomas Vander Stichele <thomas at apestaart dot org>");
-}
-
-static void
gst_adder_class_init (GstAdderClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
"object.", GST_TYPE_CAPS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_adder_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_adder_sink_template));
+ gst_element_class_set_details_simple (gstelement_class, "Adder",
+ "Generic/Audio",
+ "Add N audio channels together",
+ "Thomas Vander Stichele <thomas at apestaart dot org>");
+
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_adder_request_new_pad);
gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_adder_release_pad);
}
static void
-gst_adder_init (GstAdder * adder, GstAdderClass * klass)
+gst_adder_init (GstAdder * adder)
{
GstPadTemplate *template;
static GstPad *
gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
- const gchar * unused)
+ const gchar * unused, const GstCaps * caps)
{
gchar *name;
GstAdder *adder;
adder = GST_ADDER (element);
/* increment pad counter */
+#if GLIB_CHECK_VERSION(2,29,5)
+ padcount = g_atomic_int_add (&adder->padcount, 1);
+#else
padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
+#endif
name = g_strdup_printf ("sink%d", padcount);
newpad = gst_pad_new_from_template (templ, name);
GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
- if (adder->collect) {
- gst_collect_pads_remove_pad (adder->collect, pad);
- }
+ gst_collect_pads_remove_pad (adder->collect, pad);
gst_element_remove_pad (element, pad);
}
GST_LOG_OBJECT (adder, "channel %p: preparing output buffer of %d bytes",
collect_data, outsize);
- /* make data and metadata writable, can simply return the inbuf when we
- * are the only one referencing this buffer. If this is the last (and
- * only) GAP buffer, it will automatically copy the GAP flag. */
- outbuf = gst_buffer_make_writable (inbuf);
- outdata = GST_BUFFER_DATA (outbuf);
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
+
+ outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
} else {
if (!is_gap) {
/* we had a previous output buffer, mix this non-GAP buffer */
guint8 *indata;
- guint insize;
+ gsize insize;
- indata = GST_BUFFER_DATA (inbuf);
- insize = GST_BUFFER_SIZE (inbuf);
+ indata = gst_buffer_map (inbuf, &insize, NULL, GST_MAP_READ);
/* all buffers should have outsize, there are no short buffers because we
* asked for the max size above */
/* further buffers, need to add them */
adder->func ((gpointer) outdata, (gpointer) indata,
insize / adder->sample_size);
+ gst_buffer_unmap (inbuf, indata, insize);
} else {
/* skip gap buffer */
GST_LOG_OBJECT (adder, "channel %p: skipping GAP buffer", collect_data);
gst_buffer_unref (inbuf);
}
}
+ if (outbuf)
+ gst_buffer_unmap (outbuf, outdata, outsize);
if (outbuf == NULL) {
/* no output buffer, reuse one of the GAP buffers then if we have one */
* event. We also adjust offset & timestamp acordingly.
* This basically ignores all newsegments sent by upstream.
*/
- event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
- 1.0, GST_FORMAT_TIME, adder->segment_start, adder->segment_end,
- adder->segment_start);
- if (adder->segment_rate > 0.0) {
- adder->timestamp = adder->segment_start;
+ event = gst_event_new_segment (&adder->segment);
+
+ if (adder->segment.rate > 0.0) {
+ adder->segment.position = adder->segment.start;
} else {
- adder->timestamp = adder->segment_end;
+ adder->segment.position = adder->segment.stop;
}
- adder->offset = gst_util_uint64_scale (adder->timestamp,
+ adder->offset = gst_util_uint64_scale (adder->segment.position,
adder->rate, GST_SECOND);
GST_INFO_OBJECT (adder, "seg_start %" G_GUINT64_FORMAT ", seg_end %"
- G_GUINT64_FORMAT, adder->segment_start, adder->segment_end);
+ G_GUINT64_FORMAT, adder->segment.start, adder->segment.stop);
GST_INFO_OBJECT (adder, "timestamp %" G_GINT64_FORMAT ",new offset %"
- G_GINT64_FORMAT, adder->timestamp, adder->offset);
+ G_GINT64_FORMAT, adder->segment.position, adder->offset);
if (event) {
if (!gst_pad_push_event (adder->srcpad, event)) {
} else {
GST_WARNING_OBJECT (adder->srcpad, "Creating new segment event for "
"start:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT " failed",
- adder->segment_start, adder->segment_end);
+ adder->segment.start, adder->segment.stop);
}
}
/* for the next timestamp, use the sample counter, which will
* never accumulate rounding errors */
- if (adder->segment_rate > 0.0) {
+ if (adder->segment.rate > 0.0) {
next_offset = adder->offset + outsize / adder->bps;
} else {
next_offset = adder->offset - outsize / adder->bps;
/* set timestamps on the output buffer */
- if (adder->segment_rate > 0.0) {
- GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
+ if (adder->segment.rate > 0.0) {
+ GST_BUFFER_TIMESTAMP (outbuf) = adder->segment.position;
GST_BUFFER_OFFSET (outbuf) = adder->offset;
- GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->timestamp;
+ GST_BUFFER_OFFSET_END (outbuf) = next_offset;
+ GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->segment.position;
} else {
GST_BUFFER_TIMESTAMP (outbuf) = next_timestamp;
GST_BUFFER_OFFSET (outbuf) = next_offset;
- GST_BUFFER_DURATION (outbuf) = adder->timestamp - next_timestamp;
+ GST_BUFFER_OFFSET_END (outbuf) = adder->offset;
+ GST_BUFFER_DURATION (outbuf) = adder->segment.position - next_timestamp;
}
adder->offset = next_offset;
- adder->timestamp = next_timestamp;
+ adder->segment.position = next_timestamp;
/* send it out */
GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
- adder->timestamp = 0;
+ adder->segment.position = 0;
adder->offset = 0;
adder->flush_stop_pending = FALSE;
adder->segment_pending = TRUE;
- adder->segment_start = 0;
- adder->segment_end = GST_CLOCK_TIME_NONE;
- adder->segment_rate = 1.0;
- gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
+ gst_segment_init (&adder->segment, GST_FORMAT_TIME);
gst_collect_pads_start (adder->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING: