tizen 2.3 release
[framework/multimedia/gst-plugins-base0.10.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
78   /* samples per frame based on caps */
79   guint spf;
80
81   /* state stuff */
82   GstAdapter *adapter;
83   guint count;
84
85   /* QoS stuff *//* with LOCK */
86   gdouble proportion;
87   GstClockTime earliest_time;
88 };
89
90 struct _GstVisualClass
91 {
92   GstElementClass parent_class;
93
94   VisPluginRef *plugin;
95 };
96
97 GType gst_visual_get_type (void);
98
99
100 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
101     GST_PAD_SRC,
102     GST_PAD_ALWAYS,
103     GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN "; "
104 #if G_BYTE_ORDER == G_BIG_ENDIAN
105         GST_VIDEO_CAPS_RGB "; "
106 #else
107         GST_VIDEO_CAPS_BGR "; "
108 #endif
109         GST_VIDEO_CAPS_RGB_16)
110     );
111
112 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
113     GST_PAD_SINK,
114     GST_PAD_ALWAYS,
115     GST_STATIC_CAPS ("audio/x-raw-int, "
116         "width = (int) 16, "
117         "depth = (int) 16, "
118         "endianness = (int) BYTE_ORDER, "
119         "signed = (boolean) TRUE, " "channels = (int) { 1, 2 }, "
120 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
121         "rate = (int) { 8000, 11250, 22500, 32000, 44100, 48000, 96000 }"
122 #else
123         "rate = (int) [ 1000, MAX ]"
124 #endif
125     )
126     );
127
128
129 static void gst_visual_class_init (gpointer g_class, gpointer class_data);
130 static void gst_visual_init (GstVisual * visual);
131 static void gst_visual_dispose (GObject * object);
132
133 static GstStateChangeReturn gst_visual_change_state (GstElement * element,
134     GstStateChange transition);
135 static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer);
136 static gboolean gst_visual_sink_event (GstPad * pad, GstEvent * event);
137 static gboolean gst_visual_src_event (GstPad * pad, GstEvent * event);
138
139 static gboolean gst_visual_src_query (GstPad * pad, GstQuery * query);
140
141 static gboolean gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps);
142 static gboolean gst_visual_src_setcaps (GstPad * pad, GstCaps * caps);
143 static GstCaps *gst_visual_getcaps (GstPad * pad);
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_static_pad_template (element, &src_template);
198     gst_element_class_add_static_pad_template (element, &sink_template);
199     gst_element_class_set_details_simple (element,
200         longname, "Visualization",
201         klass->plugin->info->about, "Benjamin Otte <otte@gnome.org>");
202
203     g_free (longname);
204   }
205
206   object->dispose = gst_visual_dispose;
207 }
208
209 static void
210 gst_visual_init (GstVisual * visual)
211 {
212   /* create the sink and src pads */
213   visual->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
214   gst_pad_set_setcaps_function (visual->sinkpad, gst_visual_sink_setcaps);
215   gst_pad_set_chain_function (visual->sinkpad, gst_visual_chain);
216   gst_pad_set_event_function (visual->sinkpad, gst_visual_sink_event);
217   gst_element_add_pad (GST_ELEMENT (visual), visual->sinkpad);
218
219   visual->srcpad = gst_pad_new_from_static_template (&src_template, "src");
220   gst_pad_set_setcaps_function (visual->srcpad, gst_visual_src_setcaps);
221   gst_pad_set_getcaps_function (visual->srcpad, gst_visual_getcaps);
222   gst_pad_set_event_function (visual->srcpad, gst_visual_src_event);
223   gst_pad_set_query_function (visual->srcpad, gst_visual_src_query);
224   gst_element_add_pad (GST_ELEMENT (visual), visual->srcpad);
225
226   visual->adapter = gst_adapter_new ();
227 }
228
229 static void
230 gst_visual_clear_actors (GstVisual * visual)
231 {
232   if (visual->actor) {
233     visual_object_unref (VISUAL_OBJECT (visual->actor));
234     visual->actor = NULL;
235   }
236   if (visual->video) {
237     visual_object_unref (VISUAL_OBJECT (visual->video));
238     visual->video = NULL;
239   }
240   if (visual->audio) {
241     visual_object_unref (VISUAL_OBJECT (visual->audio));
242     visual->audio = NULL;
243   }
244 }
245
246 static void
247 gst_visual_dispose (GObject * object)
248 {
249   GstVisual *visual = GST_VISUAL (object);
250
251   if (visual->adapter) {
252     g_object_unref (visual->adapter);
253     visual->adapter = NULL;
254   }
255   gst_visual_clear_actors (visual);
256
257   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (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)
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_caps_copy (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   gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN));
299
300   if (depths & VISUAL_VIDEO_DEPTH_24BIT) {
301 #if G_BYTE_ORDER == G_BIG_ENDIAN
302     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB));
303 #else
304     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_BGR));
305 #endif
306   }
307   if (depths & VISUAL_VIDEO_DEPTH_16BIT) {
308     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB_16));
309   }
310
311 beach:
312
313   GST_DEBUG_OBJECT (visual, "returning caps %" GST_PTR_FORMAT, ret);
314   gst_object_unref (visual);
315   return ret;
316 }
317
318 static gboolean
319 gst_visual_src_setcaps (GstPad * pad, GstCaps * caps)
320 {
321   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
322   GstStructure *structure;
323   gint depth, pitch;
324
325   structure = gst_caps_get_structure (caps, 0);
326
327   GST_DEBUG_OBJECT (visual, "src pad got caps %" GST_PTR_FORMAT, caps);
328
329   if (!gst_structure_get_int (structure, "width", &visual->width))
330     goto error;
331   if (!gst_structure_get_int (structure, "height", &visual->height))
332     goto error;
333   if (!gst_structure_get_int (structure, "bpp", &depth))
334     goto error;
335   if (!gst_structure_get_fraction (structure, "framerate", &visual->fps_n,
336           &visual->fps_d))
337     goto error;
338
339   visual_video_set_depth (visual->video,
340       visual_video_depth_enum_from_value (depth));
341   visual_video_set_dimension (visual->video, visual->width, visual->height);
342   pitch = GST_ROUND_UP_4 (visual->width * visual->video->bpp);
343   visual_video_set_pitch (visual->video, pitch);
344   visual_actor_video_negotiate (visual->actor, 0, FALSE, FALSE);
345
346   /* precalc some values */
347   visual->outsize = visual->video->height * pitch;
348   visual->spf =
349       gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
350   visual->duration =
351       gst_util_uint64_scale_int (GST_SECOND, visual->fps_d, visual->fps_n);
352
353   gst_object_unref (visual);
354   return TRUE;
355
356   /* ERRORS */
357 error:
358   {
359     GST_DEBUG_OBJECT (visual, "error parsing caps");
360     gst_object_unref (visual);
361     return FALSE;
362   }
363 }
364
365 static gboolean
366 gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps)
367 {
368   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
369   GstStructure *structure;
370
371   structure = gst_caps_get_structure (caps, 0);
372
373   gst_structure_get_int (structure, "channels", &visual->channels);
374   gst_structure_get_int (structure, "rate", &visual->rate);
375
376   /* this is how many samples we need to fill one frame at the requested
377    * framerate. */
378   if (visual->fps_n != 0) {
379     visual->spf =
380         gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
381   }
382   visual->bps = visual->channels * sizeof (gint16);
383
384   gst_object_unref (visual);
385   return TRUE;
386 }
387
388 static gboolean
389 gst_vis_src_negotiate (GstVisual * visual)
390 {
391   GstCaps *othercaps, *target;
392   GstStructure *structure;
393   GstCaps *caps;
394
395   caps = gst_pad_get_caps (visual->srcpad);
396
397   /* see what the peer can do */
398   othercaps = gst_pad_peer_get_caps (visual->srcpad);
399   if (othercaps) {
400     target = gst_caps_intersect (othercaps, caps);
401     gst_caps_unref (othercaps);
402     gst_caps_unref (caps);
403
404     if (gst_caps_is_empty (target))
405       goto no_format;
406
407     gst_caps_truncate (target);
408   } else {
409     /* need a copy, we'll be modifying it when fixating */
410     target = gst_caps_copy (caps);
411     gst_caps_unref (caps);
412   }
413
414   /* fixate in case something is not fixed. This does nothing if the value is
415    * already fixed. For video we always try to fixate to something like
416    * 320x240x25 by convention. */
417   structure = gst_caps_get_structure (target, 0);
418   gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH);
419   gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT);
420   gst_structure_fixate_field_nearest_fraction (structure, "framerate",
421       DEFAULT_FPS_N, DEFAULT_FPS_D);
422
423   gst_pad_set_caps (visual->srcpad, target);
424   gst_caps_unref (target);
425
426   return TRUE;
427
428   /* ERRORS */
429 no_format:
430   {
431     GST_ELEMENT_ERROR (visual, STREAM, FORMAT, (NULL),
432         ("could not negotiate output format"));
433     gst_caps_unref (target);
434     return FALSE;
435   }
436 }
437
438 static gboolean
439 gst_visual_sink_event (GstPad * pad, GstEvent * event)
440 {
441   GstVisual *visual;
442   gboolean res;
443
444   visual = GST_VISUAL (gst_pad_get_parent (pad));
445
446   switch (GST_EVENT_TYPE (event)) {
447     case GST_EVENT_FLUSH_START:
448       res = gst_pad_push_event (visual->srcpad, event);
449       break;
450     case GST_EVENT_FLUSH_STOP:
451       /* reset QoS and adapter. */
452       gst_visual_reset (visual);
453       res = gst_pad_push_event (visual->srcpad, event);
454       break;
455     case GST_EVENT_NEWSEGMENT:
456     {
457       GstFormat format;
458       gdouble rate, arate;
459       gint64 start, stop, time;
460       gboolean update;
461
462       /* the newsegment values are used to clip the input samples
463        * and to convert the incomming timestamps to running time so
464        * we can do QoS */
465       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
466           &start, &stop, &time);
467
468       /* now configure the values */
469       gst_segment_set_newsegment_full (&visual->segment, update,
470           rate, arate, format, start, stop, time);
471
472       /* and forward */
473       res = gst_pad_push_event (visual->srcpad, event);
474       break;
475     }
476     default:
477       res = gst_pad_push_event (visual->srcpad, event);
478       break;
479   }
480
481   gst_object_unref (visual);
482   return res;
483 }
484
485 static gboolean
486 gst_visual_src_event (GstPad * pad, GstEvent * event)
487 {
488   GstVisual *visual;
489   gboolean res;
490
491   visual = GST_VISUAL (gst_pad_get_parent (pad));
492
493   switch (GST_EVENT_TYPE (event)) {
494     case GST_EVENT_QOS:
495     {
496       gdouble proportion;
497       GstClockTimeDiff diff;
498       GstClockTime timestamp;
499
500       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
501
502       /* save stuff for the _chain function */
503       GST_OBJECT_LOCK (visual);
504       visual->proportion = proportion;
505       if (diff >= 0)
506         /* we're late, this is a good estimate for next displayable
507          * frame (see part-qos.txt) */
508         visual->earliest_time = timestamp + 2 * diff + visual->duration;
509       else
510         visual->earliest_time = timestamp + diff;
511
512       GST_OBJECT_UNLOCK (visual);
513
514       res = gst_pad_push_event (visual->sinkpad, event);
515       break;
516     }
517     default:
518       res = gst_pad_push_event (visual->sinkpad, event);
519       break;
520   }
521
522   gst_object_unref (visual);
523   return res;
524 }
525
526 static gboolean
527 gst_visual_src_query (GstPad * pad, GstQuery * query)
528 {
529   gboolean res;
530   GstVisual *visual;
531
532   visual = GST_VISUAL (gst_pad_get_parent (pad));
533
534   switch (GST_QUERY_TYPE (query)) {
535     case GST_QUERY_LATENCY:
536     {
537       /* We need to send the query upstream and add the returned latency to our
538        * own */
539       GstClockTime min_latency, max_latency;
540       gboolean us_live;
541       GstClockTime our_latency;
542       guint max_samples;
543
544       if ((res = gst_pad_peer_query (visual->sinkpad, query))) {
545         gst_query_parse_latency (query, &us_live, &min_latency, &max_latency);
546
547         GST_DEBUG_OBJECT (visual, "Peer latency: min %"
548             GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
549             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
550
551         /* the max samples we must buffer */
552         max_samples = MAX (VISUAL_SAMPLES, visual->spf);
553         our_latency =
554             gst_util_uint64_scale_int (max_samples, GST_SECOND, visual->rate);
555
556         GST_DEBUG_OBJECT (visual, "Our latency: %" GST_TIME_FORMAT,
557             GST_TIME_ARGS (our_latency));
558
559         /* we add some latency but only if we need to buffer more than what
560          * upstream gives us */
561         min_latency += our_latency;
562         if (max_latency != -1)
563           max_latency += our_latency;
564
565         GST_DEBUG_OBJECT (visual, "Calculated total latency : min %"
566             GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
567             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
568
569         gst_query_set_latency (query, TRUE, min_latency, max_latency);
570       }
571       break;
572     }
573     default:
574       res = gst_pad_peer_query (visual->sinkpad, query);
575       break;
576   }
577
578   gst_object_unref (visual);
579
580   return res;
581 }
582
583 /* allocate and output buffer, if no format was negotiated, this
584  * function will negotiate one. After calling this function, a
585  * reverse negotiation could have happened. */
586 static GstFlowReturn
587 get_buffer (GstVisual * visual, GstBuffer ** outbuf)
588 {
589   GstFlowReturn ret;
590
591   /* we don't know an output format yet, pick one */
592   if (GST_PAD_CAPS (visual->srcpad) == NULL) {
593     if (!gst_vis_src_negotiate (visual))
594       return GST_FLOW_NOT_NEGOTIATED;
595   }
596
597   GST_DEBUG_OBJECT (visual, "allocating output buffer with caps %"
598       GST_PTR_FORMAT, GST_PAD_CAPS (visual->srcpad));
599
600   /* now allocate a buffer with the last negotiated format. 
601    * Downstream could renegotiate a new format, which will trigger
602    * our setcaps function on the source pad. */
603   ret =
604       gst_pad_alloc_buffer_and_set_caps (visual->srcpad,
605       GST_BUFFER_OFFSET_NONE, visual->outsize,
606       GST_PAD_CAPS (visual->srcpad), outbuf);
607
608   /* no buffer allocated, we don't care why. */
609   if (ret != GST_FLOW_OK)
610     return ret;
611
612   return GST_FLOW_OK;
613 }
614
615 static GstFlowReturn
616 gst_visual_chain (GstPad * pad, GstBuffer * buffer)
617 {
618   GstBuffer *outbuf = NULL;
619   guint i;
620   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
621   GstFlowReturn ret = GST_FLOW_OK;
622   guint avail;
623
624   GST_DEBUG_OBJECT (visual, "chain function called");
625
626   /* If we don't have an output format yet, preallocate a buffer to try and
627    * set one */
628   if (GST_PAD_CAPS (visual->srcpad) == NULL) {
629     ret = get_buffer (visual, &outbuf);
630     if (ret != GST_FLOW_OK) {
631       gst_buffer_unref (buffer);
632       goto beach;
633     }
634   }
635
636   /* resync on DISCONT */
637   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
638     gst_adapter_clear (visual->adapter);
639   }
640
641   GST_DEBUG_OBJECT (visual,
642       "Input buffer has %d samples, time=%" G_GUINT64_FORMAT,
643       GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer));
644
645   gst_adapter_push (visual->adapter, buffer);
646
647   while (TRUE) {
648     gboolean need_skip;
649     const guint16 *data;
650     guint64 dist, timestamp;
651
652     GST_DEBUG_OBJECT (visual, "processing buffer");
653
654     avail = gst_adapter_available (visual->adapter);
655     GST_DEBUG_OBJECT (visual, "avail now %u", avail);
656
657     /* we need at least VISUAL_SAMPLES samples */
658     if (avail < VISUAL_SAMPLES * visual->bps)
659       break;
660
661     /* we need at least enough samples to make one frame */
662     if (avail < visual->spf * visual->bps)
663       break;
664
665     /* get timestamp of the current adapter byte */
666     timestamp = gst_adapter_prev_timestamp (visual->adapter, &dist);
667     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
668       /* convert bytes to time */
669       dist /= visual->bps;
670       timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, visual->rate);
671     }
672
673     if (timestamp != -1) {
674       gint64 qostime;
675
676       /* QoS is done on running time */
677       qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME,
678           timestamp);
679       qostime += visual->duration;
680
681       GST_OBJECT_LOCK (visual);
682       /* check for QoS, don't compute buffers that are known to be late */
683       need_skip = visual->earliest_time != -1 &&
684           qostime <= visual->earliest_time;
685       GST_OBJECT_UNLOCK (visual);
686
687       if (need_skip) {
688         GST_WARNING_OBJECT (visual,
689             "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
690             GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time));
691         goto skip;
692       }
693     }
694
695     /* Read VISUAL_SAMPLES samples per channel */
696     data =
697         (const guint16 *) gst_adapter_peek (visual->adapter,
698         VISUAL_SAMPLES * visual->bps);
699
700 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
701     {
702       VisBuffer *lbuf, *rbuf;
703       guint16 ldata[VISUAL_SAMPLES], rdata[VISUAL_SAMPLES];
704       VisAudioSampleRateType rate;
705
706       lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL);
707       rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL);
708
709       if (visual->channels == 2) {
710         for (i = 0; i < VISUAL_SAMPLES; i++) {
711           ldata[i] = *data++;
712           rdata[i] = *data++;
713         }
714       } else {
715         for (i = 0; i < VISUAL_SAMPLES; i++) {
716           ldata[i] = *data;
717           rdata[i] = *data++;
718         }
719       }
720
721       switch (visual->rate) {
722         case 8000:
723           rate = VISUAL_AUDIO_SAMPLE_RATE_8000;
724           break;
725         case 11250:
726           rate = VISUAL_AUDIO_SAMPLE_RATE_11250;
727           break;
728         case 22500:
729           rate = VISUAL_AUDIO_SAMPLE_RATE_22500;
730           break;
731         case 32000:
732           rate = VISUAL_AUDIO_SAMPLE_RATE_32000;
733           break;
734         case 44100:
735           rate = VISUAL_AUDIO_SAMPLE_RATE_44100;
736           break;
737         case 48000:
738           rate = VISUAL_AUDIO_SAMPLE_RATE_48000;
739           break;
740         case 96000:
741           rate = VISUAL_AUDIO_SAMPLE_RATE_96000;
742           break;
743         default:
744           visual_object_unref (VISUAL_OBJECT (lbuf));
745           visual_object_unref (VISUAL_OBJECT (rbuf));
746           GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate);
747           ret = GST_FLOW_ERROR;
748           goto beach;
749           break;
750       }
751
752       visual_audio_samplepool_input_channel (visual->audio->samplepool,
753           lbuf,
754           rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16,
755           (char *) VISUAL_AUDIO_CHANNEL_LEFT);
756       visual_audio_samplepool_input_channel (visual->audio->samplepool, rbuf,
757           rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16,
758           (char *) VISUAL_AUDIO_CHANNEL_RIGHT);
759
760       visual_object_unref (VISUAL_OBJECT (lbuf));
761       visual_object_unref (VISUAL_OBJECT (rbuf));
762
763     }
764 #else
765     if (visual->channels == 2) {
766       for (i = 0; i < VISUAL_SAMPLES; i++) {
767         visual->audio->plugpcm[0][i] = *data++;
768         visual->audio->plugpcm[1][i] = *data++;
769       }
770     } else {
771       for (i = 0; i < VISUAL_SAMPLES; i++) {
772         visual->audio->plugpcm[0][i] = *data;
773         visual->audio->plugpcm[1][i] = *data++;
774       }
775     }
776 #endif
777
778     /* alloc a buffer if we don't have one yet, this happens
779      * when we pushed a buffer in this while loop before */
780     if (outbuf == NULL) {
781       ret = get_buffer (visual, &outbuf);
782       if (ret != GST_FLOW_OK) {
783         goto beach;
784       }
785     }
786     visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf));
787     visual_audio_analyze (visual->audio);
788     visual_actor_run (visual->actor, visual->audio);
789     visual_video_set_buffer (visual->video, NULL);
790     GST_DEBUG_OBJECT (visual, "rendered one frame");
791
792     GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
793     GST_BUFFER_DURATION (outbuf) = visual->duration;
794
795     ret = gst_pad_push (visual->srcpad, outbuf);
796     outbuf = NULL;
797
798   skip:
799     GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input",
800         visual->spf);
801
802     /* Flush out the number of samples per frame */
803     gst_adapter_flush (visual->adapter, visual->spf * visual->bps);
804
805     /* quit the loop if something was wrong */
806     if (ret != GST_FLOW_OK)
807       break;
808   }
809
810 beach:
811
812   if (outbuf != NULL)
813     gst_buffer_unref (outbuf);
814
815   gst_object_unref (visual);
816
817   return ret;
818 }
819
820 static GstStateChangeReturn
821 gst_visual_change_state (GstElement * element, GstStateChange transition)
822 {
823   GstVisual *visual = GST_VISUAL (element);
824   GstStateChangeReturn ret;
825
826   switch (transition) {
827     case GST_STATE_CHANGE_NULL_TO_READY:
828       visual->actor =
829           visual_actor_new (GST_VISUAL_GET_CLASS (visual)->plugin->info->
830           plugname);
831       visual->video = visual_video_new ();
832       visual->audio = visual_audio_new ();
833       /* can't have a play without actors */
834       if (!visual->actor || !visual->video)
835         goto no_actors;
836
837       if (visual_actor_realize (visual->actor) != 0)
838         goto no_realize;
839
840       visual_actor_set_video (visual->actor, visual->video);
841       break;
842     case GST_STATE_CHANGE_READY_TO_PAUSED:
843       gst_visual_reset (visual);
844       break;
845     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
846       break;
847     default:
848       break;
849   }
850
851   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
852
853   switch (transition) {
854     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
855       break;
856     case GST_STATE_CHANGE_PAUSED_TO_READY:
857       break;
858     case GST_STATE_CHANGE_READY_TO_NULL:
859       gst_visual_clear_actors (visual);
860       break;
861     default:
862       break;
863   }
864
865   return ret;
866
867   /* ERRORS */
868 no_actors:
869   {
870     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
871         ("could not create actors"));
872     gst_visual_clear_actors (visual);
873     return GST_STATE_CHANGE_FAILURE;
874   }
875 no_realize:
876   {
877     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
878         ("could not realize actor"));
879     gst_visual_clear_actors (visual);
880     return GST_STATE_CHANGE_FAILURE;
881   }
882 }
883
884 static void
885 make_valid_name (char *name)
886 {
887   /*
888    * Replace invalid chars with _ in the type name
889    */
890   static const gchar extra_chars[] = "-_+";
891   gchar *p = name;
892
893   for (; *p; p++) {
894     int valid = ((p[0] >= 'A' && p[0] <= 'Z') ||
895         (p[0] >= 'a' && p[0] <= 'z') ||
896         (p[0] >= '0' && p[0] <= '9') || strchr (extra_chars, p[0]));
897     if (!valid)
898       *p = '_';
899   }
900 }
901
902 static gboolean
903 gst_visual_actor_plugin_is_gl (VisObject * plugin, const gchar * name)
904 {
905   gboolean is_gl;
906   gint depth;
907
908 #if !defined(VISUAL_API_VERSION)
909
910   depth = VISUAL_PLUGIN_ACTOR (plugin)->depth;
911   is_gl = (depth == VISUAL_VIDEO_DEPTH_GL);
912
913 #elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
914
915   depth = VISUAL_ACTOR_PLUGIN (plugin)->vidoptions.depth;
916   /* FIXME: how to figure this out correctly in 0.4? */
917   is_gl = (depth & VISUAL_VIDEO_DEPTH_GL) == VISUAL_VIDEO_DEPTH_GL;
918
919 #else
920 # error what libvisual version is this?
921 #endif
922
923   if (!is_gl) {
924     GST_DEBUG ("plugin %s is not a GL plugin (%d), registering", name, depth);
925   } else {
926     GST_DEBUG ("plugin %s is a GL plugin (%d), ignoring", name, depth);
927   }
928
929   return is_gl;
930 }
931
932 static gboolean
933 plugin_init (GstPlugin * plugin)
934 {
935   guint i, count;
936   VisList *list;
937
938   GST_DEBUG_CATEGORY_INIT (libvisual_debug, "libvisual", 0,
939       "libvisual audio visualisations");
940
941 #ifdef LIBVISUAL_PLUGINSBASEDIR
942   gst_plugin_add_dependency_simple (plugin, "HOME/.libvisual/actor",
943       LIBVISUAL_PLUGINSBASEDIR "/actor", NULL, GST_PLUGIN_DEPENDENCY_FLAG_NONE);
944 #endif
945
946   visual_log_set_verboseness (VISUAL_LOG_VERBOSENESS_LOW);
947   visual_log_set_info_handler (libvisual_log_handler, (void *) GST_LEVEL_INFO);
948   visual_log_set_warning_handler (libvisual_log_handler,
949       (void *) GST_LEVEL_WARNING);
950   visual_log_set_critical_handler (libvisual_log_handler,
951       (void *) GST_LEVEL_ERROR);
952   visual_log_set_error_handler (libvisual_log_handler,
953       (void *) GST_LEVEL_ERROR);
954
955   if (!visual_is_initialized ())
956     if (visual_init (NULL, NULL) != 0)
957       return FALSE;
958
959   list = visual_actor_get_list ();
960
961 #if !defined(VISUAL_API_VERSION)
962   count = visual_list_count (list);
963 #elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
964   count = visual_collection_size (VISUAL_COLLECTION (list));
965 #endif
966
967   for (i = 0; i < count; i++) {
968     VisPluginRef *ref = visual_list_get (list, i);
969     VisPluginData *visplugin = NULL;
970     gboolean skip = FALSE;
971     GType type;
972     gchar *name;
973     GTypeInfo info = {
974       sizeof (GstVisualClass),
975       NULL,
976       NULL,
977       gst_visual_class_init,
978       NULL,
979       ref,
980       sizeof (GstVisual),
981       0,
982       NULL
983     };
984
985     visplugin = visual_plugin_load (ref);
986
987     if (ref->info->plugname == NULL)
988       continue;
989
990     /* Blacklist some plugins */
991     if (strcmp (ref->info->plugname, "gstreamer") == 0 ||
992         strcmp (ref->info->plugname, "gdkpixbuf") == 0) {
993       skip = TRUE;
994     } else {
995       /* Ignore plugins that only support GL output for now */
996       skip = gst_visual_actor_plugin_is_gl (visplugin->info->plugin,
997           visplugin->info->plugname);
998     }
999
1000     visual_plugin_unload (visplugin);
1001
1002     if (!skip) {
1003       name = g_strdup_printf ("GstVisual%s", ref->info->plugname);
1004       make_valid_name (name);
1005       type = g_type_register_static (GST_TYPE_VISUAL, name, &info, 0);
1006       g_free (name);
1007
1008       name = g_strdup_printf ("libvisual_%s", ref->info->plugname);
1009       make_valid_name (name);
1010       if (!gst_element_register (plugin, name, GST_RANK_NONE, type)) {
1011         g_free (name);
1012         return FALSE;
1013       }
1014       g_free (name);
1015     }
1016   }
1017
1018   return TRUE;
1019 }
1020
1021 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1022     GST_VERSION_MINOR,
1023     "libvisual",
1024     "libvisual visualization plugins",
1025     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)