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.
23 #include "monoscope.h"
25 #define GST_TYPE_MONOSCOPE (gst_monoscope_get_type())
26 #define GST_MONOSCOPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MONOSCOPE,GstMonoscope))
27 #define GST_MONOSCOPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MONOSCOPE,GstMonoscope))
28 #define GST_IS_MONOSCOPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MONOSCOPE))
29 #define GST_IS_MONOSCOPE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MONOSCOPE))
31 typedef struct _GstMonoscope GstMonoscope;
32 typedef struct _GstMonoscopeClass GstMonoscopeClass;
34 struct _GstMonoscope {
38 GstPad *sinkpad,*srcpad;
39 GstBufferPool *peerpool;
41 // the timestamp of the next frame
49 gboolean first_buffer;
51 // visualisation state
52 struct monoscope_state * visstate;
55 struct _GstMonoscopeClass {
56 GstElementClass parent_class;
59 GType gst_monoscope_get_type(void);
62 /* elementfactory information */
63 static GstElementDetails gst_monoscope_details = {
65 "Filter/Visualization",
66 "Displays a highly stabilised waveform of audio input",
68 "Richard Boulton <richard@tartarus.org>",
72 /* signals and args */
86 GST_PADTEMPLATE_FACTORY (src_template,
93 "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")),
94 "bpp", GST_PROPS_INT (32),
95 "depth", GST_PROPS_INT (32),
96 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
97 "red_mask", GST_PROPS_INT (0xff0000),
98 "green_mask", GST_PROPS_INT (0xff00),
99 "blue_mask", GST_PROPS_INT (0xff),
100 "width", GST_PROPS_INT_RANGE (16, 4096),
101 "height", GST_PROPS_INT_RANGE (16, 4096)
105 GST_PADTEMPLATE_FACTORY (sink_template,
106 "sink", /* the name of the pads */
107 GST_PAD_SINK, /* type of the pad */
108 GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */
110 "monoscopesink", /* the name of the caps */
111 "audio/raw", /* the mime type of the caps */
112 /* Properties follow: */
113 "format", GST_PROPS_STRING ("int"),
114 "law", GST_PROPS_INT (0),
115 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
116 "signed", GST_PROPS_BOOLEAN (TRUE),
117 "width", GST_PROPS_INT (16),
118 "depth", GST_PROPS_INT (16),
119 "rate", GST_PROPS_INT_RANGE (8000, 96000),
120 "channels", GST_PROPS_INT (1)
125 static void gst_monoscope_class_init (GstMonoscopeClass *klass);
126 static void gst_monoscope_init (GstMonoscope *monoscope);
128 static void gst_monoscope_set_property (GObject *object, guint prop_id,
129 const GValue *value, GParamSpec *pspec);
130 static void gst_monoscope_get_property (GObject *object, guint prop_id,
131 GValue *value, GParamSpec *pspec);
133 static void gst_monoscope_chain (GstPad *pad, GstBuffer *buf);
135 static GstPadConnectReturn
136 gst_monoscope_sinkconnect (GstPad *pad, GstCaps *caps);
138 static GstElementClass *parent_class = NULL;
141 gst_monoscope_get_type (void)
143 static GType type = 0;
146 static const GTypeInfo info = {
147 sizeof (GstMonoscopeClass),
150 (GClassInitFunc) gst_monoscope_class_init,
153 sizeof (GstMonoscope),
155 (GInstanceInitFunc) gst_monoscope_init,
157 type = g_type_register_static (GST_TYPE_ELEMENT, "GstMonoscope", &info, 0);
163 gst_monoscope_class_init(GstMonoscopeClass *klass)
165 GObjectClass *gobject_class;
166 GstElementClass *gstelement_class;
168 gobject_class = (GObjectClass*) klass;
169 gstelement_class = (GstElementClass*) klass;
171 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
173 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_WIDTH,
174 g_param_spec_int ("width","Width","The Width",
175 1, 2048, 256, G_PARAM_READWRITE));
176 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HEIGHT,
177 g_param_spec_int ("height","Height","The height",
178 1, 2048, 128, G_PARAM_READWRITE));
179 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FPS,
180 g_param_spec_int ("fps","FPS","Frames per second",
181 1, 100, 25, G_PARAM_READWRITE));
183 gobject_class->set_property = gst_monoscope_set_property;
184 gobject_class->get_property = gst_monoscope_get_property;
188 gst_monoscope_init (GstMonoscope *monoscope)
190 /* create the sink and src pads */
191 monoscope->sinkpad = gst_pad_new_from_template (
192 GST_PADTEMPLATE_GET (sink_template ), "sink");
193 monoscope->srcpad = gst_pad_new_from_template (
194 GST_PADTEMPLATE_GET (src_template ), "src");
195 gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->sinkpad);
196 gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->srcpad);
198 gst_pad_set_chain_function (monoscope->sinkpad, gst_monoscope_chain);
199 gst_pad_set_connect_function (monoscope->sinkpad, gst_monoscope_sinkconnect);
201 monoscope->next_time = 0;
202 monoscope->peerpool = NULL;
204 // reset the initial video state
205 monoscope->first_buffer = TRUE;
206 monoscope->width = 256;
207 monoscope->height = 128;
208 monoscope->fps = 25; // desired frame rate
212 static GstPadConnectReturn
213 gst_monoscope_sinkconnect (GstPad *pad, GstCaps *caps)
215 GstMonoscope *monoscope;
216 monoscope = GST_MONOSCOPE (gst_pad_get_parent (pad));
218 if (!GST_CAPS_IS_FIXED (caps)) {
219 return GST_PAD_CONNECT_DELAYED;
222 return GST_PAD_CONNECT_OK;
226 gst_monoscope_chain (GstPad *pad, GstBuffer *bufin)
228 GstMonoscope *monoscope;
234 monoscope = GST_MONOSCOPE (gst_pad_get_parent (pad));
236 GST_DEBUG (0, "Monoscope: chainfunc called\n");
238 samples_in = GST_BUFFER_SIZE (bufin) / sizeof (gint16);
240 GST_DEBUG (0, "input buffer has %d samples\n", samples_in);
242 /* FIXME: should really select the first 1024 samples after the timestamp. */
243 if (GST_BUFFER_TIMESTAMP (bufin) < monoscope->next_time || samples_in < 1024) {
244 GST_DEBUG (0, "timestamp is %llu: want >= %llu\n", GST_BUFFER_TIMESTAMP (bufin), monoscope->next_time);
245 gst_buffer_unref (bufin);
249 data = (gint16 *) GST_BUFFER_DATA (bufin);
250 // FIXME: get rid of this: waste of effort.
251 for (i=0; i < 512; i++) {
252 monoscope->datain[i] = *data++;
255 if (monoscope->first_buffer) {
258 monoscope->visstate = monoscope_init (monoscope->width, monoscope->height);
259 g_assert(monoscope->visstate != 0);
260 GST_DEBUG (0, "making new pad\n");
262 caps = GST_CAPS_NEW (
265 "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")),
266 "bpp", GST_PROPS_INT (32),
267 "depth", GST_PROPS_INT (32),
268 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
269 "red_mask", GST_PROPS_INT (0xff0000),
270 "green_mask", GST_PROPS_INT (0x00ff00),
271 "blue_mask", GST_PROPS_INT (0x0000ff),
272 "width", GST_PROPS_INT (monoscope->width),
273 "height", GST_PROPS_INT (monoscope->height)
276 if (!gst_pad_try_set_caps (monoscope->srcpad, caps)) {
277 gst_element_error (GST_ELEMENT (monoscope), "could not set caps");
280 monoscope->first_buffer = FALSE;
283 bufout = gst_buffer_new ();
284 GST_BUFFER_SIZE (bufout) = monoscope->width * monoscope->height * 4;
285 GST_BUFFER_DATA (bufout) = (guchar *) monoscope_update (monoscope->visstate, monoscope->datain);
286 GST_BUFFER_TIMESTAMP (bufout) = monoscope->next_time;
287 GST_BUFFER_FLAG_SET (bufout, GST_BUFFER_DONTFREE);
289 monoscope->next_time += 1000000LL / monoscope->fps;
291 gst_pad_push (monoscope->srcpad, bufout);
293 gst_buffer_unref (bufin);
295 GST_DEBUG (0, "Monoscope: exiting chainfunc\n");
300 gst_monoscope_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
302 GstMonoscope *monoscope;
304 /* it's not null if we got it, but it might not be ours */
305 g_return_if_fail (GST_IS_MONOSCOPE (object));
306 monoscope = GST_MONOSCOPE (object);
310 monoscope->width = g_value_get_int (value);
313 monoscope->height = g_value_get_int (value);
316 monoscope->fps = g_value_get_int (value);
324 gst_monoscope_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
326 GstMonoscope *monoscope;
328 /* it's not null if we got it, but it might not be ours */
329 g_return_if_fail (GST_IS_MONOSCOPE (object));
330 monoscope = GST_MONOSCOPE (object);
334 g_value_set_int (value, monoscope->width);
337 g_value_set_int (value, monoscope->height);
340 g_value_set_int (value, monoscope->fps);
348 plugin_init (GModule *module, GstPlugin *plugin)
350 GstElementFactory *factory;
352 /* create an elementfactory for the monoscope element */
353 factory = gst_elementfactory_new("monoscope",GST_TYPE_MONOSCOPE,
354 &gst_monoscope_details);
355 g_return_val_if_fail(factory != NULL, FALSE);
357 gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_template));
358 gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_template));
360 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
365 GstPluginDesc plugin_desc = {