1 /* GStreamer LADSPA filter category
2  * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3  *               2001 Steve Baker <stevebaker_org@yahoo.co.uk>
4  *               2003 Andy Wingo <wingo at pobox.com>
5  * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "gstladspafilter.h"
28 #include "gstladspa.h"
29 #include "gstladspautils.h"
30 
31 GST_DEBUG_CATEGORY_EXTERN (ladspa_debug);
32 #define GST_CAT_DEFAULT ladspa_debug
33 
34 #define GST_LADSPA_FILTER_CLASS_TAGS "Filter/Effect/Audio/LADSPA"
35 
36 static GstLADSPAFilterClass *gst_ladspa_filter_type_parent_class = NULL;
37 
38 /*
39  * Assumes only same format (base of AudioFilter), not same channels.
40  */
41 void
gst_my_audio_filter_class_add_pad_templates(GstAudioFilterClass * audio_class,GstCaps * srccaps,GstCaps * sinkcaps)42 gst_my_audio_filter_class_add_pad_templates (GstAudioFilterClass * audio_class,
43     GstCaps * srccaps, GstCaps * sinkcaps)
44 {
45   GstElementClass *elem_class = GST_ELEMENT_CLASS (audio_class);
46   GstPadTemplate *pad_template;
47 
48   g_return_if_fail (GST_IS_CAPS (srccaps) && GST_IS_CAPS (sinkcaps));
49 
50   pad_template =
51       gst_pad_template_new (GST_BASE_TRANSFORM_SRC_NAME, GST_PAD_SRC,
52       GST_PAD_ALWAYS, srccaps);
53   gst_element_class_add_pad_template (elem_class, pad_template);
54 
55   pad_template =
56       gst_pad_template_new (GST_BASE_TRANSFORM_SINK_NAME, GST_PAD_SINK,
57       GST_PAD_ALWAYS, sinkcaps);
58   gst_element_class_add_pad_template (elem_class, pad_template);
59 }
60 
61 static GstCaps *
gst_ladspa_filter_type_fixate_caps(GstBaseTransform * base,GstPadDirection direction,GstCaps * caps,GstCaps * othercaps)62 gst_ladspa_filter_type_fixate_caps (GstBaseTransform * base,
63     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
64 {
65   GstStructure *structure;
66   gint rate;
67 
68   structure = gst_caps_get_structure (caps, 0);
69   if (G_UNLIKELY (!gst_structure_get_int (structure, "rate", &rate)))
70     return othercaps;
71 
72   othercaps = gst_caps_truncate (othercaps);
73   othercaps = gst_caps_make_writable (othercaps);
74   structure = gst_caps_get_structure (othercaps, 0);
75 
76   gst_structure_fixate_field_nearest_int (structure, "rate", rate);
77 
78   return othercaps;
79 }
80 
81 static GstCaps *
gst_ladspa_filter_type_transform_caps(GstBaseTransform * base,GstPadDirection direction,GstCaps * caps,GstCaps * filter)82 gst_ladspa_filter_type_transform_caps (GstBaseTransform * base,
83     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
84 {
85   GstCaps *srccaps, *sinkcaps;
86   GstCaps *ret = NULL;
87 
88   srccaps = gst_pad_get_pad_template_caps (GST_BASE_TRANSFORM_SRC_PAD (base));
89   sinkcaps = gst_pad_get_pad_template_caps (GST_BASE_TRANSFORM_SINK_PAD (base));
90 
91   switch (direction) {
92     case GST_PAD_SINK:
93       if (gst_caps_can_intersect (caps, sinkcaps))
94         ret = gst_caps_copy (srccaps);
95       else
96         ret = gst_caps_new_empty ();
97       break;
98     case GST_PAD_SRC:
99       if (gst_caps_can_intersect (caps, srccaps))
100         ret = gst_caps_copy (sinkcaps);
101       else
102         ret = gst_caps_new_empty ();
103       break;
104     default:
105       g_assert_not_reached ();
106   }
107 
108   GST_DEBUG_OBJECT (base, "transformed %" GST_PTR_FORMAT, ret);
109 
110   if (filter) {
111     GstCaps *intersection;
112 
113     GST_DEBUG_OBJECT (base, "Using filter caps %" GST_PTR_FORMAT, filter);
114 
115     intersection =
116         gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
117     gst_caps_unref (ret);
118     ret = intersection;
119 
120     GST_DEBUG_OBJECT (base, "Intersection %" GST_PTR_FORMAT, ret);
121   }
122 
123   gst_caps_unref (srccaps);
124   gst_caps_unref (sinkcaps);
125 
126   return ret;
127 }
128 
129 static GstFlowReturn
gst_ladspa_filter_type_prepare_output_buffer(GstBaseTransform * base,GstBuffer * inbuf,GstBuffer ** outbuf)130 gst_ladspa_filter_type_prepare_output_buffer (GstBaseTransform * base,
131     GstBuffer * inbuf, GstBuffer ** outbuf)
132 {
133   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
134   GstLADSPAFilterClass *ladspa_class = GST_LADSPA_FILTER_GET_CLASS (ladspa);
135   guint samples;
136 
137   samples =
138       gst_buffer_get_size (inbuf) / sizeof (LADSPA_Data) /
139       ladspa_class->ladspa.count.audio.in;
140 
141   if (!gst_base_transform_is_in_place (base)) {
142     *outbuf =
143         gst_buffer_new_allocate (NULL,
144         samples * sizeof (LADSPA_Data) * ladspa_class->ladspa.count.audio.out,
145         NULL);
146     *outbuf = gst_buffer_make_writable (*outbuf);
147     return GST_FLOW_OK;
148   } else {
149     return
150         GST_BASE_TRANSFORM_CLASS
151         (gst_ladspa_filter_type_parent_class)->prepare_output_buffer (base,
152         inbuf, outbuf);
153   }
154 }
155 
156 static gboolean
gst_ladspa_filter_type_setup(GstAudioFilter * audio,const GstAudioInfo * info)157 gst_ladspa_filter_type_setup (GstAudioFilter * audio, const GstAudioInfo * info)
158 {
159   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (audio);
160 
161   return gst_ladspa_setup (&ladspa->ladspa, GST_AUDIO_INFO_RATE (info));
162 }
163 
164 static gboolean
gst_ladspa_filter_type_cleanup(GstBaseTransform * base)165 gst_ladspa_filter_type_cleanup (GstBaseTransform * base)
166 {
167   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
168 
169   return gst_ladspa_cleanup (&ladspa->ladspa);
170 }
171 
172 static GstFlowReturn
gst_ladspa_filter_type_transform_ip(GstBaseTransform * base,GstBuffer * buf)173 gst_ladspa_filter_type_transform_ip (GstBaseTransform * base, GstBuffer * buf)
174 {
175   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
176   GstMapInfo map;
177   guint samples;
178 
179   gst_buffer_map (buf, &map, GST_MAP_READWRITE);
180   samples =
181       map.size / sizeof (LADSPA_Data) / ladspa->ladspa.klass->count.audio.in;
182   gst_ladspa_transform (&ladspa->ladspa, map.data, samples, map.data);
183   gst_buffer_unmap (buf, &map);
184 
185   return GST_FLOW_OK;
186 }
187 
188 static GstFlowReturn
gst_ladspa_filter_type_transform(GstBaseTransform * base,GstBuffer * inbuf,GstBuffer * outbuf)189 gst_ladspa_filter_type_transform (GstBaseTransform * base,
190     GstBuffer * inbuf, GstBuffer * outbuf)
191 {
192   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
193   GstMapInfo inmap, outmap;
194   guint samples;
195 
196   gst_object_sync_values (GST_OBJECT (ladspa), GST_BUFFER_TIMESTAMP (inbuf));
197 
198   gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
199   gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
200   samples =
201       inmap.size / sizeof (LADSPA_Data) / ladspa->ladspa.klass->count.audio.in;
202   gst_ladspa_transform (&ladspa->ladspa, outmap.data, samples, inmap.data);
203   gst_buffer_unmap (outbuf, &outmap);
204   gst_buffer_unmap (inbuf, &inmap);
205 
206   return GST_FLOW_OK;
207 }
208 
209 static void
gst_ladspa_filter_type_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)210 gst_ladspa_filter_type_set_property (GObject * object, guint prop_id,
211     const GValue * value, GParamSpec * pspec)
212 {
213   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (object);
214 
215   gst_ladspa_object_set_property (&ladspa->ladspa, object, prop_id, value,
216       pspec);
217 }
218 
219 static void
gst_ladspa_filter_type_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)220 gst_ladspa_filter_type_get_property (GObject * object, guint prop_id,
221     GValue * value, GParamSpec * pspec)
222 {
223   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (object);
224 
225   gst_ladspa_object_get_property (&ladspa->ladspa, object, prop_id, value,
226       pspec);
227 }
228 
229 static void
gst_ladspa_filter_type_init(GstLADSPAFilter * ladspa,LADSPA_Descriptor * desc)230 gst_ladspa_filter_type_init (GstLADSPAFilter * ladspa, LADSPA_Descriptor * desc)
231 {
232   GstBaseTransform *base = GST_BASE_TRANSFORM (ladspa);
233   GstLADSPAFilterClass *ladspa_class = GST_LADSPA_FILTER_GET_CLASS (ladspa);
234 
235   gst_ladspa_init (&ladspa->ladspa, &ladspa_class->ladspa);
236 
237   /* even if channels are different LADSPA still maintains same samples */
238   gst_base_transform_set_in_place (base,
239       ladspa_class->ladspa.count.audio.in ==
240       ladspa_class->ladspa.count.audio.out
241       && !LADSPA_IS_INPLACE_BROKEN (ladspa_class->ladspa.descriptor->
242           Properties));
243 
244 }
245 
246 static void
gst_ladspa_filter_type_dispose(GObject * object)247 gst_ladspa_filter_type_dispose (GObject * object)
248 {
249   GstBaseTransform *base = GST_BASE_TRANSFORM (object);
250 
251   gst_ladspa_filter_type_cleanup (base);
252 
253   G_OBJECT_CLASS (gst_ladspa_filter_type_parent_class)->dispose (object);
254 }
255 
256 static void
gst_ladspa_filter_type_finalize(GObject * object)257 gst_ladspa_filter_type_finalize (GObject * object)
258 {
259   GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (object);
260 
261   gst_ladspa_finalize (&ladspa->ladspa);
262 
263   G_OBJECT_CLASS (gst_ladspa_filter_type_parent_class)->finalize (object);
264 }
265 
266 /*
267  * It is okay for plugins to 'leak' a one-time allocation. This will be freed when
268  * the application exits. When the plugins are scanned for the first time, this is
269  * done from a separate process to not impose the memory overhead on the calling
270  * application (among other reasons). Hence no need for class_finalize.
271  */
272 static void
gst_ladspa_filter_type_base_init(GstLADSPAFilterClass * ladspa_class)273 gst_ladspa_filter_type_base_init (GstLADSPAFilterClass * ladspa_class)
274 {
275   GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class);
276   GstAudioFilterClass *audio_class = GST_AUDIO_FILTER_CLASS (ladspa_class);
277 
278   gst_ladspa_class_init (&ladspa_class->ladspa,
279       G_TYPE_FROM_CLASS (ladspa_class));
280 
281   gst_ladspa_element_class_set_metadata (&ladspa_class->ladspa, elem_class,
282       GST_LADSPA_FILTER_CLASS_TAGS);
283   gst_ladspa_filter_type_class_add_pad_templates (&ladspa_class->ladspa,
284       audio_class);
285 }
286 
287 static void
gst_ladspa_filter_type_base_finalize(GstLADSPAFilterClass * ladspa_class)288 gst_ladspa_filter_type_base_finalize (GstLADSPAFilterClass * ladspa_class)
289 {
290   gst_ladspa_class_finalize (&ladspa_class->ladspa);
291 }
292 
293 static void
gst_ladspa_filter_type_class_init(GstLADSPAFilterClass * ladspa_class,LADSPA_Descriptor * desc)294 gst_ladspa_filter_type_class_init (GstLADSPAFilterClass * ladspa_class,
295     LADSPA_Descriptor * desc)
296 {
297   GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
298   GstBaseTransformClass *base_class = GST_BASE_TRANSFORM_CLASS (ladspa_class);
299   GstAudioFilterClass *audio_class = GST_AUDIO_FILTER_CLASS (ladspa_class);
300 
301   GST_DEBUG ("LADSPA filter class %p", ladspa_class);
302 
303   gst_ladspa_filter_type_parent_class = g_type_class_peek_parent (ladspa_class);
304 
305   object_class->dispose = GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_dispose);
306   object_class->finalize = GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_finalize);
307   object_class->set_property =
308       GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_set_property);
309   object_class->get_property =
310       GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_get_property);
311 
312   base_class->fixate_caps =
313       GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_fixate_caps);
314   base_class->transform_caps =
315       GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_transform_caps);
316   base_class->prepare_output_buffer =
317       GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_prepare_output_buffer);
318   base_class->transform = GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_transform);
319   base_class->transform_ip =
320       GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_transform_ip);
321 
322   audio_class->setup = GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_setup);
323 
324   gst_ladspa_object_class_install_properties (&ladspa_class->ladspa,
325       object_class, 1);
326 }
327 
328 G_DEFINE_ABSTRACT_TYPE (GstLADSPAFilter, gst_ladspa_filter,
329     GST_TYPE_AUDIO_FILTER);
330 
331 static void
gst_ladspa_filter_init(GstLADSPAFilter * ladspa)332 gst_ladspa_filter_init (GstLADSPAFilter * ladspa)
333 {
334 }
335 
336 static void
gst_ladspa_filter_class_init(GstLADSPAFilterClass * ladspa_class)337 gst_ladspa_filter_class_init (GstLADSPAFilterClass * ladspa_class)
338 {
339 }
340 
341 /*
342  * Construct the type.
343  */
344 void
ladspa_register_filter_element(GstPlugin * plugin,GstStructure * ladspa_meta)345 ladspa_register_filter_element (GstPlugin * plugin, GstStructure * ladspa_meta)
346 {
347   GTypeInfo info = {
348     sizeof (GstLADSPAFilterClass),
349     (GBaseInitFunc) gst_ladspa_filter_type_base_init,
350     (GBaseFinalizeFunc) gst_ladspa_filter_type_base_finalize,
351     (GClassInitFunc) gst_ladspa_filter_type_class_init,
352     NULL,
353     NULL,
354     sizeof (GstLADSPAFilter),
355     0,
356     (GInstanceInitFunc) gst_ladspa_filter_type_init,
357     NULL
358   };
359   ladspa_register_element (plugin, GST_TYPE_LADSPA_FILTER, &info, ladspa_meta);
360 }
361