goom2k1: post QoS messages when dropping frames due to QoS
[platform/upstream/gst-plugins-good.git] / gst / goom2k1 / gstgoom.c
1 /* gstgoom.c: implementation of goom drawing element
2  * Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
3  *           (C) <2006> Wim Taymans <wim at fluendo dot com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * SECTION:element-goom2k1
23  * @see_also: goom, synaesthesia
24  *
25  * Goom2k1 is an audio visualisation element. It creates warping structures
26  * based on the incomming audio signal. Goom2k1 is the older version of the
27  * visualisation. Also available is goom2k4, with a different look.
28  *
29  * <refsect2>
30  * <title>Example launch line</title>
31  * |[
32  * gst-launch-1.0 -v audiotestsrc ! goom2k1 ! videoconvert ! xvimagesink
33  * ]|
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include <string.h>
42 #include <gst/gst.h>
43 #include "gstgoom.h"
44 #include <gst/video/video.h>
45 #include <gst/audio/audio.h>
46 #include "goom_core.h"
47
48 GST_DEBUG_CATEGORY_STATIC (goom_debug);
49 #define GST_CAT_DEFAULT goom_debug
50
51 #define DEFAULT_WIDTH  320
52 #define DEFAULT_HEIGHT 240
53 #define DEFAULT_FPS_N  25
54 #define DEFAULT_FPS_D  1
55
56 /* signals and args */
57 enum
58 {
59   /* FILL ME */
60   LAST_SIGNAL
61 };
62
63 enum
64 {
65   ARG_0
66       /* FILL ME */
67 };
68
69 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
70     GST_PAD_SRC,
71     GST_PAD_ALWAYS,
72 #if G_BYTE_ORDER == G_BIG_ENDIAN
73     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
74 #else
75     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
76 #endif
77     );
78
79 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",    /* the name of the pads */
80     GST_PAD_SINK,               /* type of the pad */
81     GST_PAD_ALWAYS,             /* ALWAYS/SOMETIMES */
82     GST_STATIC_CAPS ("audio/x-raw, "
83         "format = (string) " GST_AUDIO_NE (S16) ", "
84         "rate = (int) [ 8000, 96000 ], "
85         "channels = (int) 1, "
86         "layout = (string) interleaved; "
87         "audio/x-raw, "
88         "format = (string) " GST_AUDIO_NE (S16) ", "
89         "rate = (int) [ 8000, 96000 ], "
90         "channels = (int) 2, "
91         "channel-mask = (bitmask) 0x3, " "layout = (string) interleaved")
92     );
93
94 static void gst_goom_finalize (GObject * object);
95
96 static GstStateChangeReturn gst_goom_change_state (GstElement * element,
97     GstStateChange transition);
98
99 static GstFlowReturn gst_goom_chain (GstPad * pad, GstObject * parent,
100     GstBuffer * buffer);
101 static gboolean gst_goom_src_event (GstPad * pad, GstObject * parent,
102     GstEvent * event);
103 static gboolean gst_goom_sink_event (GstPad * pad, GstObject * parent,
104     GstEvent * event);
105
106 static gboolean gst_goom_src_query (GstPad * pad, GstObject * parent,
107     GstQuery * query);
108
109 static gboolean gst_goom_src_negotiate (GstGoom * goom);
110
111 #define gst_goom_parent_class parent_class
112 typedef GstGoom GstGoom2k1;
113 typedef GstGoomClass GstGoom2k1Class;
114 G_DEFINE_TYPE (GstGoom2k1, gst_goom, GST_TYPE_ELEMENT);
115
116 static void
117 gst_goom_class_init (GstGoomClass * klass)
118 {
119   GObjectClass *gobject_class;
120   GstElementClass *gstelement_class;
121
122   gobject_class = (GObjectClass *) klass;
123   gstelement_class = (GstElementClass *) klass;
124
125   parent_class = g_type_class_peek_parent (klass);
126
127   gobject_class->finalize = gst_goom_finalize;
128
129   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_goom_change_state);
130
131   gst_element_class_set_static_metadata (gstelement_class,
132       "GOOM: what a GOOM! 2k1 edition", "Visualization",
133       "Takes frames of data and outputs video frames using the GOOM 2k1 filter",
134       "Wim Taymans <wim@fluendo.com>");
135   gst_element_class_add_pad_template (gstelement_class,
136       gst_static_pad_template_get (&sink_template));
137   gst_element_class_add_pad_template (gstelement_class,
138       gst_static_pad_template_get (&src_template));
139
140   GST_DEBUG_CATEGORY_INIT (goom_debug, "goom", 0, "goom visualisation element");
141 }
142
143 static void
144 gst_goom_init (GstGoom * goom)
145 {
146   /* create the sink and src pads */
147   goom->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
148   gst_pad_set_chain_function (goom->sinkpad,
149       GST_DEBUG_FUNCPTR (gst_goom_chain));
150   gst_pad_set_event_function (goom->sinkpad,
151       GST_DEBUG_FUNCPTR (gst_goom_sink_event));
152   gst_element_add_pad (GST_ELEMENT (goom), goom->sinkpad);
153
154   goom->srcpad = gst_pad_new_from_static_template (&src_template, "src");
155   gst_pad_set_event_function (goom->srcpad,
156       GST_DEBUG_FUNCPTR (gst_goom_src_event));
157   gst_pad_set_query_function (goom->srcpad,
158       GST_DEBUG_FUNCPTR (gst_goom_src_query));
159   gst_element_add_pad (GST_ELEMENT (goom), goom->srcpad);
160
161   goom->adapter = gst_adapter_new ();
162
163   goom->width = DEFAULT_WIDTH;
164   goom->height = DEFAULT_HEIGHT;
165   goom->fps_n = DEFAULT_FPS_N;  /* desired frame rate */
166   goom->fps_d = DEFAULT_FPS_D;  /* desired frame rate */
167   goom->channels = 0;
168   goom->rate = 0;
169   goom->duration = 0;
170
171   goom_init (&(goom->goomdata), goom->width, goom->height);
172 }
173
174 static void
175 gst_goom_finalize (GObject * object)
176 {
177   GstGoom *goom = GST_GOOM (object);
178
179   goom_close (&(goom->goomdata));
180
181   g_object_unref (goom->adapter);
182
183   G_OBJECT_CLASS (parent_class)->finalize (object);
184 }
185
186 static void
187 gst_goom_reset (GstGoom * goom)
188 {
189   gst_adapter_clear (goom->adapter);
190   gst_segment_init (&goom->segment, GST_FORMAT_UNDEFINED);
191
192   GST_OBJECT_LOCK (goom);
193   goom->proportion = 1.0;
194   goom->earliest_time = GST_CLOCK_TIME_NONE;
195   GST_OBJECT_UNLOCK (goom);
196
197   goom->dropped = 0;
198   goom->processed = 0;
199 }
200
201 static gboolean
202 gst_goom_sink_setcaps (GstGoom * goom, GstCaps * caps)
203 {
204   GstStructure *structure;
205   gboolean res;
206
207   structure = gst_caps_get_structure (caps, 0);
208
209   res = gst_structure_get_int (structure, "channels", &goom->channels);
210   res &= gst_structure_get_int (structure, "rate", &goom->rate);
211   if (!res)
212     return FALSE;
213
214   goom->bps = goom->channels * sizeof (gint16);
215
216   return gst_goom_src_negotiate (goom);
217 }
218
219 static gboolean
220 gst_goom_src_setcaps (GstGoom * goom, GstCaps * caps)
221 {
222   GstStructure *structure;
223
224   structure = gst_caps_get_structure (caps, 0);
225
226   if (!gst_structure_get_int (structure, "width", &goom->width) ||
227       !gst_structure_get_int (structure, "height", &goom->height) ||
228       !gst_structure_get_fraction (structure, "framerate", &goom->fps_n,
229           &goom->fps_d))
230     goto error;
231
232   goom_set_resolution (&(goom->goomdata), goom->width, goom->height);
233
234   /* size of the output buffer in bytes, depth is always 4 bytes */
235   goom->outsize = goom->width * goom->height * 4;
236   goom->duration =
237       gst_util_uint64_scale_int (GST_SECOND, goom->fps_d, goom->fps_n);
238   goom->spf = gst_util_uint64_scale_int (goom->rate, goom->fps_d, goom->fps_n);
239   goom->bpf = goom->spf * goom->bps;
240
241   GST_DEBUG_OBJECT (goom, "dimension %dx%d, framerate %d/%d, spf %d",
242       goom->width, goom->height, goom->fps_n, goom->fps_d, goom->spf);
243
244   return gst_pad_set_caps (goom->srcpad, caps);
245
246   /* ERRORS */
247 error:
248   {
249     GST_DEBUG_OBJECT (goom, "error parsing caps");
250     return FALSE;
251   }
252 }
253
254 static gboolean
255 gst_goom_src_negotiate (GstGoom * goom)
256 {
257   GstCaps *othercaps, *target;
258   GstStructure *structure;
259   GstCaps *templ;
260   GstQuery *query;
261   GstBufferPool *pool = NULL;
262   GstStructure *config;
263   guint size, min, max;
264
265   templ = gst_pad_get_pad_template_caps (goom->srcpad);
266
267   GST_DEBUG_OBJECT (goom, "performing negotiation");
268
269   /* see what the peer can do */
270   othercaps = gst_pad_peer_query_caps (goom->srcpad, NULL);
271   if (othercaps) {
272     target = gst_caps_intersect (othercaps, templ);
273     gst_caps_unref (templ);
274     gst_caps_unref (othercaps);
275
276     if (gst_caps_is_empty (target))
277       goto no_format;
278
279     target = gst_caps_truncate (target);
280   } else {
281     target = gst_caps_copy (templ);
282   }
283
284   structure = gst_caps_get_structure (target, 0);
285   gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
286   gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT);
287   gst_structure_fixate_field_nearest_fraction (structure, "framerate",
288       DEFAULT_FPS_N, DEFAULT_FPS_D);
289
290   gst_goom_src_setcaps (goom, target);
291
292   /* find a pool for the negotiated caps now */
293   query = gst_query_new_allocation (target, TRUE);
294
295   if (!gst_pad_peer_query (goom->srcpad, query)) {
296     /* no problem, we use the query defaults */
297     GST_DEBUG_OBJECT (goom, "ALLOCATION query failed");
298   }
299
300   if (gst_query_get_n_allocation_pools (query) > 0) {
301     /* we got configuration from our peer, parse them */
302     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
303   } else {
304     pool = NULL;
305     size = goom->outsize;
306     min = max = 0;
307   }
308
309   if (pool == NULL) {
310     /* we did not get a pool, make one ourselves then */
311     pool = gst_buffer_pool_new ();
312   }
313
314   config = gst_buffer_pool_get_config (pool);
315   gst_buffer_pool_config_set_params (config, target, size, min, max);
316   gst_buffer_pool_set_config (pool, config);
317
318   if (goom->pool) {
319     gst_buffer_pool_set_active (goom->pool, FALSE);
320     gst_object_unref (goom->pool);
321   }
322   goom->pool = pool;
323
324   /* and activate */
325   gst_buffer_pool_set_active (pool, TRUE);
326
327   gst_caps_unref (target);
328
329   return TRUE;
330
331 no_format:
332   {
333     gst_caps_unref (target);
334     return FALSE;
335   }
336 }
337
338 static gboolean
339 gst_goom_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
340 {
341   gboolean res;
342   GstGoom *goom;
343
344   goom = GST_GOOM (parent);
345
346   switch (GST_EVENT_TYPE (event)) {
347     case GST_EVENT_QOS:
348     {
349       gdouble proportion;
350       GstClockTimeDiff diff;
351       GstClockTime timestamp;
352
353       gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
354
355       /* save stuff for the _chain() function */
356       GST_OBJECT_LOCK (goom);
357       goom->proportion = proportion;
358       if (diff >= 0)
359         /* we're late, this is a good estimate for next displayable
360          * frame (see part-qos.txt) */
361         goom->earliest_time = timestamp + 2 * diff + goom->duration;
362       else
363         goom->earliest_time = timestamp + diff;
364       GST_OBJECT_UNLOCK (goom);
365
366       res = gst_pad_event_default (pad, parent, event);
367       break;
368     }
369     default:
370       res = gst_pad_event_default (pad, parent, event);
371       break;
372   }
373
374   return res;
375 }
376
377 static gboolean
378 gst_goom_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
379 {
380   gboolean res;
381   GstGoom *goom;
382
383   goom = GST_GOOM (parent);
384
385   switch (GST_EVENT_TYPE (event)) {
386     case GST_EVENT_CAPS:
387     {
388       GstCaps *caps;
389
390       gst_event_parse_caps (event, &caps);
391       res = gst_goom_sink_setcaps (goom, caps);
392       gst_event_unref (event);
393       break;
394     }
395     case GST_EVENT_FLUSH_STOP:
396       gst_goom_reset (goom);
397       res = gst_pad_event_default (pad, parent, event);
398       break;
399     case GST_EVENT_SEGMENT:
400     {
401       /* the newsegment values are used to clip the input samples
402        * and to convert the incomming timestamps to running time so
403        * we can do QoS */
404       gst_event_copy_segment (event, &goom->segment);
405
406       res = gst_pad_event_default (pad, parent, event);
407       break;
408     }
409     default:
410       res = gst_pad_event_default (pad, parent, event);
411       break;
412   }
413
414   return res;
415 }
416
417 static gboolean
418 gst_goom_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
419 {
420   gboolean res;
421   GstGoom *goom;
422
423   goom = GST_GOOM (parent);
424
425   switch (GST_QUERY_TYPE (query)) {
426     case GST_QUERY_LATENCY:
427     {
428       /* We need to send the query upstream and add the returned latency to our
429        * own */
430       GstClockTime min_latency, max_latency;
431       gboolean us_live;
432       GstClockTime our_latency;
433       guint max_samples;
434
435       if ((res = gst_pad_peer_query (goom->sinkpad, query))) {
436         gst_query_parse_latency (query, &us_live, &min_latency, &max_latency);
437
438         GST_DEBUG_OBJECT (goom, "Peer latency: min %"
439             GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
440             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
441
442         /* the max samples we must buffer buffer */
443         max_samples = MAX (GOOM_SAMPLES, goom->spf);
444         our_latency =
445             gst_util_uint64_scale_int (max_samples, GST_SECOND, goom->rate);
446
447         GST_DEBUG_OBJECT (goom, "Our latency: %" GST_TIME_FORMAT,
448             GST_TIME_ARGS (our_latency));
449
450         /* we add some latency but only if we need to buffer more than what
451          * upstream gives us */
452         min_latency += our_latency;
453         if (max_latency != -1)
454           max_latency += our_latency;
455
456         GST_DEBUG_OBJECT (goom, "Calculated total latency : min %"
457             GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
458             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
459
460         gst_query_set_latency (query, TRUE, min_latency, max_latency);
461       }
462       break;
463     }
464     default:
465       res = gst_pad_query_default (pad, parent, query);
466       break;
467   }
468
469   return res;
470 }
471
472 /* make sure we are negotiated */
473 static GstFlowReturn
474 ensure_negotiated (GstGoom * goom)
475 {
476   if (gst_pad_check_reconfigure (goom->srcpad)) {
477     if (!gst_goom_src_negotiate (goom))
478       return GST_FLOW_NOT_NEGOTIATED;
479   }
480   return GST_FLOW_OK;
481 }
482
483 static GstFlowReturn
484 gst_goom_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
485 {
486   GstGoom *goom;
487   GstFlowReturn ret;
488   GstBuffer *outbuf = NULL;
489
490   goom = GST_GOOM (parent);
491
492   /* If we don't have an output format yet, preallocate a buffer to try and
493    * set one */
494   if (goom->bps == 0) {
495     gst_buffer_unref (buffer);
496     ret = GST_FLOW_NOT_NEGOTIATED;
497     goto beach;
498   }
499
500   /* Make sure have an output format */
501   ret = ensure_negotiated (goom);
502   if (ret != GST_FLOW_OK) {
503     gst_buffer_unref (buffer);
504     goto beach;
505   }
506
507   /* don't try to combine samples from discont buffer */
508   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
509     gst_adapter_clear (goom->adapter);
510   }
511
512   GST_DEBUG_OBJECT (goom,
513       "Input buffer has %" G_GSIZE_FORMAT " samples, time=%" G_GUINT64_FORMAT,
514       gst_buffer_get_size (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer));
515
516   /* Collect samples until we have enough for an output frame */
517   gst_adapter_push (goom->adapter, buffer);
518
519   ret = GST_FLOW_OK;
520
521   while (TRUE) {
522     const guint16 *data;
523     guchar *out_frame;
524     gint i;
525     guint avail, to_flush;
526     guint64 dist, timestamp;
527
528     avail = gst_adapter_available (goom->adapter);
529     GST_DEBUG_OBJECT (goom, "avail now %u", avail);
530
531     /* we need GOOM_SAMPLES to get a meaningful result from goom. */
532     if (avail < (GOOM_SAMPLES * goom->bps))
533       break;
534
535     /* we also need enough samples to produce one frame at least */
536     if (avail < goom->bpf)
537       break;
538
539     GST_DEBUG_OBJECT (goom, "processing buffer");
540
541     /* get timestamp of the current adapter byte */
542     timestamp = gst_adapter_prev_pts (goom->adapter, &dist);
543     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
544       /* convert bytes to time */
545       dist /= goom->bps;
546       timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, goom->rate);
547     }
548
549     /* check for QoS, don't compute buffers that are known to be late */
550     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
551       GstClockTime earliest_time;
552       gdouble proportion;
553       gint64 qostime;
554
555       qostime = gst_segment_to_running_time (&goom->segment, GST_FORMAT_TIME,
556           timestamp);
557       qostime += goom->duration;
558
559       GST_OBJECT_LOCK (goom);
560       earliest_time = goom->earliest_time;
561       proportion = goom->proportion;
562       GST_OBJECT_UNLOCK (goom);
563
564       if (GST_CLOCK_TIME_IS_VALID (earliest_time) && qostime <= earliest_time) {
565         GstClockTime stream_time, jitter;
566         GstMessage *qos_msg;
567
568         GST_DEBUG_OBJECT (goom,
569             "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
570             GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
571
572         ++goom->dropped;
573         stream_time = gst_segment_to_stream_time (&goom->segment,
574             GST_FORMAT_TIME, timestamp);
575         jitter = GST_CLOCK_DIFF (qostime, earliest_time);
576         qos_msg = gst_message_new_qos (GST_OBJECT (goom), FALSE, qostime,
577             stream_time, timestamp, GST_BUFFER_DURATION (buffer));
578         gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
579         gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
580             goom->processed, goom->dropped);
581         gst_element_post_message (GST_ELEMENT (goom), qos_msg);
582         goto skip;
583       }
584     }
585
586     ++goom->processed;
587
588     /* get next GOOM_SAMPLES, we have at least this amount of samples */
589     data =
590         (const guint16 *) gst_adapter_map (goom->adapter,
591         GOOM_SAMPLES * goom->bps);
592
593     if (goom->channels == 2) {
594       for (i = 0; i < GOOM_SAMPLES; i++) {
595         goom->datain[0][i] = *data++;
596         goom->datain[1][i] = *data++;
597       }
598     } else {
599       for (i = 0; i < GOOM_SAMPLES; i++) {
600         goom->datain[0][i] = *data;
601         goom->datain[1][i] = *data++;
602       }
603     }
604
605     /* alloc a buffer if we don't have one yet, this happens
606      * when we pushed a buffer in this while loop before */
607     if (outbuf == NULL) {
608       GST_DEBUG_OBJECT (goom, "allocating output buffer");
609       ret = gst_buffer_pool_acquire_buffer (goom->pool, &outbuf, NULL);
610       if (ret != GST_FLOW_OK) {
611         gst_adapter_unmap (goom->adapter);
612         goto beach;
613       }
614     }
615
616     GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
617     GST_BUFFER_DURATION (outbuf) = goom->duration;
618
619     out_frame = (guchar *) goom_update (&(goom->goomdata), goom->datain);
620     gst_buffer_fill (outbuf, 0, out_frame, goom->outsize);
621
622     gst_adapter_unmap (goom->adapter);
623
624     GST_DEBUG ("Pushing frame with time=%" GST_TIME_FORMAT ", duration=%"
625         GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
626         GST_TIME_ARGS (goom->duration));
627
628     ret = gst_pad_push (goom->srcpad, outbuf);
629     outbuf = NULL;
630
631   skip:
632     /* Now flush the samples we needed for this frame, which might be more than
633      * the samples we used (GOOM_SAMPLES). */
634     to_flush = goom->bpf;
635
636     GST_DEBUG_OBJECT (goom, "finished frame, flushing %u bytes from input",
637         to_flush);
638     gst_adapter_flush (goom->adapter, to_flush);
639
640     if (ret != GST_FLOW_OK)
641       break;
642   }
643
644   if (outbuf != NULL)
645     gst_buffer_unref (outbuf);
646
647 beach:
648
649   return ret;
650 }
651
652 static GstStateChangeReturn
653 gst_goom_change_state (GstElement * element, GstStateChange transition)
654 {
655   GstGoom *goom = GST_GOOM (element);
656   GstStateChangeReturn ret;
657
658   switch (transition) {
659     case GST_STATE_CHANGE_NULL_TO_READY:
660       break;
661     case GST_STATE_CHANGE_READY_TO_PAUSED:
662       gst_goom_reset (goom);
663       break;
664     default:
665       break;
666   }
667
668   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
669
670   switch (transition) {
671     case GST_STATE_CHANGE_PAUSED_TO_READY:
672       if (goom->pool) {
673         gst_buffer_pool_set_active (goom->pool, FALSE);
674         gst_object_replace ((GstObject **) & goom->pool, NULL);
675       }
676       break;
677     case GST_STATE_CHANGE_READY_TO_NULL:
678       break;
679     default:
680       break;
681   }
682
683   return ret;
684 }
685
686 static gboolean
687 plugin_init (GstPlugin * plugin)
688 {
689   return gst_element_register (plugin, "goom2k1", GST_RANK_NONE, GST_TYPE_GOOM);
690 }
691
692 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
693     GST_VERSION_MINOR,
694     goom2k1,
695     "GOOM 2k1 visualization filter",
696     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)