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