diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/ladspa/gstsignalprocessor.c | 201 |
1 files changed, 127 insertions, 74 deletions
diff --git a/ext/ladspa/gstsignalprocessor.c b/ext/ladspa/gstsignalprocessor.c index 884bb1e5..880a94c0 100644 --- a/ext/ladspa/gstsignalprocessor.c +++ b/ext/ladspa/gstsignalprocessor.c @@ -110,6 +110,10 @@ struct _GstSignalProcessorPad GstBuffer *pen; guint index; + + /* these are only used for sink pads */ + guint samples_avail; + gfloat *data; }; static GType @@ -281,15 +285,17 @@ gst_signal_processor_setcaps (GstPad * pad, GstCaps * caps) GST_WARNING ("got no sample-rate"); goto impossible; } else { - GST_DEBUG ("Got rate=%d", sample_rate); + GST_DEBUG_OBJECT (self, "Got rate=%d", sample_rate); } - if (!klass->setup (self, sample_rate)) + if (!klass->setup (self, sample_rate)) { goto setup_failed; - else + } else { self->sample_rate = sample_rate; + gst_caps_replace (&self->caps, caps); + } } else { - GST_DEBUG ("skipping, have caps already"); + GST_DEBUG_OBJECT (self, "skipping, have caps already"); } /* FIXME: handle was_active, etc */ @@ -334,90 +340,138 @@ gst_signal_processor_event (GstPad * pad, GstEvent * event) return ret; } -static void -gst_signal_processor_process (GstSignalProcessor * self) +static guint +gst_signal_processor_prepare (GstSignalProcessor * self) { - GstElement *elem; - GList *l1, *l2; - GstSignalProcessorClass *klass; - guint nframes = G_MAXUINT; + GstElement *elem = (GstElement *) self; + GList *sinks, *srcs; + guint samples_avail = G_MAXUINT; + + /* first, assign audio_in pointers, and determine the number of samples that + * we can process */ + for (sinks = elem->sinkpads; sinks; sinks = sinks->next) { + GstSignalProcessorPad *sinkpad; + + sinkpad = (GstSignalProcessorPad *) sinks->data; + g_assert (sinkpad->samples_avail > 0); + samples_avail = MIN (samples_avail, sinkpad->samples_avail); + self->audio_in[sinkpad->index] = sinkpad->data; + } - g_return_if_fail (self->pending_in == 0); - g_return_if_fail (self->pending_out == 0); + if (samples_avail == G_MAXUINT) { + /* we don't have any sink pads, just choose a size -- should fix this + * function to have a suggested number of samples in the case of + * gst_pad_pull_range */ + samples_avail = 256; + } - elem = GST_ELEMENT (self); + /* now assign output buffers. we can avoid allocation by reusing input + buffers, but only if process() can work in place, and if the input buffer + is the exact size of the number of samples we are processing. */ + sinks = elem->sinkpads; + srcs = elem->srcpads; + while (sinks && srcs) { + GstSignalProcessorPad *sinkpad, *srcpad; - /* arrange the output buffers */ - for (l1 = elem->sinkpads, l2 = elem->srcpads; l1 || l2; - l1 = l1 ? l1->next : NULL, l2 = l2 ? l2->next : NULL) { - GstSignalProcessorPad *srcpad, *sinkpad; + sinkpad = (GstSignalProcessorPad *) sinks->data; + srcpad = (GstSignalProcessorPad *) srcs->data; - if (l1) { - GstSignalProcessorPad *tmp = (GstSignalProcessorPad *) l1->data; + if (GST_BUFFER_SIZE (sinkpad->pen) == samples_avail * sizeof (gfloat)) { + /* reusable, yay */ + g_assert (sinkpad->samples_avail == samples_avail); + srcpad->pen = sinkpad->pen; + sinkpad->pen = NULL; + self->audio_out[srcpad->index] = sinkpad->data; + self->pending_out++; - nframes = MIN (nframes, GST_BUFFER_SIZE (tmp->pen) / sizeof (gfloat)); + srcs = srcs->next; } - if (!l2) { - /* the output buffers have been covered, yay -- just keep looping to check - available frames */ - } else if (!l1) { - /* need to alloc some output buffers */ - for (; l2; l2 = l2->next) { - GstFlowReturn ret; - - srcpad = (GstSignalProcessorPad *) l2->data; - - ret = - gst_pad_alloc_buffer_and_set_caps (GST_PAD (srcpad), -1, - nframes, GST_PAD_CAPS (srcpad), &srcpad->pen); - - if (ret != GST_FLOW_OK) { - self->state = ret; - goto flow_error; - } else { - self->audio_out[srcpad->index] = - (gfloat *) GST_BUFFER_DATA (srcpad->pen); - self->pending_out++; - } - } - - /* the for condition should cut out because of this, but I assert to be - clear */ - g_assert (l2 == NULL); - } else { - /* copy input to output */ - sinkpad = (GstSignalProcessorPad *) l1->data; - srcpad = (GstSignalProcessorPad *) l2->data; + sinks = sinks->next; + } - srcpad->pen = sinkpad->pen; - sinkpad->pen = NULL; + /* now allocate for any remaining outputs */ + while (srcs) { + GstSignalProcessorPad *srcpad; + GstFlowReturn ret; + + srcpad = (GstSignalProcessorPad *) srcs->data; + + ret = + gst_pad_alloc_buffer_and_set_caps (GST_PAD (srcpad), -1, + samples_avail, GST_PAD_CAPS (srcpad), &srcpad->pen); + + if (ret != GST_FLOW_OK) { + self->state = ret; + return 0; + } else { self->audio_out[srcpad->index] = (gfloat *) GST_BUFFER_DATA (srcpad->pen); self->pending_out++; } - } - /* will fail in the ladspa src case, need to check that :-/ */ - g_assert (nframes < G_MAXUINT); - - klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self); + srcs = srcs->next; + } - GST_INFO_OBJECT (self, "process(%u)", nframes); + return samples_avail; +} - klass->process (self, nframes); +static void +gst_signal_processor_update_inputs (GstSignalProcessor * self, guint nprocessed) +{ + GstElement *elem = (GstElement *) self; + GList *sinks; - /* reset */ - self->pending_in = klass->num_audio_in; + for (sinks = elem->sinkpads; sinks; sinks = sinks->next) { + GstSignalProcessorPad *sinkpad; - /* free unneeded input buffers */ - for (l1 = elem->sinkpads; l1; l1 = l1->next) { - GstSignalProcessorPad *sinkpad = (GstSignalProcessorPad *) l1->data; + sinkpad = (GstSignalProcessorPad *) sinks->data; + g_assert (sinkpad->samples_avail >= nprocessed); - if (sinkpad->pen) { + if (sinkpad->pen && sinkpad->samples_avail == nprocessed) { + /* used up this buffer, unpen */ gst_buffer_unref (sinkpad->pen); sinkpad->pen = NULL; } + + if (!sinkpad->pen) { + /* this buffer was used up */ + self->pending_in++; + sinkpad->data = NULL; + sinkpad->samples_avail = 0; + } else { + /* advance ->data pointers and decrement ->samples_avail, unreffing buffer + if no samples are left */ + sinkpad->samples_avail -= nprocessed; + sinkpad->data += nprocessed; /* gfloat* arithmetic */ + } } +} + +static void +gst_signal_processor_process (GstSignalProcessor * self) +{ + GstElement *elem; + GstSignalProcessorClass *klass; + guint nframes; + + g_return_if_fail (self->pending_in == 0); + g_return_if_fail (self->pending_out == 0); + + elem = GST_ELEMENT (self); + + nframes = gst_signal_processor_prepare (self); + if (G_UNLIKELY (nframes == 0)) + goto flow_error; + + klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self); + + GST_LOG_OBJECT (self, "process(%u)", nframes); + + klass->process (self, nframes); + + gst_signal_processor_update_inputs (self, nframes); + + return; flow_error: { @@ -442,15 +496,12 @@ gst_signal_processor_pen_buffer (GstSignalProcessor * self, GstPad * pad, /* keep the reference */ spad->pen = buffer; - self->audio_in[spad->index] = (gfloat *) GST_BUFFER_DATA (buffer); + spad->data = (gfloat *) GST_BUFFER_DATA (buffer); + spad->samples_avail = GST_BUFFER_SIZE (buffer) / sizeof (float); g_assert (self->pending_in != 0); self->pending_in--; - - if (self->pending_in == 0) { - gst_signal_processor_process (self); - } } static void @@ -466,6 +517,8 @@ gst_signal_processor_flush (GstSignalProcessor * self) if (spad->pen) { gst_buffer_unref (spad->pen); spad->pen = NULL; + spad->data = NULL; + spad->samples_avail = 0; } } } @@ -666,7 +719,7 @@ gst_signal_processor_sink_activate_push (GstPad * pad, gboolean active) } } - GST_DEBUG ("result : %d", TRUE); + GST_DEBUG_OBJECT (self, "result : %d", result); gst_object_unref (self); @@ -714,7 +767,7 @@ gst_signal_processor_src_activate_pull (GstPad * pad, gboolean active) } } - GST_DEBUG ("result : %d", TRUE); + GST_DEBUG_OBJECT ("result : %d", result); gst_object_unref (self); @@ -766,7 +819,7 @@ gst_signal_processor_change_state (GstElement * element, /* ERRORS */ failure: { - GST_DEBUG ("parent failed state change"); + GST_DEBUG_OBJECT (element, "parent failed state change"); return result; } } |