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