/GstBuffer/GstData/ in the API where you can pass events. Fix the plugins to deal...
[platform/upstream/gst-plugins-good.git] / gst / monoscope / gstmonoscope.c
1 /* gstmonoscope.c: implementation of monoscope drawing element
2  * Copyright (C) <2002> Richard Boulton <richard@tartarus.org>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <config.h>
24 #include <gst/gst.h>
25 #include <gst/video/video.h>
26 #include "monoscope.h"
27
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))
33
34 typedef struct _GstMonoscope GstMonoscope;
35 typedef struct _GstMonoscopeClass GstMonoscopeClass;
36
37 struct _GstMonoscope {
38   GstElement element;
39
40   /* pads */
41   GstPad *sinkpad,*srcpad;
42   GstBufferPool *peerpool;
43
44   /* the timestamp of the next frame */
45   guint64 next_time;
46   gint16 datain[512];
47
48   /* video state */
49   gfloat fps;
50   gint width;
51   gint height;
52   gboolean first_buffer;
53
54   /* visualisation state */
55   struct monoscope_state * visstate;
56 };
57
58 struct _GstMonoscopeClass {
59   GstElementClass parent_class;
60 };
61
62 GType gst_monoscope_get_type(void);
63
64
65 /* elementfactory information */
66 static GstElementDetails gst_monoscope_details = {
67   "Monoscope",
68   "Visualization",
69   "GPL",
70   "Displays a highly stabilised waveform of audio input",
71   VERSION,
72   "Richard Boulton <richard@tartarus.org>",
73   "(C) 2002",
74 };
75
76 /* signals and args */
77 enum {
78   /* FILL ME */
79   LAST_SIGNAL
80 };
81
82 enum {
83   ARG_0,
84   /* FILL ME */
85 };
86
87 GST_PAD_TEMPLATE_FACTORY (src_template,
88   "src",
89   GST_PAD_SRC,
90   GST_PAD_ALWAYS,
91   GST_CAPS_NEW (
92     "monoscopesrc",
93     "video/x-raw-rgb",
94       "bpp",            GST_PROPS_INT (32),
95       "depth",          GST_PROPS_INT (32),
96       "endianness",     GST_PROPS_INT (G_BIG_ENDIAN),
97       "red_mask",       GST_PROPS_INT (R_MASK_32),
98       "green_mask",     GST_PROPS_INT (G_MASK_32),
99       "blue_mask",      GST_PROPS_INT (B_MASK_32),
100       "width",          GST_PROPS_INT_RANGE (16, 4096),
101       "height",         GST_PROPS_INT_RANGE (16, 4096),
102       "framerate",      GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT)
103   )
104 )
105
106 GST_PAD_TEMPLATE_FACTORY (sink_template,
107   "sink",                                       /* the name of the pads */
108   GST_PAD_SINK,                         /* type of the pad */
109   GST_PAD_ALWAYS,                               /* ALWAYS/SOMETIMES */
110   GST_CAPS_NEW (
111     "monoscopesink",                            /* the name of the caps */
112     "audio/x-raw-int",                          /* the mime type of the caps */
113        /* Properties follow: */
114       "endianness", GST_PROPS_INT (G_BYTE_ORDER),
115       "signed",     GST_PROPS_BOOLEAN (TRUE),
116       "width",      GST_PROPS_INT (16),
117       "depth",      GST_PROPS_INT (16),
118       "rate",       GST_PROPS_INT_RANGE (8000, 96000),
119       "channels",   GST_PROPS_INT (1)
120   )
121 )
122
123
124 static void     gst_monoscope_class_init        (GstMonoscopeClass *klass);
125 static void     gst_monoscope_init              (GstMonoscope *monoscope);
126
127 static void     gst_monoscope_chain             (GstPad *pad, GstData *_data);
128
129 static GstPadLinkReturn 
130                 gst_monoscope_sinkconnect       (GstPad *pad, GstCaps *caps);
131 static GstPadLinkReturn
132                 gst_monoscope_srcconnect        (GstPad *pad, GstCaps *caps);
133
134 static GstElementClass *parent_class = NULL;
135
136 GType
137 gst_monoscope_get_type (void)
138 {
139   static GType type = 0;
140
141   if (!type) {
142     static const GTypeInfo info = {
143       sizeof (GstMonoscopeClass),      
144       NULL,      
145       NULL,      
146       (GClassInitFunc) gst_monoscope_class_init,
147       NULL,
148       NULL,
149       sizeof (GstMonoscope),
150       0,
151       (GInstanceInitFunc) gst_monoscope_init,
152     };
153     type = g_type_register_static (GST_TYPE_ELEMENT, "GstMonoscope", &info, 0);
154   }
155   return type;
156 }
157
158 static void
159 gst_monoscope_class_init(GstMonoscopeClass *klass)
160 {
161   GObjectClass *gobject_class;
162   GstElementClass *gstelement_class;
163
164   gobject_class = (GObjectClass*) klass;
165   gstelement_class = (GstElementClass*) klass;
166
167   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
168 }
169
170 static void
171 gst_monoscope_init (GstMonoscope *monoscope)
172 {
173   /* create the sink and src pads */
174   monoscope->sinkpad = gst_pad_new_from_template (
175                   GST_PAD_TEMPLATE_GET (sink_template ), "sink");
176   monoscope->srcpad = gst_pad_new_from_template (
177                   GST_PAD_TEMPLATE_GET (src_template ), "src");
178   gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->sinkpad);
179   gst_element_add_pad (GST_ELEMENT (monoscope), monoscope->srcpad);
180
181   gst_pad_set_chain_function (monoscope->sinkpad, gst_monoscope_chain);
182   gst_pad_set_link_function (monoscope->sinkpad, gst_monoscope_sinkconnect);
183   gst_pad_set_link_function (monoscope->srcpad, gst_monoscope_srcconnect);
184
185   monoscope->next_time = 0;
186   monoscope->peerpool = NULL;
187
188   /* reset the initial video state */
189   monoscope->first_buffer = TRUE;
190   monoscope->width = 256;
191   monoscope->height = 128;
192   monoscope->fps = 25.; /* desired frame rate */
193 }
194
195 static GstPadLinkReturn
196 gst_monoscope_sinkconnect (GstPad *pad, GstCaps *caps)
197 {
198   GstMonoscope *monoscope;
199   monoscope = GST_MONOSCOPE (gst_pad_get_parent (pad));
200
201   if (!GST_CAPS_IS_FIXED (caps)) {
202     return GST_PAD_LINK_DELAYED;
203   }
204
205   return GST_PAD_LINK_OK;
206 }
207
208 static GstPadLinkReturn
209 gst_monoscope_negotiate (GstMonoscope *monoscope)
210 {
211   GstCaps *caps;
212
213   caps = GST_CAPS_NEW (
214                      "monoscopesrc",
215                      "video/x-raw-rgb",
216                        "bpp",           GST_PROPS_INT (32), 
217                        "depth",         GST_PROPS_INT (32), 
218                        "endianness",    GST_PROPS_INT (G_BIG_ENDIAN), 
219                        "red_mask",      GST_PROPS_INT (R_MASK_32), 
220                        "green_mask",    GST_PROPS_INT (G_MASK_32), 
221                        "blue_mask",     GST_PROPS_INT (B_MASK_32), 
222                        "width",         GST_PROPS_INT (monoscope->width), 
223                        "height",        GST_PROPS_INT (monoscope->height),
224                "framerate",     GST_PROPS_FLOAT (monoscope->fps)
225                    );
226
227   return gst_pad_try_set_caps (monoscope->srcpad, caps);
228 }
229
230 static GstPadLinkReturn
231 gst_monoscope_srcconnect (GstPad *pad, GstCaps *caps)
232 {
233   GstPadLinkReturn ret;
234   GstMonoscope *monoscope = GST_MONOSCOPE (gst_pad_get_parent (pad));
235
236   if (gst_caps_has_property_typed (caps, "width", GST_PROPS_INT_TYPE)) {
237     gst_caps_get_int (caps, "width", &monoscope->width);
238   }
239   if (gst_caps_has_property_typed (caps, "height", GST_PROPS_INT_TYPE)) {
240     gst_caps_get_int (caps, "height", &monoscope->height);
241   }
242   if (gst_caps_has_property_typed (caps, "framerate", GST_PROPS_FLOAT_TYPE)) {
243     gst_caps_get_float (caps, "framerate", &monoscope->fps);
244   }
245
246   if ((ret = gst_monoscope_negotiate (monoscope)) <= 0)
247     return ret;
248
249   return GST_PAD_LINK_DONE;
250 }
251
252 static void
253 gst_monoscope_chain (GstPad *pad, GstData *_data)
254 {
255   GstBuffer *bufin = GST_BUFFER (_data);
256   GstMonoscope *monoscope;
257   GstBuffer *bufout;
258   guint32 samples_in;
259   gint16 *data;
260   gint i;
261
262   monoscope = GST_MONOSCOPE (gst_pad_get_parent (pad));
263
264   GST_DEBUG ("Monoscope: chainfunc called");
265
266   samples_in = GST_BUFFER_SIZE (bufin) / sizeof (gint16);
267
268   GST_DEBUG ("input buffer has %d samples", samples_in);
269
270   /* FIXME: should really select the first 1024 samples after the timestamp. */
271   if (GST_BUFFER_TIMESTAMP (bufin) < monoscope->next_time || samples_in < 1024) {
272     GST_DEBUG ("timestamp is %" G_GUINT64_FORMAT ": want >= %" G_GUINT64_FORMAT, GST_BUFFER_TIMESTAMP (bufin), monoscope->next_time);
273     gst_buffer_unref (bufin);
274     return;
275   }
276
277   data = (gint16 *) GST_BUFFER_DATA (bufin);
278   /* FIXME: Select samples in a better way. */
279   for (i=0; i < 512; i++) {
280     monoscope->datain[i] = *data++;
281   }
282
283   if (monoscope->first_buffer) {
284     monoscope->visstate = monoscope_init (monoscope->width, monoscope->height);
285     g_assert(monoscope->visstate != 0);
286     GST_DEBUG ("making new pad");
287     if (!GST_PAD_CAPS (monoscope->srcpad)) {
288       if (gst_monoscope_negotiate (monoscope) <= 0) {
289         gst_element_error (GST_ELEMENT (monoscope), "could not set caps");
290         return;
291       }
292     }
293     monoscope->first_buffer = FALSE;
294   }
295
296   bufout = gst_buffer_new ();
297   GST_BUFFER_SIZE (bufout) = monoscope->width * monoscope->height * 4;
298   GST_BUFFER_DATA (bufout) = (guchar *) monoscope_update (monoscope->visstate, monoscope->datain);
299   GST_BUFFER_TIMESTAMP (bufout) = monoscope->next_time;
300   GST_BUFFER_FLAG_SET (bufout, GST_BUFFER_DONTFREE);
301
302   monoscope->next_time += GST_SECOND / monoscope->fps;
303
304   gst_pad_push (monoscope->srcpad, GST_DATA (bufout));
305
306   gst_buffer_unref (bufin);
307
308   GST_DEBUG ("Monoscope: exiting chainfunc");
309
310 }
311
312 static gboolean
313 plugin_init (GModule *module, GstPlugin *plugin)
314 {
315   GstElementFactory *factory;
316
317   /* create an elementfactory for the monoscope element */
318   factory = gst_element_factory_new("monoscope",GST_TYPE_MONOSCOPE,
319                                    &gst_monoscope_details);
320   g_return_val_if_fail(factory != NULL, FALSE);
321
322   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_template));
323   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_template));
324
325   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
326
327   return TRUE;
328 }
329
330 GstPluginDesc plugin_desc = {
331   GST_VERSION_MAJOR,
332   GST_VERSION_MINOR,
333   "monoscope",
334   plugin_init
335 };