-base: port elements to new video caps
[platform/upstream/gstreamer.git] / ext / libvisual / visual.c
1 /* GStreamer
2  * Copyright (C) 2004 Benjamin Otte <otte@gnome.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
24 #include <gst/gst.h>
25 #include <gst/base/gstadapter.h>
26 #include <gst/video/video.h>
27 #include <gst/audio/audio.h>
28 #include <libvisual/libvisual.h>
29
30 #define GST_TYPE_VISUAL (gst_visual_get_type())
31 #define GST_IS_VISUAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VISUAL))
32 #define GST_VISUAL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VISUAL,GstVisual))
33 #define GST_IS_VISUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VISUAL))
34 #define GST_VISUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VISUAL,GstVisualClass))
35 #define GST_VISUAL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VISUAL, GstVisualClass))
36
37 typedef struct _GstVisual GstVisual;
38 typedef struct _GstVisualClass GstVisualClass;
39
40 GST_DEBUG_CATEGORY_STATIC (libvisual_debug);
41 #define GST_CAT_DEFAULT (libvisual_debug)
42
43 /* amounf of samples before we can feed libvisual */
44 #define VISUAL_SAMPLES  512
45
46 #define DEFAULT_WIDTH   320
47 #define DEFAULT_HEIGHT  240
48 #define DEFAULT_FPS_N   25
49 #define DEFAULT_FPS_D   1
50
51 struct _GstVisual
52 {
53   GstElement element;
54
55   /* pads */
56   GstPad *sinkpad;
57   GstPad *srcpad;
58   GstSegment segment;
59
60   /* libvisual stuff */
61   VisAudio *audio;
62   VisVideo *video;
63   VisActor *actor;
64
65   /* audio/video state */
66   gint channels;
67   gint rate;                    /* Input samplerate */
68   gint bps;
69
70   /* framerate numerator & denominator */
71   gint fps_n;
72   gint fps_d;
73   gint width;
74   gint height;
75   GstClockTime duration;
76   guint outsize;
77   GstBufferPool *pool;
78
79   /* samples per frame based on caps */
80   guint spf;
81
82   /* state stuff */
83   GstAdapter *adapter;
84   guint count;
85
86   /* QoS stuff *//* with LOCK */
87   gdouble proportion;
88   GstClockTime earliest_time;
89 };
90
91 struct _GstVisualClass
92 {
93   GstElementClass parent_class;
94
95   VisPluginRef *plugin;
96 };
97
98 GType gst_visual_get_type (void);
99
100
101 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
102     GST_PAD_SRC,
103     GST_PAD_ALWAYS,
104     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (" { "
105 #if G_BYTE_ORDER == G_BIG_ENDIAN
106             "\"xRGB\", " "\"RGB\", "
107 #else
108             "\"BGRx\", " "\"BGR\", "
109 #endif
110             "\"RGB16\" } "))
111     );
112
113 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
114     GST_PAD_SINK,
115     GST_PAD_ALWAYS,
116     GST_STATIC_CAPS ("audio/x-raw-int, "
117         "width = (int) 16, "
118         "depth = (int) 16, "
119         "endianness = (int) BYTE_ORDER, "
120         "signed = (boolean) TRUE, " "channels = (int) { 1, 2 }, "
121 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
122         "rate = (int) { 8000, 11250, 22500, 32000, 44100, 48000, 96000 }"
123 #else
124         "rate = (int) [ 1000, MAX ]"
125 #endif
126     )
127     );
128
129
130 static void gst_visual_class_init (gpointer g_class, gpointer class_data);
131 static void gst_visual_init (GstVisual * visual);
132 static void gst_visual_finalize (GObject * object);
133
134 static GstStateChangeReturn gst_visual_change_state (GstElement * element,
135     GstStateChange transition);
136 static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer);
137 static gboolean gst_visual_sink_event (GstPad * pad, GstEvent * event);
138 static gboolean gst_visual_src_event (GstPad * pad, GstEvent * event);
139
140 static gboolean gst_visual_src_query (GstPad * pad, GstQuery * query);
141
142 static gboolean gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps);
143 static GstCaps *gst_visual_getcaps (GstPad * pad, GstCaps * filter);
144 static void libvisual_log_handler (const char *message, const char *funcname,
145     void *priv);
146
147 static GstElementClass *parent_class = NULL;
148
149 GType
150 gst_visual_get_type (void)
151 {
152   static GType type = 0;
153
154   if (G_UNLIKELY (type == 0)) {
155     static const GTypeInfo info = {
156       sizeof (GstVisualClass),
157       NULL,
158       NULL,
159       gst_visual_class_init,
160       NULL,
161       NULL,
162       sizeof (GstVisual),
163       0,
164       (GInstanceInitFunc) gst_visual_init,
165     };
166
167     type = g_type_register_static (GST_TYPE_ELEMENT, "GstVisual", &info, 0);
168   }
169   return type;
170 }
171
172 static void
173 libvisual_log_handler (const char *message, const char *funcname, void *priv)
174 {
175   GST_CAT_LEVEL_LOG (libvisual_debug, (GstDebugLevel) (priv), NULL, "%s - %s",
176       funcname, message);
177 }
178
179 static void
180 gst_visual_class_init (gpointer g_class, gpointer class_data)
181 {
182   GstVisualClass *klass = GST_VISUAL_CLASS (g_class);
183   GstElementClass *element = GST_ELEMENT_CLASS (g_class);
184   GObjectClass *object = G_OBJECT_CLASS (g_class);
185
186   klass->plugin = class_data;
187
188   element->change_state = gst_visual_change_state;
189
190   if (class_data == NULL) {
191     parent_class = g_type_class_peek_parent (g_class);
192   } else {
193     char *longname = g_strdup_printf ("libvisual %s plugin v.%s",
194         klass->plugin->info->name, klass->plugin->info->version);
195
196     /* FIXME: improve to only register what plugin supports? */
197     gst_element_class_add_pad_template (element,
198         gst_static_pad_template_get (&src_template));
199     gst_element_class_add_pad_template (element,
200         gst_static_pad_template_get (&sink_template));
201
202     gst_element_class_set_details_simple (element,
203         longname, "Visualization",
204         klass->plugin->info->about, "Benjamin Otte <otte@gnome.org>");
205
206     g_free (longname);
207   }
208
209   object->finalize = gst_visual_finalize;
210 }
211
212 static void
213 gst_visual_init (GstVisual * visual)
214 {
215   /* create the sink and src pads */
216   visual->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
217   gst_pad_set_chain_function (visual->sinkpad, gst_visual_chain);
218   gst_pad_set_event_function (visual->sinkpad, gst_visual_sink_event);
219   gst_element_add_pad (GST_ELEMENT (visual), visual->sinkpad);
220
221   visual->srcpad = gst_pad_new_from_static_template (&src_template, "src");
222   gst_pad_set_getcaps_function (visual->srcpad, gst_visual_getcaps);
223   gst_pad_set_event_function (visual->srcpad, gst_visual_src_event);
224   gst_pad_set_query_function (visual->srcpad, gst_visual_src_query);
225   gst_element_add_pad (GST_ELEMENT (visual), visual->srcpad);
226
227   visual->adapter = gst_adapter_new ();
228 }
229
230 static void
231 gst_visual_clear_actors (GstVisual * visual)
232 {
233   if (visual->actor) {
234     visual_object_unref (VISUAL_OBJECT (visual->actor));
235     visual->actor = NULL;
236   }
237   if (visual->video) {
238     visual_object_unref (VISUAL_OBJECT (visual->video));
239     visual->video = NULL;
240   }
241   if (visual->audio) {
242     visual_object_unref (VISUAL_OBJECT (visual->audio));
243     visual->audio = NULL;
244   }
245 }
246
247 static void
248 gst_visual_finalize (GObject * object)
249 {
250   GstVisual *visual = GST_VISUAL (object);
251
252   g_object_unref (visual->adapter);
253   if (visual->pool)
254     gst_object_unref (visual->pool);
255   gst_visual_clear_actors (visual);
256
257   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
258 }
259
260 static void
261 gst_visual_reset (GstVisual * visual)
262 {
263   gst_adapter_clear (visual->adapter);
264   gst_segment_init (&visual->segment, GST_FORMAT_UNDEFINED);
265
266   GST_OBJECT_LOCK (visual);
267   visual->proportion = 1.0;
268   visual->earliest_time = -1;
269   GST_OBJECT_UNLOCK (visual);
270 }
271
272 static GstCaps *
273 gst_visual_getcaps (GstPad * pad, GstCaps * filter)
274 {
275   GstCaps *ret;
276   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
277   int depths;
278
279   if (!visual->actor) {
280     ret = gst_pad_get_pad_template_caps (visual->srcpad);
281     goto beach;
282   }
283
284   ret = gst_caps_new_empty ();
285   depths = visual_actor_get_supported_depth (visual->actor);
286   if (depths < 0) {
287     /* FIXME: set an error */
288     goto beach;
289   }
290   if (depths == VISUAL_VIDEO_DEPTH_GL) {
291     /* We can't handle GL only plugins */
292     goto beach;
293   }
294
295   GST_DEBUG_OBJECT (visual, "libvisual plugin supports depths %u (0x%04x)",
296       depths, depths);
297   /* if (depths & VISUAL_VIDEO_DEPTH_32BIT) Always supports 32bit output */
298 #if G_BYTE_ORDER == G_BIG_ENDIAN
299   gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("xRGB")));
300 #else
301   gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("BGRx")));
302 #endif
303
304   if (depths & VISUAL_VIDEO_DEPTH_24BIT) {
305 #if G_BYTE_ORDER == G_BIG_ENDIAN
306     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("RGB")));
307 #else
308     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("BGR")));
309 #endif
310   }
311   if (depths & VISUAL_VIDEO_DEPTH_16BIT) {
312     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("RGB16")));
313   }
314
315 beach:
316
317   if (filter) {
318     GstCaps *intersection;
319
320     intersection =
321         gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
322     gst_caps_unref (ret);
323     ret = intersection;
324   }
325
326   GST_DEBUG_OBJECT (visual, "returning caps %" GST_PTR_FORMAT, ret);
327   gst_object_unref (visual);
328   return ret;
329 }
330
331 static gboolean
332 gst_visual_src_setcaps (GstVisual * visual, GstCaps * caps)
333 {
334   gboolean res;
335   GstStructure *structure;
336   gint depth, pitch;
337   const gchar *fmt;
338
339   structure = gst_caps_get_structure (caps, 0);
340
341   GST_DEBUG_OBJECT (visual, "src pad got caps %" GST_PTR_FORMAT, caps);
342
343   if (!gst_structure_get_int (structure, "width", &visual->width))
344     goto error;
345   if (!gst_structure_get_int (structure, "height", &visual->height))
346     goto error;
347   if (!(fmt = gst_structure_get_string (structure, "format")))
348     goto error;
349   if (!gst_structure_get_fraction (structure, "framerate", &visual->fps_n,
350           &visual->fps_d))
351     goto error;
352
353   if (!strcmp (fmt, "BGR") || !strcmp (fmt, "RGB"))
354     depth = 24;
355   else if (!strcmp (fmt, "BGRx") || !strcmp (fmt, "xRGB"))
356     depth = 32;
357   else
358     depth = 16;
359
360   visual_video_set_depth (visual->video,
361       visual_video_depth_enum_from_value (depth));
362   visual_video_set_dimension (visual->video, visual->width, visual->height);
363   pitch = GST_ROUND_UP_4 (visual->width * visual->video->bpp);
364   visual_video_set_pitch (visual->video, pitch);
365   visual_actor_video_negotiate (visual->actor, 0, FALSE, FALSE);
366
367   /* precalc some values */
368   visual->outsize = visual->video->height * pitch;
369   visual->spf =
370       gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
371   visual->duration =
372       gst_util_uint64_scale_int (GST_SECOND, visual->fps_d, visual->fps_n);
373
374   res = gst_pad_push_event (visual->srcpad, gst_event_new_caps (caps));
375
376   return res;
377
378   /* ERRORS */
379 error:
380   {
381     GST_DEBUG_OBJECT (visual, "error parsing caps");
382     return FALSE;
383   }
384 }
385
386 static gboolean
387 gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps)
388 {
389   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
390   GstStructure *structure;
391
392   structure = gst_caps_get_structure (caps, 0);
393
394   gst_structure_get_int (structure, "channels", &visual->channels);
395   gst_structure_get_int (structure, "rate", &visual->rate);
396
397   /* this is how many samples we need to fill one frame at the requested
398    * framerate. */
399   if (visual->fps_n != 0) {
400     visual->spf =
401         gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
402   }
403   visual->bps = visual->channels * sizeof (gint16);
404
405   gst_object_unref (visual);
406   return TRUE;
407 }
408
409 static gboolean
410 gst_vis_src_negotiate (GstVisual * visual)
411 {
412   GstCaps *othercaps, *target;
413   GstStructure *structure;
414   GstCaps *caps;
415   GstQuery *query;
416   GstBufferPool *pool = NULL;
417   guint size, min, max, prefix, alignment;
418
419   caps = gst_pad_get_caps (visual->srcpad, NULL);
420
421   /* see what the peer can do */
422   othercaps = gst_pad_peer_get_caps (visual->srcpad, caps);
423   if (othercaps) {
424     target = othercaps;
425     gst_caps_unref (caps);
426
427     if (gst_caps_is_empty (target))
428       goto no_format;
429
430     target = gst_caps_make_writable (target);
431     gst_caps_truncate (target);
432   } else {
433     /* need a copy, we'll be modifying it when fixating */
434     target = gst_caps_copy (caps);
435     gst_caps_unref (caps);
436   }
437   GST_DEBUG_OBJECT (visual, "before fixate caps %" GST_PTR_FORMAT, target);
438
439   /* fixate in case something is not fixed. This does nothing if the value is
440    * already fixed. For video we always try to fixate to something like
441    * 320x240x25 by convention. */
442   structure = gst_caps_get_structure (target, 0);
443   gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
444   gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
445   gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT);
446   gst_structure_fixate_field_nearest_fraction (structure, "framerate",
447       DEFAULT_FPS_N, DEFAULT_FPS_D);
448
449   gst_pad_fixate_caps (visual->srcpad, target);
450
451   GST_DEBUG_OBJECT (visual, "after fixate caps %" GST_PTR_FORMAT, target);
452
453   gst_visual_src_setcaps (visual, target);
454
455   /* try to get a bufferpool now */
456   /* find a pool for the negotiated caps now */
457   query = gst_query_new_allocation (target, TRUE);
458
459   if (gst_pad_peer_query (visual->srcpad, query)) {
460     /* we got configuration from our peer, parse them */
461     gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
462         &alignment, &pool);
463   } else {
464     size = visual->outsize;
465     min = max = 0;
466     prefix = 0;
467     alignment = 0;
468   }
469
470   if (pool == NULL) {
471     GstStructure *config;
472
473     /* we did not get a pool, make one ourselves then */
474     pool = gst_buffer_pool_new ();
475
476     config = gst_buffer_pool_get_config (pool);
477     gst_buffer_pool_config_set (config, target, size, min, max, prefix,
478         alignment);
479     gst_buffer_pool_set_config (pool, config);
480   }
481
482   if (visual->pool)
483     gst_object_unref (visual->pool);
484   visual->pool = pool;
485
486   /* and activate */
487   gst_buffer_pool_set_active (pool, TRUE);
488
489   gst_caps_unref (target);
490
491   return TRUE;
492
493   /* ERRORS */
494 no_format:
495   {
496     GST_ELEMENT_ERROR (visual, STREAM, FORMAT, (NULL),
497         ("could not negotiate output format"));
498     gst_caps_unref (target);
499     return FALSE;
500   }
501 }
502
503 static gboolean
504 gst_visual_sink_event (GstPad * pad, GstEvent * event)
505 {
506   GstVisual *visual;
507   gboolean res;
508
509   visual = GST_VISUAL (gst_pad_get_parent (pad));
510
511   switch (GST_EVENT_TYPE (event)) {
512     case GST_EVENT_FLUSH_START:
513       res = gst_pad_push_event (visual->srcpad, event);
514       break;
515     case GST_EVENT_FLUSH_STOP:
516       /* reset QoS and adapter. */
517       gst_visual_reset (visual);
518       res = gst_pad_push_event (visual->srcpad, event);
519       break;
520     case GST_EVENT_CAPS:
521     {
522       GstCaps *caps;
523
524       gst_event_parse_caps (event, &caps);
525       res = gst_visual_sink_setcaps (pad, caps);
526       gst_event_unref (event);
527       break;
528     }
529     case GST_EVENT_SEGMENT:
530     {
531       /* the newsegment values are used to clip the input samples
532        * and to convert the incomming timestamps to running time so
533        * we can do QoS */
534       gst_event_copy_segment (event, &visual->segment);
535
536       /* and forward */
537       res = gst_pad_push_event (visual->srcpad, event);
538       break;
539     }
540     default:
541       res = gst_pad_event_default (pad, event);
542       break;
543   }
544
545   gst_object_unref (visual);
546   return res;
547 }
548
549 static gboolean
550 gst_visual_src_event (GstPad * pad, GstEvent * event)
551 {
552   GstVisual *visual;
553   gboolean res;
554
555   visual = GST_VISUAL (gst_pad_get_parent (pad));
556
557   switch (GST_EVENT_TYPE (event)) {
558     case GST_EVENT_QOS:
559     {
560       gdouble proportion;
561       GstClockTimeDiff diff;
562       GstClockTime timestamp;
563
564       gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
565
566       /* save stuff for the _chain function */
567       GST_OBJECT_LOCK (visual);
568       visual->proportion = proportion;
569       if (diff >= 0)
570         /* we're late, this is a good estimate for next displayable
571          * frame (see part-qos.txt) */
572         visual->earliest_time = timestamp + 2 * diff + visual->duration;
573       else
574         visual->earliest_time = timestamp + diff;
575
576       GST_OBJECT_UNLOCK (visual);
577
578       res = gst_pad_push_event (visual->sinkpad, event);
579       break;
580     }
581     case GST_EVENT_RECONFIGURE:
582       /* dont't forward */
583       gst_event_unref (event);
584       res = TRUE;
585       break;
586     default:
587       res = gst_pad_event_default (pad, event);
588       break;
589   }
590
591   gst_object_unref (visual);
592   return res;
593 }
594
595 static gboolean
596 gst_visual_src_query (GstPad * pad, GstQuery * query)
597 {
598   gboolean res;
599   GstVisual *visual;
600
601   visual = GST_VISUAL (gst_pad_get_parent (pad));
602
603   switch (GST_QUERY_TYPE (query)) {
604     case GST_QUERY_LATENCY:
605     {
606       /* We need to send the query upstream and add the returned latency to our
607        * own */
608       GstClockTime min_latency, max_latency;
609       gboolean us_live;
610       GstClockTime our_latency;
611       guint max_samples;
612
613       if ((res = gst_pad_peer_query (visual->sinkpad, query))) {
614         gst_query_parse_latency (query, &us_live, &min_latency, &max_latency);
615
616         GST_DEBUG_OBJECT (visual, "Peer latency: min %"
617             GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
618             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
619
620         /* the max samples we must buffer buffer */
621         max_samples = MAX (VISUAL_SAMPLES, visual->spf);
622         our_latency =
623             gst_util_uint64_scale_int (max_samples, GST_SECOND, visual->rate);
624
625         GST_DEBUG_OBJECT (visual, "Our latency: %" GST_TIME_FORMAT,
626             GST_TIME_ARGS (our_latency));
627
628         /* we add some latency but only if we need to buffer more than what
629          * upstream gives us */
630         min_latency += our_latency;
631         if (max_latency != -1)
632           max_latency += our_latency;
633
634         GST_DEBUG_OBJECT (visual, "Calculated total latency : min %"
635             GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
636             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
637
638         gst_query_set_latency (query, TRUE, min_latency, max_latency);
639       }
640       break;
641     }
642     default:
643       res = gst_pad_peer_query (visual->sinkpad, query);
644       break;
645   }
646
647   gst_object_unref (visual);
648
649   return res;
650 }
651
652 /* Make sure we are negotiated */
653 static GstFlowReturn
654 ensure_negotiated (GstVisual * visual)
655 {
656   gboolean reconfigure;
657
658   GST_OBJECT_LOCK (visual->srcpad);
659   reconfigure = GST_PAD_NEEDS_RECONFIGURE (visual->srcpad);
660   GST_OBJECT_FLAG_UNSET (visual->srcpad, GST_PAD_NEED_RECONFIGURE);
661   GST_OBJECT_UNLOCK (visual->srcpad);
662
663   /* we don't know an output format yet, pick one */
664   if (reconfigure || !gst_pad_has_current_caps (visual->srcpad)) {
665     if (!gst_vis_src_negotiate (visual))
666       return GST_FLOW_NOT_NEGOTIATED;
667   }
668   return GST_FLOW_OK;
669 }
670
671 static GstFlowReturn
672 gst_visual_chain (GstPad * pad, GstBuffer * buffer)
673 {
674   GstBuffer *outbuf = NULL;
675   guint i;
676   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
677   GstFlowReturn ret = GST_FLOW_OK;
678   guint avail;
679
680   GST_DEBUG_OBJECT (visual, "chain function called");
681
682   /* Make sure have an output format */
683   ret = ensure_negotiated (visual);
684   if (ret != GST_FLOW_OK) {
685     gst_buffer_unref (buffer);
686     goto beach;
687   }
688
689   /* resync on DISCONT */
690   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
691     gst_adapter_clear (visual->adapter);
692   }
693
694   GST_DEBUG_OBJECT (visual,
695       "Input buffer has %d samples, time=%" G_GUINT64_FORMAT,
696       gst_buffer_get_size (buffer) / visual->bps,
697       GST_BUFFER_TIMESTAMP (buffer));
698
699   gst_adapter_push (visual->adapter, buffer);
700
701   while (TRUE) {
702     gboolean need_skip;
703     const guint16 *data;
704     guint64 dist, timestamp;
705     guint8 *outdata;
706     gsize outsize;
707
708     GST_DEBUG_OBJECT (visual, "processing buffer");
709
710     avail = gst_adapter_available (visual->adapter);
711     GST_DEBUG_OBJECT (visual, "avail now %u", avail);
712
713     /* we need at least VISUAL_SAMPLES samples */
714     if (avail < VISUAL_SAMPLES * visual->bps)
715       break;
716
717     /* we need at least enough samples to make one frame */
718     if (avail < visual->spf * visual->bps)
719       break;
720
721     /* get timestamp of the current adapter byte */
722     timestamp = gst_adapter_prev_timestamp (visual->adapter, &dist);
723     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
724       /* convert bytes to time */
725       dist /= visual->bps;
726       timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, visual->rate);
727     }
728
729     if (timestamp != -1) {
730       gint64 qostime;
731
732       /* QoS is done on running time */
733       qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME,
734           timestamp);
735       qostime += visual->duration;
736
737       GST_OBJECT_LOCK (visual);
738       /* check for QoS, don't compute buffers that are known to be late */
739       need_skip = visual->earliest_time != -1 &&
740           qostime <= visual->earliest_time;
741       GST_OBJECT_UNLOCK (visual);
742
743       if (need_skip) {
744         GST_WARNING_OBJECT (visual,
745             "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
746             GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time));
747         goto skip;
748       }
749     }
750
751     /* Read VISUAL_SAMPLES samples per channel */
752     data =
753         (const guint16 *) gst_adapter_map (visual->adapter,
754         VISUAL_SAMPLES * visual->bps);
755
756 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
757     {
758       VisBuffer *lbuf, *rbuf;
759       guint16 ldata[VISUAL_SAMPLES], rdata[VISUAL_SAMPLES];
760       VisAudioSampleRateType rate;
761
762       lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL);
763       rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL);
764
765       if (visual->channels == 2) {
766         for (i = 0; i < VISUAL_SAMPLES; i++) {
767           ldata[i] = *data++;
768           rdata[i] = *data++;
769         }
770       } else {
771         for (i = 0; i < VISUAL_SAMPLES; i++) {
772           ldata[i] = *data;
773           rdata[i] = *data++;
774         }
775       }
776
777       switch (visual->rate) {
778         case 8000:
779           rate = VISUAL_AUDIO_SAMPLE_RATE_8000;
780           break;
781         case 11250:
782           rate = VISUAL_AUDIO_SAMPLE_RATE_11250;
783           break;
784         case 22500:
785           rate = VISUAL_AUDIO_SAMPLE_RATE_22500;
786           break;
787         case 32000:
788           rate = VISUAL_AUDIO_SAMPLE_RATE_32000;
789           break;
790         case 44100:
791           rate = VISUAL_AUDIO_SAMPLE_RATE_44100;
792           break;
793         case 48000:
794           rate = VISUAL_AUDIO_SAMPLE_RATE_48000;
795           break;
796         case 96000:
797           rate = VISUAL_AUDIO_SAMPLE_RATE_96000;
798           break;
799         default:
800           visual_object_unref (VISUAL_OBJECT (lbuf));
801           visual_object_unref (VISUAL_OBJECT (rbuf));
802           GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate);
803           ret = GST_FLOW_ERROR;
804           goto beach;
805           break;
806       }
807
808       visual_audio_samplepool_input_channel (visual->audio->samplepool,
809           lbuf,
810           rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16,
811           (char *) VISUAL_AUDIO_CHANNEL_LEFT);
812       visual_audio_samplepool_input_channel (visual->audio->samplepool, rbuf,
813           rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16,
814           (char *) VISUAL_AUDIO_CHANNEL_RIGHT);
815
816       visual_object_unref (VISUAL_OBJECT (lbuf));
817       visual_object_unref (VISUAL_OBJECT (rbuf));
818
819     }
820 #else
821     if (visual->channels == 2) {
822       for (i = 0; i < VISUAL_SAMPLES; i++) {
823         visual->audio->plugpcm[0][i] = *data++;
824         visual->audio->plugpcm[1][i] = *data++;
825       }
826     } else {
827       for (i = 0; i < VISUAL_SAMPLES; i++) {
828         visual->audio->plugpcm[0][i] = *data;
829         visual->audio->plugpcm[1][i] = *data++;
830       }
831     }
832 #endif
833
834     /* alloc a buffer if we don't have one yet, this happens
835      * when we pushed a buffer in this while loop before */
836     if (outbuf == NULL) {
837       GST_DEBUG_OBJECT (visual, "allocating output buffer");
838       ret = gst_buffer_pool_acquire_buffer (visual->pool, &outbuf, NULL);
839       if (ret != GST_FLOW_OK) {
840         gst_adapter_unmap (visual->adapter, 0);
841         goto beach;
842       }
843     }
844     outdata = gst_buffer_map (outbuf, &outsize, NULL, GST_MAP_WRITE);
845     visual_video_set_buffer (visual->video, outdata);
846     visual_audio_analyze (visual->audio);
847     visual_actor_run (visual->actor, visual->audio);
848     visual_video_set_buffer (visual->video, NULL);
849     gst_buffer_unmap (outbuf, outdata, outsize);
850     GST_DEBUG_OBJECT (visual, "rendered one frame");
851
852     gst_adapter_unmap (visual->adapter, 0);
853
854     GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
855     GST_BUFFER_DURATION (outbuf) = visual->duration;
856
857     ret = gst_pad_push (visual->srcpad, outbuf);
858     outbuf = NULL;
859
860   skip:
861     GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input",
862         visual->spf);
863
864     /* Flush out the number of samples per frame */
865     gst_adapter_flush (visual->adapter, visual->spf * visual->bps);
866
867     /* quit the loop if something was wrong */
868     if (ret != GST_FLOW_OK)
869       break;
870   }
871
872 beach:
873
874   if (outbuf != NULL)
875     gst_buffer_unref (outbuf);
876
877   gst_object_unref (visual);
878
879   return ret;
880 }
881
882 static GstStateChangeReturn
883 gst_visual_change_state (GstElement * element, GstStateChange transition)
884 {
885   GstVisual *visual = GST_VISUAL (element);
886   GstStateChangeReturn ret;
887
888   switch (transition) {
889     case GST_STATE_CHANGE_NULL_TO_READY:
890       visual->actor =
891           visual_actor_new (GST_VISUAL_GET_CLASS (visual)->plugin->
892           info->plugname);
893       visual->video = visual_video_new ();
894       visual->audio = visual_audio_new ();
895       /* can't have a play without actors */
896       if (!visual->actor || !visual->video)
897         goto no_actors;
898
899       if (visual_actor_realize (visual->actor) != 0)
900         goto no_realize;
901
902       visual_actor_set_video (visual->actor, visual->video);
903       break;
904     case GST_STATE_CHANGE_READY_TO_PAUSED:
905       gst_visual_reset (visual);
906       break;
907     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
908       break;
909     default:
910       break;
911   }
912
913   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
914
915   switch (transition) {
916     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
917       break;
918     case GST_STATE_CHANGE_PAUSED_TO_READY:
919       if (visual->pool) {
920         gst_buffer_pool_set_active (visual->pool, FALSE);
921         gst_object_unref (visual->pool);
922         visual->pool = NULL;
923       }
924       break;
925     case GST_STATE_CHANGE_READY_TO_NULL:
926       gst_visual_clear_actors (visual);
927       break;
928     default:
929       break;
930   }
931
932   return ret;
933
934   /* ERRORS */
935 no_actors:
936   {
937     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
938         ("could not create actors"));
939     gst_visual_clear_actors (visual);
940     return GST_STATE_CHANGE_FAILURE;
941   }
942 no_realize:
943   {
944     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
945         ("could not realize actor"));
946     gst_visual_clear_actors (visual);
947     return GST_STATE_CHANGE_FAILURE;
948   }
949 }
950
951 static void
952 make_valid_name (char *name)
953 {
954   /*
955    * Replace invalid chars with _ in the type name
956    */
957   static const gchar extra_chars[] = "-_+";
958   gchar *p = name;
959
960   for (; *p; p++) {
961     int valid = ((p[0] >= 'A' && p[0] <= 'Z') ||
962         (p[0] >= 'a' && p[0] <= 'z') ||
963         (p[0] >= '0' && p[0] <= '9') || strchr (extra_chars, p[0]));
964     if (!valid)
965       *p = '_';
966   }
967 }
968
969 static gboolean
970 gst_visual_actor_plugin_is_gl (VisObject * plugin, const gchar * name)
971 {
972   gboolean is_gl;
973   gint depth;
974
975 #if !defined(VISUAL_API_VERSION)
976
977   depth = VISUAL_PLUGIN_ACTOR (plugin)->depth;
978   is_gl = (depth == VISUAL_VIDEO_DEPTH_GL);
979
980 #elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
981
982   depth = VISUAL_ACTOR_PLUGIN (plugin)->vidoptions.depth;
983   /* FIXME: how to figure this out correctly in 0.4? */
984   is_gl = (depth & VISUAL_VIDEO_DEPTH_GL) == VISUAL_VIDEO_DEPTH_GL;
985
986 #else
987 # error what libvisual version is this?
988 #endif
989
990   if (!is_gl) {
991     GST_DEBUG ("plugin %s is not a GL plugin (%d), registering", name, depth);
992   } else {
993     GST_DEBUG ("plugin %s is a GL plugin (%d), ignoring", name, depth);
994   }
995
996   return is_gl;
997 }
998
999 static gboolean
1000 plugin_init (GstPlugin * plugin)
1001 {
1002   guint i, count;
1003   VisList *list;
1004
1005   GST_DEBUG_CATEGORY_INIT (libvisual_debug, "libvisual", 0,
1006       "libvisual audio visualisations");
1007
1008 #ifdef LIBVISUAL_PLUGINSBASEDIR
1009   gst_plugin_add_dependency_simple (plugin, "HOME/.libvisual/actor",
1010       LIBVISUAL_PLUGINSBASEDIR "/actor", NULL, GST_PLUGIN_DEPENDENCY_FLAG_NONE);
1011 #endif
1012
1013   visual_log_set_verboseness (VISUAL_LOG_VERBOSENESS_LOW);
1014   visual_log_set_info_handler (libvisual_log_handler, (void *) GST_LEVEL_INFO);
1015   visual_log_set_warning_handler (libvisual_log_handler,
1016       (void *) GST_LEVEL_WARNING);
1017   visual_log_set_critical_handler (libvisual_log_handler,
1018       (void *) GST_LEVEL_ERROR);
1019   visual_log_set_error_handler (libvisual_log_handler,
1020       (void *) GST_LEVEL_ERROR);
1021
1022   if (!visual_is_initialized ())
1023     if (visual_init (NULL, NULL) != 0)
1024       return FALSE;
1025
1026   list = visual_actor_get_list ();
1027
1028 #if !defined(VISUAL_API_VERSION)
1029   count = visual_list_count (list);
1030 #elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
1031   count = visual_collection_size (VISUAL_COLLECTION (list));
1032 #endif
1033
1034   for (i = 0; i < count; i++) {
1035     VisPluginRef *ref = visual_list_get (list, i);
1036     VisPluginData *visplugin = NULL;
1037     gboolean skip = FALSE;
1038     GType type;
1039     gchar *name;
1040     GTypeInfo info = {
1041       sizeof (GstVisualClass),
1042       NULL,
1043       NULL,
1044       gst_visual_class_init,
1045       NULL,
1046       ref,
1047       sizeof (GstVisual),
1048       0,
1049       NULL
1050     };
1051
1052     visplugin = visual_plugin_load (ref);
1053
1054     if (ref->info->plugname == NULL)
1055       continue;
1056
1057     /* Blacklist some plugins */
1058     if (strcmp (ref->info->plugname, "gstreamer") == 0 ||
1059         strcmp (ref->info->plugname, "gdkpixbuf") == 0) {
1060       skip = TRUE;
1061     } else {
1062       /* Ignore plugins that only support GL output for now */
1063       skip = gst_visual_actor_plugin_is_gl (visplugin->info->plugin,
1064           visplugin->info->plugname);
1065     }
1066
1067     visual_plugin_unload (visplugin);
1068
1069     if (!skip) {
1070       name = g_strdup_printf ("GstVisual%s", ref->info->plugname);
1071       make_valid_name (name);
1072       type = g_type_register_static (GST_TYPE_VISUAL, name, &info, 0);
1073       g_free (name);
1074
1075       name = g_strdup_printf ("libvisual_%s", ref->info->plugname);
1076       make_valid_name (name);
1077       if (!gst_element_register (plugin, name, GST_RANK_NONE, type)) {
1078         g_free (name);
1079         return FALSE;
1080       }
1081       g_free (name);
1082     }
1083   }
1084
1085   return TRUE;
1086 }
1087
1088 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1089     GST_VERSION_MINOR,
1090     "libvisual",
1091     "libvisual visualization plugins",
1092     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)