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