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