1 /* gstmonoscope.c: implementation of monoscope drawing element
2 * Copyright (C) <2002> Richard Boulton <richard@tartarus.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
26 #include "monoscope.h"
28 #define GST_TYPE_MONOSCOPE (gst_monoscope_get_type())
29 #define GST_MONOSCOPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MONOSCOPE,GstMonoscope))
30 #define GST_MONOSCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MONOSCOPE,GstMonoscope))
31 #define GST_IS_MONOSCOPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MONOSCOPE))
32 #define GST_IS_MONOSCOPE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MONOSCOPE))
34 typedef struct _GstMonoscope GstMonoscope;
35 typedef struct _GstMonoscopeClass GstMonoscopeClass;
37 struct _GstMonoscope {
41 GstPad *sinkpad,*srcpad;
42 GstBufferPool *peerpool;
44 /* the timestamp of the next frame */
52 gboolean first_buffer;
54 /* visualisation state */
55 struct monoscope_state * visstate;
58 struct _GstMonoscopeClass {
59 GstElementClass parent_class;
62 GType gst_monoscope_get_type(void);
65 /* elementfactory information */
66 static GstElementDetails gst_monoscope_details = {
70 "Displays a highly stabilised waveform of audio input",
72 "Richard Boulton <richard@tartarus.org>",
76 /* signals and args */
90 GST_PAD_TEMPLATE_FACTORY (src_template,
97 "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")),
98 "bpp", GST_PROPS_INT (32),
99 "depth", GST_PROPS_INT (32),
100 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
101 "red_mask", GST_PROPS_INT (0xff0000),
102 "green_mask", GST_PROPS_INT (0xff00),
103 "blue_mask", GST_PROPS_INT (0xff),
104 "width", GST_PROPS_INT_RANGE (16, 4096),
105 "height", GST_PROPS_INT_RANGE (16, 4096)
109 GST_PAD_TEMPLATE_FACTORY (sink_template,
110 "sink", /* the name of the pads */
111 GST_PAD_SINK, /* type of the pad */
112 GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */
114 "monoscopesink", /* the name of the caps */
115 "audio/raw", /* the mime type of the caps */
116 /* Properties follow: */
117 "format", GST_PROPS_STRING ("int"),
118 "law", GST_PROPS_INT (0),
119 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
120 "signed", GST_PROPS_BOOLEAN (TRUE),
121 "width", GST_PROPS_INT (16),
122 "depth", GST_PROPS_INT (16),
123 "rate", GST_PROPS_INT_RANGE (8000, 96000),
124 "channels", GST_PROPS_INT (1)
129 static void gst_monoscope_class_init (GstMonoscopeClass *klass);
130 static void gst_monoscope_init (GstMonoscope *monoscope);
132 static void gst_monoscope_set_property (GObject *object, guint prop_id,
133 const GValue *value, GParamSpec *pspec);
134 static void gst_monoscope_get_property (GObject *object, guint prop_id,
135 GValue *value, GParamSpec *pspec);
137 static void gst_monoscope_chain (GstPad *pad, GstBuffer *buf);
139 static GstPadLinkReturn
140 gst_monoscope_sinkconnect (GstPad *pad, GstCaps *caps);
142 static GstElementClass *parent_class = NULL;
145 gst_monoscope_get_type (void)
147 static GType type = 0;
150 static const GTypeInfo info = {
151 sizeof (GstMonoscopeClass),
154 (GClassInitFunc) gst_monoscope_class_init,
157 sizeof (GstMonoscope),
159 (GInstanceInitFunc) gst_monoscope_init,
161 type = g_type_register_static (GST_TYPE_ELEMENT, "GstMonoscope", &info, 0);
167 gst_monoscope_class_init(GstMonoscopeClass *klass)
169 GObjectClass *gobject_class;
170 GstElementClass *gstelement_class;
172 gobject_class = (GObjectClass*) klass;
173 gstelement_class = (GstElementClass*) klass;
175 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
177 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_WIDTH,
178 g_param_spec_int ("width","Width","The Width",
179 1, 2048, 256, G_PARAM_READWRITE));
180 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HEIGHT,
181 g_param_spec_int ("height","Height","The height",
182 1, 2048, 128, G_PARAM_READWRITE));
183 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FPS,
184 g_param_spec_int ("fps","FPS","Frames per second",
185 1, 100, 25, G_PARAM_READWRITE));
187 gobject_class->set_property = gst_monoscope_set_property;
188 gobject_class->get_property = gst_monoscope_get_property;
192 gst_monoscope_init (GstMonoscope *monoscope)
194 /* create the sink and src pads */
195 monoscope->sinkpad = gst_pad_new_from_template (
196 GST_PAD_TEMPLATE_GET (sink_template ), "sink");
197 monoscope->srcpad = gst_pad_new_from_template (
198 GST_PAD_TEMPLATE_GET (src_template ), "src");
199 gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->sinkpad);
200 gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->srcpad);
202 gst_pad_set_chain_function (monoscope->sinkpad, gst_monoscope_chain);
203 gst_pad_set_link_function (monoscope->sinkpad, gst_monoscope_sinkconnect);
205 monoscope->next_time = 0;
206 monoscope->peerpool = NULL;
208 /* reset the initial video state */
209 monoscope->first_buffer = TRUE;
210 monoscope->width = 256;
211 monoscope->height = 128;
212 monoscope->fps = 25; /* desired frame rate */
216 static GstPadLinkReturn
217 gst_monoscope_sinkconnect (GstPad *pad, GstCaps *caps)
219 GstMonoscope *monoscope;
220 monoscope = GST_MONOSCOPE (gst_pad_get_parent (pad));
222 if (!GST_CAPS_IS_FIXED (caps)) {
223 return GST_PAD_LINK_DELAYED;
226 return GST_PAD_LINK_OK;
230 gst_monoscope_chain (GstPad *pad, GstBuffer *bufin)
232 GstMonoscope *monoscope;
238 monoscope = GST_MONOSCOPE (gst_pad_get_parent (pad));
240 GST_DEBUG ("Monoscope: chainfunc called");
242 samples_in = GST_BUFFER_SIZE (bufin) / sizeof (gint16);
244 GST_DEBUG ("input buffer has %d samples", samples_in);
246 /* FIXME: should really select the first 1024 samples after the timestamp. */
247 if (GST_BUFFER_TIMESTAMP (bufin) < monoscope->next_time || samples_in < 1024) {
248 GST_DEBUG ("timestamp is %" G_GUINT64_FORMAT ": want >= %" G_GUINT64_FORMAT, GST_BUFFER_TIMESTAMP (bufin), monoscope->next_time);
249 gst_buffer_unref (bufin);
253 data = (gint16 *) GST_BUFFER_DATA (bufin);
254 /* FIXME: Select samples in a better way. */
255 for (i=0; i < 512; i++) {
256 monoscope->datain[i] = *data++;
259 if (monoscope->first_buffer) {
262 monoscope->visstate = monoscope_init (monoscope->width, monoscope->height);
263 g_assert(monoscope->visstate != 0);
264 GST_DEBUG ("making new pad");
266 caps = GST_CAPS_NEW (
269 "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")),
270 "bpp", GST_PROPS_INT (32),
271 "depth", GST_PROPS_INT (32),
272 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
273 "red_mask", GST_PROPS_INT (0xff0000),
274 "green_mask", GST_PROPS_INT (0x00ff00),
275 "blue_mask", GST_PROPS_INT (0x0000ff),
276 "width", GST_PROPS_INT (monoscope->width),
277 "height", GST_PROPS_INT (monoscope->height)
280 if (gst_pad_try_set_caps (monoscope->srcpad, caps) <= 0) {
281 gst_element_error (GST_ELEMENT (monoscope), "could not set caps");
284 monoscope->first_buffer = FALSE;
287 bufout = gst_buffer_new ();
288 GST_BUFFER_SIZE (bufout) = monoscope->width * monoscope->height * 4;
289 GST_BUFFER_DATA (bufout) = (guchar *) monoscope_update (monoscope->visstate, monoscope->datain);
290 GST_BUFFER_TIMESTAMP (bufout) = monoscope->next_time;
291 GST_BUFFER_FLAG_SET (bufout, GST_BUFFER_DONTFREE);
293 monoscope->next_time += GST_SECOND / monoscope->fps;
295 gst_pad_push (monoscope->srcpad, bufout);
297 gst_buffer_unref (bufin);
299 GST_DEBUG ("Monoscope: exiting chainfunc");
304 gst_monoscope_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
306 GstMonoscope *monoscope;
308 /* it's not null if we got it, but it might not be ours */
309 g_return_if_fail (GST_IS_MONOSCOPE (object));
310 monoscope = GST_MONOSCOPE (object);
314 monoscope->width = g_value_get_int (value);
317 monoscope->height = g_value_get_int (value);
320 monoscope->fps = g_value_get_int (value);
328 gst_monoscope_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
330 GstMonoscope *monoscope;
332 /* it's not null if we got it, but it might not be ours */
333 g_return_if_fail (GST_IS_MONOSCOPE (object));
334 monoscope = GST_MONOSCOPE (object);
338 g_value_set_int (value, monoscope->width);
341 g_value_set_int (value, monoscope->height);
344 g_value_set_int (value, monoscope->fps);
352 plugin_init (GModule *module, GstPlugin *plugin)
354 GstElementFactory *factory;
356 /* create an elementfactory for the monoscope element */
357 factory = gst_element_factory_new("monoscope",GST_TYPE_MONOSCOPE,
358 &gst_monoscope_details);
359 g_return_val_if_fail(factory != NULL, FALSE);
361 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_template));
362 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_template));
364 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
369 GstPluginDesc plugin_desc = {