Commit 45604245 authored by Wim Taymans's avatar Wim Taymans

- Fix endless loop in adder

Original commit message from CVS:
- Fix endless loop in adder
- return from interrupt events.
parent a183da9c
......@@ -79,6 +79,8 @@ static void gst_adder_get_property (GObject *object, guint prop_id,
static GstPad* gst_adder_request_new_pad (GstElement *element, GstPadTemplate *temp,
const gchar *unused);
static GstElementStateReturn
gst_adder_change_state (GstElement *element);
/* we do need a loop function */
static void gst_adder_loop (GstElement *element);
......@@ -135,7 +137,7 @@ gst_adder_parse_caps (GstAdder *adder, GstCaps *caps)
gst_caps_get_int (caps, "rate", &adder->rate);
}
} else {
/* otherwise, a previously-connected pad has set all the values. we should
/* otherwise, a previously-linked pad has set all the values. we should
barf if some of the attempted new values don't match. */
if (strcmp (format, "int") == 0) {
gint width, channels, rate;
......@@ -146,30 +148,30 @@ gst_adder_parse_caps (GstAdder *adder, GstCaps *caps)
gst_caps_get_boolean (caps, "signed", &is_signed);
gst_caps_get_int (caps, "rate", &rate);
/* provide an error message if we can't connect */
/* provide an error message if we can't link */
if (adder->format != GST_ADDER_FORMAT_INT) {
gst_element_error (el, "can't connect a non-int pad to an int adder");
gst_element_error (el, "can't link a non-int pad to an int adder");
return FALSE;
}
if (adder->channels != channels) {
gst_element_error (el,
"can't connect %d-channel pad with %d-channel adder",
"can't link %d-channel pad with %d-channel adder",
channels, adder->channels);
return FALSE;
}
if (adder->rate != rate) {
gst_element_error (el, "can't connect %d Hz pad with %d Hz adder",
gst_element_error (el, "can't link %d Hz pad with %d Hz adder",
rate, adder->rate);
return FALSE;
}
if (adder->width != width) {
gst_element_error (el, "can't connect %d-bit pad with %d-bit adder",
gst_element_error (el, "can't link %d-bit pad with %d-bit adder",
width, adder->width);
return FALSE;
}
if (adder->is_signed != is_signed) {
gst_element_error (el,
"can't connect %ssigned pad with %ssigned adder",
"can't link %ssigned pad with %ssigned adder",
adder->is_signed ? "" : "un",
is_signed ? "" : "un");
return FALSE;
......@@ -182,21 +184,21 @@ gst_adder_parse_caps (GstAdder *adder, GstCaps *caps)
if (adder->format != GST_ADDER_FORMAT_FLOAT) {
gst_element_error (el,
"can't connect a non-float pad to a float adder");
"can't link a non-float pad to a float adder");
return FALSE;
}
if (adder->channels != channels) {
gst_element_error (el,
"can't connect %d-channel pad with %d-channel adder",
"can't link %d-channel pad with %d-channel adder",
channels, adder->channels);
return FALSE;
}
if (adder->rate != rate) {
gst_element_error (el, "can't connect %d Hz pad with %d Hz adder",
gst_element_error (el, "can't link %d Hz pad with %d Hz adder",
rate, adder->rate);
return FALSE;
} else {
/* whoa, we don't know what's trying to connect with us ! barf ! */
/* whoa, we don't know what's trying to link with us ! barf ! */
return FALSE;
}
}
......@@ -205,7 +207,7 @@ gst_adder_parse_caps (GstAdder *adder, GstCaps *caps)
}
static GstPadLinkReturn
gst_adder_connect (GstPad *pad, GstCaps *caps)
gst_adder_link (GstPad *pad, GstCaps *caps)
{
GstAdder *adder;
const GList *sinkpads;
......@@ -285,6 +287,7 @@ gst_adder_class_init (GstAdderClass *klass)
gobject_class->get_property = gst_adder_get_property;
gstelement_class->request_new_pad = gst_adder_request_new_pad;
gstelement_class->change_state = gst_adder_change_state;
}
static void
......@@ -294,12 +297,13 @@ gst_adder_init (GstAdder *adder)
"src");
gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
gst_element_set_loop_function (GST_ELEMENT (adder), gst_adder_loop);
gst_pad_set_link_function (adder->srcpad, gst_adder_connect);
gst_pad_set_link_function (adder->srcpad, gst_adder_link);
adder->format = GST_ADDER_FORMAT_UNSET;
/* keep track of the sinkpads requested */
adder->bufpool = NULL;
adder->numsinkpads = 0;
adder->input_channels = NULL;
}
......@@ -336,7 +340,7 @@ gst_adder_request_new_pad (GstElement *element, GstPadTemplate *templ,
input->bytestream = gst_bytestream_new (input->sinkpad);
gst_element_add_pad (GST_ELEMENT (adder), input->sinkpad);
gst_pad_set_link_function(input->sinkpad, gst_adder_connect);
gst_pad_set_link_function(input->sinkpad, gst_adder_link);
/* add the input_channel to the list of input channels */
......@@ -380,172 +384,211 @@ gst_adder_loop (GstElement *element)
* - otherwise add the gotten bytes to the output buffer
* - push out the output buffer
*/
GstAdder *adder;
GstBuffer *buf_out;
GstEvent *event = NULL;
GSList *inputs;
GstAdderInputChannel *input;
GSList *inputs;
guint8 *raw_in;
guint32 waiting;
guint32 got_bytes;
gint64 timestamp = 0;
gint64 offset = 0;
register guint i;
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_ADDER (element));
adder = GST_ADDER (element);
adder->bufpool = gst_pad_get_bufferpool (adder->srcpad);
if (adder->bufpool == NULL) {
adder->bufpool = gst_buffer_pool_get_default (GST_ADDER_BUFFER_SIZE,
GST_ADDER_NUM_BUFFERS);
adder->bufpool = gst_pad_get_bufferpool (adder->srcpad);
if (adder->bufpool == NULL) {
adder->bufpool = gst_buffer_pool_get_default (GST_ADDER_BUFFER_SIZE,
GST_ADDER_NUM_BUFFERS);
}
}
do {
/* get new output buffer */
buf_out = gst_buffer_new_from_pool (adder->bufpool, 0, 0);
/* get new output buffer */
buf_out = gst_buffer_new_from_pool (adder->bufpool, 0, 0);
if (buf_out == NULL)
gst_element_error (GST_ELEMENT (adder),
if (buf_out == NULL) {
gst_element_error (GST_ELEMENT (adder),
"could not get new output buffer !\n");
return;
}
/* initialize the output data to 0 */
memset (GST_BUFFER_DATA (buf_out), 0, GST_BUFFER_SIZE (buf_out));
/* initialize the output data to 0 */
memset (GST_BUFFER_DATA (buf_out), 0, GST_BUFFER_SIZE (buf_out));
/* get data from all of the sinks */
inputs = adder->input_channels;
/* get data from all of the sinks */
inputs = adder->input_channels;
GST_DEBUG (GST_CAT_PLUGIN_INFO, "starting to cycle through channels");
GST_DEBUG (GST_CAT_PLUGIN_INFO, "starting to cycle through channels");
while (inputs) {
guint32 got_bytes;
guint8 *raw_in;
GstAdderInputChannel *input;
while (inputs) {
input = (GstAdderInputChannel *) inputs->data;
input = (GstAdderInputChannel *) inputs->data;
GST_DEBUG (GST_CAT_PLUGIN_INFO, "looking into channel %p", input);
inputs = inputs->next;
GST_DEBUG (GST_CAT_PLUGIN_INFO, "looking into channel %p", input);
if (!GST_PAD_IS_USABLE (input->sinkpad)) {
GST_DEBUG (GST_CAT_PLUGIN_INFO, "adder ignoring pad %s:%s",
GST_DEBUG_PAD_NAME (input->sinkpad));
inputs = inputs->next;
continue;
}
if (!GST_PAD_IS_USABLE (input->sinkpad)) {
GST_DEBUG (GST_CAT_PLUGIN_INFO, "adder ignoring pad %s:%s",
GST_DEBUG_PAD_NAME (input->sinkpad));
continue;
}
/* Get data from the bytestream of each input channel.
* We need to check for events before passing on the data
* to the output buffer. */
got_bytes = gst_bytestream_peek_bytes (input->bytestream, &raw_in,
/* Get data from the bytestream of each input channel.
* We need to check for events before passing on the data
* to the output buffer. */
got_bytes = gst_bytestream_peek_bytes (input->bytestream, &raw_in,
GST_BUFFER_SIZE (buf_out));
/* FIXME we should do something with the data if
* got_bytes is more than zero */
if (got_bytes < GST_BUFFER_SIZE(buf_out)) {
/* we need to check for an event. */
gst_bytestream_get_status (input->bytestream, &waiting, &event);
/* FIXME we should do something with the data if
* got_bytes is more than zero */
if (got_bytes < GST_BUFFER_SIZE(buf_out)) {
GstEvent *event = NULL;
guint32 waiting;
if (event) {
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
/* we need to check for an event. */
gst_bytestream_get_status (input->bytestream, &waiting, &event);
if (event) {
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
/* if we get an EOS event from one of our sink pads, we assume that
pad's finished handling data. delete the bytestream, free up the
pad, and free up the memory associated with the input channel. */
pad's finished handling data. just skip this pad */
GST_DEBUG (GST_CAT_PLUGIN_INFO, "got an EOS event");
gst_bytestream_destroy (input->bytestream);
/* gst_object_unref (GST_OBJECT (input->sinkpad));
* this causes problems */
g_free (input);
adder->input_channels = g_slist_delete_link (inputs, inputs);
inputs = adder->input_channels;
break;
}
gst_event_unref (event);
continue;
case GST_EVENT_INTERRUPT:
gst_event_unref (event);
GST_DEBUG (GST_CAT_PLUGIN_INFO, "got an interrupt event");
/* we have to call interrupt here, the scheduler will switch out this
* element ASAP or returns TRUE if we need to exit the loop */
if (gst_element_interrupt (GST_ELEMENT (adder))) {
gst_buffer_unref (buf_out);
return;
}
default:
break;
}
} else {
/* here's where the data gets copied. this is a little nasty looking
because it's the same code pretty much 3 times, except each time uses
different data types and clamp limits. */
GST_DEBUG (GST_CAT_PLUGIN_INFO,
"copying %d bytes from channel %p to output data %p "
"in buffer %p",
GST_BUFFER_SIZE (buf_out), input,
GST_BUFFER_DATA (buf_out), buf_out);
if (adder->format == GST_ADDER_FORMAT_INT) {
if (adder->width == 16) {
gint16 *in = (gint16 *) raw_in;
gint16 *out = (gint16 *) GST_BUFFER_DATA (buf_out);
for (i = 0; i < GST_BUFFER_SIZE (buf_out) / 2; i++)
out[i] = CLAMP(out[i] + in[i], -32768, 32767);
} else if (adder->width == 8) {
gint8 *in = (gint8 *) raw_in;
gint8 *out = (gint8 *) GST_BUFFER_DATA (buf_out);
for (i = 0; i < GST_BUFFER_SIZE (buf_out); i++)
out[i] = CLAMP(out[i] + in[i], -128, 127);
} else {
GST_ERROR (GST_ELEMENT (adder),
"invalid width (%d) for int format in gstadder\n",
adder->width);
}
} else if (adder->format == GST_ADDER_FORMAT_FLOAT) {
gfloat *in = (gfloat *) raw_in;
gfloat *out = (gfloat *) GST_BUFFER_DATA (buf_out);
for (i = 0; i < GST_BUFFER_SIZE (buf_out) / sizeof (gfloat); i++)
out[i] += in[i];
}
} else {
/* here's where the data gets copied. this is a little nasty looking
because it's the same code pretty much 3 times, except each time uses
different data types and clamp limits. */
GST_DEBUG (GST_CAT_PLUGIN_INFO,
"copying %d bytes from channel %p to output data %p "
"in buffer %p",
GST_BUFFER_SIZE (buf_out), input,
GST_BUFFER_DATA (buf_out), buf_out);
if (adder->format == GST_ADDER_FORMAT_INT) {
if (adder->width == 16) {
gint16 *in = (gint16 *) raw_in;
gint16 *out = (gint16 *) GST_BUFFER_DATA (buf_out);
for (i = 0; i < GST_BUFFER_SIZE (buf_out) / 2; i++)
out[i] = CLAMP(out[i] + in[i], -32768, 32767);
} else if (adder->width == 8) {
gint8 *in = (gint8 *) raw_in;
gint8 *out = (gint8 *) GST_BUFFER_DATA (buf_out);
for (i = 0; i < GST_BUFFER_SIZE (buf_out); i++)
out[i] = CLAMP(out[i] + in[i], -128, 127);
} else {
GST_ERROR (GST_ELEMENT (adder),
"invalid audio format (%d) in gstadder\n",
adder->format);
"invalid width (%d) for int format in gstadder\n",
adder->width);
}
} else if (adder->format == GST_ADDER_FORMAT_FLOAT) {
gfloat *in = (gfloat *) raw_in;
gfloat *out = (gfloat *) GST_BUFFER_DATA (buf_out);
for (i = 0; i < GST_BUFFER_SIZE (buf_out) / sizeof (gfloat); i++)
out[i] += in[i];
} else {
GST_ERROR (GST_ELEMENT (adder),
"invalid audio format (%d) in gstadder\n",
adder->format);
}
gst_bytestream_flush (input->bytestream, GST_BUFFER_SIZE (buf_out));
gst_bytestream_flush (input->bytestream, GST_BUFFER_SIZE (buf_out));
GST_DEBUG (GST_CAT_PLUGIN_INFO, "done copying data");
}
inputs = g_slist_next (inputs);
GST_DEBUG (GST_CAT_PLUGIN_INFO, "done copying data");
}
}
if (adder->format == GST_ADDER_FORMAT_UNSET) {
GstCaps *caps =
gst_caps_new ("default_adder_caps",
"audio/raw",
gst_props_new ("format", GST_PROPS_STRING ("int"),
"width", GST_PROPS_INT (16),
"depth", GST_PROPS_INT (16),
"rate", GST_PROPS_INT (44100),
"channels", GST_PROPS_INT (2),
"law", GST_PROPS_INT (0),
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
"signed", GST_PROPS_BOOLEAN (TRUE),
NULL));
if (gst_pad_try_set_caps (adder->srcpad, caps) < 0) {
gst_element_error (GST_ELEMENT (adder),
if (adder->format == GST_ADDER_FORMAT_UNSET) {
GstCaps *caps =
gst_caps_new ("default_adder_caps",
"audio/raw",
gst_props_new ("format", GST_PROPS_STRING ("int"),
"width", GST_PROPS_INT (16),
"depth", GST_PROPS_INT (16),
"rate", GST_PROPS_INT (44100),
"channels", GST_PROPS_INT (2),
"law", GST_PROPS_INT (0),
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
"signed", GST_PROPS_BOOLEAN (TRUE),
NULL));
if (gst_pad_try_set_caps (adder->srcpad, caps) < 0) {
gst_element_error (GST_ELEMENT (adder),
"Couldn't set the default caps, "
"use connect_filtered instead");
return;
}
gst_adder_parse_caps (adder, caps);
"use link_filtered instead");
return;
}
gst_adder_parse_caps (adder, caps);
}
GST_BUFFER_TIMESTAMP (buf_out) = adder->timestamp;
if (adder->format == GST_ADDER_FORMAT_FLOAT)
adder->offset += GST_BUFFER_SIZE (buf_out) / sizeof (gfloat) / adder->channels;
else
adder->offset += GST_BUFFER_SIZE (buf_out) * 8 / adder->width / adder->channels;
adder->timestamp = adder->offset * GST_SECOND / adder->rate;
/* send it out */
GST_DEBUG (GST_CAT_PLUGIN_INFO, "pushing buf_out");
gst_pad_push (adder->srcpad, buf_out);
}
static GstElementStateReturn
gst_adder_change_state (GstElement *element)
{
GstAdder *adder;
GST_BUFFER_TIMESTAMP (buf_out) = timestamp;
if (adder->format == GST_ADDER_FORMAT_FLOAT)
offset += GST_BUFFER_SIZE (buf_out) / sizeof (gfloat) / adder->channels;
else
offset += GST_BUFFER_SIZE (buf_out) * 8 / adder->width / adder->channels;
timestamp = offset * GST_SECOND / adder->rate;
adder = GST_ADDER (element);
/* send it out */
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
adder->timestamp = 0;
adder->offset = 0;
break;
case GST_STATE_PAUSED_TO_PLAYING:
break;
case GST_STATE_PLAYING_TO_PAUSED:
if (adder->bufpool) {
gst_buffer_pool_unref (adder->bufpool);
adder->bufpool = NULL;
}
break;
case GST_STATE_PAUSED_TO_READY:
break;
case GST_STATE_READY_TO_NULL:
break;
default:
g_assert_not_reached ();
break;
}
GST_DEBUG (GST_CAT_PLUGIN_INFO, "pushing buf_out");
gst_pad_push (adder->srcpad, buf_out);
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
/* give another element a chance to do something */
gst_element_yield (element);
} while (TRUE);
return GST_STATE_SUCCESS;
}
static gboolean
......
......@@ -86,6 +86,9 @@ struct _GstAdder {
gfloat slope;
gfloat intercept;
/* counters to keep track of timestamps */
gint64 timestamp;
gint64 offset;
};
struct _GstAdderClass {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment