#include "config.h"
#endif
-/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
#include "gstadder.h"
#include <gst/audio/audio.h>
#include <string.h> /* strcmp */
/* elementfactory information */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CAPS \
+ GST_AUDIO_CAPS_MAKE ("{ S32LE, U32LE, S16LE, U16LE, S8, U8, F32LE, F64LE }") \
+ ", layout = (string) { interleaved, non-interleaved }"
+#else
#define CAPS \
- "audio/x-raw-int, " \
- "rate = (int) [ 1, MAX ], " \
- "channels = (int) [ 1, MAX ], " \
- "endianness = (int) BYTE_ORDER, " \
- "width = (int) 32, " \
- "depth = (int) 32, " \
- "signed = (boolean) { true, false } ;" \
- "audio/x-raw-int, " \
- "rate = (int) [ 1, MAX ], " \
- "channels = (int) [ 1, MAX ], " \
- "endianness = (int) BYTE_ORDER, " \
- "width = (int) 16, " \
- "depth = (int) 16, " \
- "signed = (boolean) { true, false } ;" \
- "audio/x-raw-int, " \
- "rate = (int) [ 1, MAX ], " \
- "channels = (int) [ 1, MAX ], " \
- "endianness = (int) BYTE_ORDER, " \
- "width = (int) 8, " \
- "depth = (int) 8, " \
- "signed = (boolean) { true, false } ;" \
- "audio/x-raw-float, " \
- "rate = (int) [ 1, MAX ], " \
- "channels = (int) [ 1, MAX ], " \
- "endianness = (int) BYTE_ORDER, " \
- "width = (int) { 32, 64 }"
+ GST_AUDIO_CAPS_MAKE ("{ S32BE, U32BE, S16BE, U16BE, S8, U8, F32BE, F64BE }") \
+ ", layout = (string) { interleaved, non-interleaved }"
+#endif
static GstStaticPadTemplate gst_adder_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
);
static GstStaticPadTemplate gst_adder_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink%d",
+GST_STATIC_PAD_TEMPLATE ("sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
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 void gst_adder_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
-static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_adder_setcaps (GstAdder * adder, GstPad * pad,
+ GstCaps * caps);
+static gboolean gst_adder_src_query (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+static gboolean gst_adder_sink_query (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+static gboolean gst_adder_src_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
static gboolean gst_adder_sink_event (GstCollectPads2 * pads,
GstCollectData2 * pad, GstEvent * event, gpointer user_data);
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 = filter ? gst_caps_ref (filter) : NULL;
+ }
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_query_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;
}
+static gboolean
+gst_adder_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+ gboolean res = FALSE;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CAPS:
+ {
+ GstCaps *filter, *caps;
+
+ gst_query_parse_caps (query, &filter);
+ caps = gst_adder_sink_getcaps (pad, filter);
+ gst_query_set_caps_result (query, caps);
+ gst_caps_unref (caps);
+ res = TRUE;
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, parent, query);
+ break;
+ }
+ return res;
+}
+
+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.
*/
static gboolean
-gst_adder_setcaps (GstPad * pad, GstCaps * caps)
+gst_adder_setcaps (GstAdder * adder, 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));
+ /* this get called recursively due to gst_iterator_foreach calling
+ * gst_pad_set_caps() */
+ if (adder->in_setcaps)
+ return TRUE;
- GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
+ GST_LOG_OBJECT (adder, "setting caps 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;
- if (otherpad != pad) {
- gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
- }
- pads = g_list_next (pads);
- }
- GST_OBJECT_UNLOCK (adder);
+ adder->in_setcaps = TRUE;
+ done = FALSE;
+ while (!done) {
+ ires = gst_iterator_foreach (it, (GstIteratorForeachFunction) setcapsfunc,
+ &idata);
- /* parse caps now */
- structure = gst_caps_get_structure (caps, 0);
- media_type = gst_structure_get_name (structure);
- if (strcmp (media_type, "audio/x-raw-int") == 0) {
- adder->format = GST_ADDER_FORMAT_INT;
- gst_structure_get_int (structure, "width", &adder->width);
- gst_structure_get_int (structure, "depth", &adder->depth);
- gst_structure_get_int (structure, "endianness", &adder->endianness);
- gst_structure_get_boolean (structure, "signed", &adder->is_signed);
-
- GST_INFO_OBJECT (pad, "parse_caps sets adder to format int, %d bit",
- adder->width);
-
- if (adder->endianness != G_BYTE_ORDER)
- goto not_supported;
-
- switch (adder->width) {
- case 8:
- adder->func = (adder->is_signed ?
- (GstAdderFunction) add_int8 : (GstAdderFunction) add_uint8);
- adder->sample_size = 1;
- break;
- case 16:
- adder->func = (adder->is_signed ?
- (GstAdderFunction) add_int16 : (GstAdderFunction) add_uint16);
- adder->sample_size = 2;
- break;
- case 32:
- adder->func = (adder->is_signed ?
- (GstAdderFunction) add_int32 : (GstAdderFunction) add_uint32);
- adder->sample_size = 4;
+ switch (ires) {
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (it);
break;
default:
- goto not_supported;
- }
- } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
- adder->format = GST_ADDER_FORMAT_FLOAT;
- gst_structure_get_int (structure, "width", &adder->width);
- gst_structure_get_int (structure, "endianness", &adder->endianness);
-
- GST_INFO_OBJECT (pad, "parse_caps sets adder to format float, %d bit",
- adder->width);
-
- if (adder->endianness != G_BYTE_ORDER)
- goto not_supported;
-
- switch (adder->width) {
- case 32:
- adder->func = (GstAdderFunction) add_float32;
- adder->sample_size = 4;
- break;
- case 64:
- adder->func = (GstAdderFunction) add_float64;
- adder->sample_size = 8;
+ done = TRUE;
break;
- default:
- goto not_supported;
}
- } else {
- goto not_supported;
}
+ adder->in_setcaps = FALSE;
+
+ GST_LOG_OBJECT (adder, "handle caps changes on pad %p,%s to %" GST_PTR_FORMAT,
+ pad, GST_PAD_NAME (pad), caps);
- gst_structure_get_int (structure, "channels", &adder->channels);
- gst_structure_get_int (structure, "rate", &adder->rate);
- /* precalc bps */
- adder->bps = (adder->width / 8) * adder->channels;
+ if (!gst_audio_info_from_caps (&adder->info, caps))
+ goto invalid_format;
+ switch (GST_AUDIO_INFO_FORMAT (&adder->info)) {
+ case GST_AUDIO_FORMAT_S8:
+ adder->func = (GstAdderFunction) add_int8;
+ break;
+ case GST_AUDIO_FORMAT_U8:
+ adder->func = (GstAdderFunction) add_uint8;
+ break;
+ case GST_AUDIO_FORMAT_S16:
+ adder->func = (GstAdderFunction) add_int16;
+ break;
+ case GST_AUDIO_FORMAT_U16:
+ adder->func = (GstAdderFunction) add_uint16;
+ break;
+ case GST_AUDIO_FORMAT_S32:
+ adder->func = (GstAdderFunction) add_int32;
+ break;
+ case GST_AUDIO_FORMAT_U32:
+ adder->func = (GstAdderFunction) add_uint32;
+ break;
+ case GST_AUDIO_FORMAT_F32:
+ adder->func = (GstAdderFunction) add_float32;
+ break;
+ case GST_AUDIO_FORMAT_F64:
+ adder->func = (GstAdderFunction) add_float64;
+ break;
+ default:
+ goto invalid_format;
+ }
return TRUE;
/* ERRORS */
-not_supported:
+invalid_format:
{
- GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
+ GST_DEBUG_OBJECT (adder, "invalid format set as caps");
return FALSE;
}
}
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 */
- res &= gst_pad_query_peer_duration (pad, &format, &duration);
+ res &= gst_pad_peer_query_duration (pad, format, &duration);
/* take max from all valid return values */
if (res) {
/* valid unknown length, stop searching */
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) {
}
static gboolean
-gst_adder_query (GstPad * pad, GstQuery * query)
+gst_adder_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
- GstAdder *adder = GST_ADDER (gst_pad_get_parent (pad));
+ GstAdder *adder = GST_ADDER (parent);
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
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:
default:
/* FIXME, needs a custom query handler because we have multiple
* sinkpads */
- res = gst_pad_query_default (pad, query);
+ res = gst_pad_query_default (pad, parent, query);
break;
}
- gst_object_unref (adder);
return res;
}
} 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);
/* quick hack to unflush the pads, ideally we need a way to just unflush
* this single collect pad */
if (data->flush)
- gst_pad_send_event (pad, gst_event_new_flush_stop ());
+ gst_pad_send_event (pad, gst_event_new_flush_stop (TRUE));
} else {
g_value_set_boolean (ret, TRUE);
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:
}
static gboolean
-gst_adder_src_event (GstPad * pad, GstEvent * event)
+gst_adder_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstAdder *adder;
gboolean result;
- adder = GST_ADDER (gst_pad_get_parent (pad));
+ adder = GST_ADDER (parent);
- GST_DEBUG_OBJECT (pad, "Got %s event on src pad from %s",
- GST_EVENT_TYPE_NAME (event), GST_OBJECT_NAME (GST_EVENT_SRC (event)));
+ GST_DEBUG_OBJECT (pad, "Got %s event on src pad",
+ GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
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_COLLECT_PADS2_STREAM_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;
if (flush) {
/* Yes, we need to call _set_flushing again *WHEN* the streaming threads
* have stopped so that the cookie gets properly updated. */
if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
TRUE, FALSE)) {
GST_DEBUG_OBJECT (adder, "pending flush stop");
- gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop ());
+ gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop (TRUE));
}
break;
}
}
done:
- gst_object_unref (adder);
return result;
}
GstAdder *adder = GST_ADDER (user_data);
gboolean res = FALSE;
- GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad from %s",
- GST_EVENT_TYPE_NAME (event), GST_OBJECT_NAME (GST_EVENT_SRC (event)));
+ GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad",
+ GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- /* drop flush start events, as we forwarded one already when handing the
- * flushing seek on the sink pad */
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ res = gst_adder_setcaps (adder, pad->pad, caps);
gst_event_unref (event);
- res = TRUE;
+
+ break;
+ }
+ case GST_EVENT_FLUSH_START:
+ res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event);
break;
case GST_EVENT_FLUSH_STOP:
/* we received a flush-stop. We will only forward it when
g_list_free (adder->pending_events);
adder->pending_events = NULL;
}
+ res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event);
break;
case GST_EVENT_TAG:
/* collect tags here so we can push them out when we collect data */
adder->pending_events = g_list_append (adder->pending_events, event);
res = TRUE;
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
if (g_atomic_int_compare_and_exchange (&adder->wait_for_new_segment,
TRUE, FALSE)) {
/* make sure we push a new segment, to inform about new basetime
gst_event_unref (event);
res = TRUE;
break;
+ case GST_EVENT_EOS:
+ gst_event_unref (event);
+ res = TRUE;
+ break;
default:
+ res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event);
break;
}
- return res;
-}
-
-static void
-gst_adder_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
- gst_element_class_add_static_pad_template (gstelement_class,
- &gst_adder_src_template);
- gst_element_class_add_static_pad_template (gstelement_class,
- &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>");
+ return res;
}
static void
"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;
adder->srcpad = gst_pad_new_from_template (template, "src");
gst_object_unref (template);
- gst_pad_set_getcaps_function (adder->srcpad,
- GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
- gst_pad_set_setcaps_function (adder->srcpad,
- GST_DEBUG_FUNCPTR (gst_adder_setcaps));
gst_pad_set_query_function (adder->srcpad,
- GST_DEBUG_FUNCPTR (gst_adder_query));
+ GST_DEBUG_FUNCPTR (gst_adder_src_query));
gst_pad_set_event_function (adder->srcpad,
GST_DEBUG_FUNCPTR (gst_adder_src_event));
+ GST_PAD_SET_PROXY_CAPS (adder->srcpad);
gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
- adder->format = GST_ADDER_FORMAT_UNSET;
+ gst_audio_info_init (&adder->info);
adder->padcount = 0;
adder->func = NULL;
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);
+ name = g_strdup_printf ("sink_%u", padcount);
newpad = gst_pad_new_from_template (templ, name);
GST_DEBUG_OBJECT (adder, "request new pad %s", name);
g_free (name);
- gst_pad_set_getcaps_function (newpad,
- GST_DEBUG_FUNCPTR (gst_adder_sink_getcaps));
- gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_setcaps));
+ gst_pad_set_query_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_query));
gst_collect_pads2_add_pad (adder->collect, newpad, sizeof (GstCollectData2));
/* takes ownership of the pad */
GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
- gst_collect_pads2_remove_pad (adder->collect, pad);
+ if (adder->collect)
+ gst_collect_pads2_remove_pad (adder->collect, pad);
gst_element_remove_pad (element, pad);
}
GstBuffer * buffer, GstBuffer ** out, gpointer user_data)
{
GstAdder *adder = GST_ADDER (user_data);
+ gint rate, bpf;
- /* in 0.10 the application might need to seek on newly added source-branches
- * to make it send a newsegment, that is hard to sync and so the segment might
- * not be initialized. Check this here to not trigger the assertion
- */
- if (data->segment.format != GST_FORMAT_UNDEFINED) {
- buffer = gst_audio_buffer_clip (buffer, &data->segment, adder->rate,
- adder->bps);
- }
+ rate = GST_AUDIO_INFO_RATE (&adder->info);
+ bpf = GST_AUDIO_INFO_BPF (&adder->info);
+
+ buffer = gst_audio_buffer_clip (buffer, &data->segment, rate, bpf);
*out = buffer;
return GST_FLOW_OK;
GSList *collected, *next = NULL;
GstFlowReturn ret;
GstBuffer *outbuf = NULL, *gapbuf = NULL;
- gpointer outdata = NULL;
+ GstMapInfo outmap = { NULL };
guint outsize;
gint64 next_offset;
gint64 next_timestamp;
+ gint rate, bps, bpf;
adder = GST_ADDER (user_data);
if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
TRUE, FALSE)) {
GST_DEBUG_OBJECT (adder, "pending flush stop");
- gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop ());
+ gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop (TRUE));
}
/* get available bytes for reading, this can be 0 which could mean empty
if (outsize == 0)
goto eos;
+ rate = GST_AUDIO_INFO_RATE (&adder->info);
+ bps = GST_AUDIO_INFO_BPS (&adder->info);
+ bpf = GST_AUDIO_INFO_BPF (&adder->info);
+
GST_LOG_OBJECT (adder,
- "starting to cycle through channels, %d bytes available (bps = %d)",
- outsize, adder->bps);
+ "starting to cycle through channels, %d bytes available (bps = %d, bpf = %d)",
+ outsize, bps, bpf);
for (collected = pads->data; collected; collected = next) {
GstCollectData2 *collect_data;
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));
+ gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
} else {
if (!is_gap) {
/* we had a previous output buffer, mix this non-GAP buffer */
- guint8 *indata;
- guint insize;
+ GstMapInfo inmap;
- indata = GST_BUFFER_DATA (inbuf);
- insize = GST_BUFFER_SIZE (inbuf);
+ gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
/* all buffers should have outsize, there are no short buffers because we
* asked for the max size above */
- g_assert (insize == outsize);
+ g_assert (inmap.size == outmap.size);
- GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
- collect_data, insize, indata);
+ GST_LOG_OBJECT (adder, "channel %p: mixing %" G_GSIZE_FORMAT " bytes"
+ " from data %p", collect_data, inmap.size, inmap.data);
/* further buffers, need to add them */
- adder->func ((gpointer) outdata, (gpointer) indata,
- insize / adder->sample_size);
+ adder->func ((gpointer) outmap.data, (gpointer) inmap.data,
+ inmap.size / bps);
+ gst_buffer_unmap (inbuf, &inmap);
} 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, &outmap);
if (outbuf == NULL) {
/* no output buffer, reuse one of the GAP buffers then if we have one */
* event. We also adjust offset & timestamp accordingly.
* 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->rate, GST_SECOND);
+ adder->offset = gst_util_uint64_scale (adder->segment.position,
+ 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) {
- next_offset = adder->offset + outsize / adder->bps;
+ if (adder->segment.rate > 0.0) {
+ next_offset = adder->offset + outsize / bpf;
} else {
- next_offset = adder->offset - outsize / adder->bps;
+ next_offset = adder->offset - outsize / bpf;
}
- next_timestamp = gst_util_uint64_scale (next_offset, GST_SECOND, adder->rate);
+ next_timestamp = gst_util_uint64_scale (next_offset, GST_SECOND, rate);
/* 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_OFFSET_END (outbuf) = next_offset;
- GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->timestamp;
+ GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->segment.position;
} else {
GST_BUFFER_TIMESTAMP (outbuf) = next_timestamp;
GST_BUFFER_OFFSET (outbuf) = next_offset;
GST_BUFFER_OFFSET_END (outbuf) = adder->offset;
- GST_BUFFER_DURATION (outbuf) = adder->timestamp - next_timestamp;
+ 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
{
GST_DEBUG_OBJECT (adder, "no data available, must be EOS");
gst_pad_push_event (adder->srcpad, gst_event_new_eos ());
- return GST_FLOW_UNEXPECTED;
+ return GST_FLOW_EOS;
}
}
-
static GstStateChangeReturn
gst_adder_change_state (GstElement * element, GstStateChange transition)
{
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->new_segment_pending = TRUE;
adder->wait_for_new_segment = FALSE;
- 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_pads2_start (adder->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING: