From 4560424580af347c998aa9790ee995e4a59eba92 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 11 Jan 2003 16:28:29 +0000 Subject: [PATCH] - Fix endless loop in adder Original commit message from CVS: - Fix endless loop in adder - return from interrupt events. --- gst/adder/gstadder.c | 321 +++++++++++++++++++++++++++++---------------------- gst/adder/gstadder.h | 3 + 2 files changed, 185 insertions(+), 139 deletions(-) diff --git a/gst/adder/gstadder.c b/gst/adder/gstadder.c index 36b613f..97e84da 100644 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@ -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 diff --git a/gst/adder/gstadder.h b/gst/adder/gstadder.h index 39fb370..2493534 100644 --- a/gst/adder/gstadder.h +++ b/gst/adder/gstadder.h @@ -86,6 +86,9 @@ struct _GstAdder { gfloat slope; gfloat intercept; + /* counters to keep track of timestamps */ + gint64 timestamp; + gint64 offset; }; struct _GstAdderClass { -- 2.7.4