gst_plugins_base/ext/libvisual/visual.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     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 struct _GstVisual
       
    44 {
       
    45   GstElement element;
       
    46 
       
    47   /* pads */
       
    48   GstPad *sinkpad;
       
    49   GstPad *srcpad;
       
    50   GstClockTime next_ts;
       
    51   GstSegment segment;
       
    52 
       
    53   /* libvisual stuff */
       
    54   VisAudio *audio;
       
    55   VisVideo *video;
       
    56   VisActor *actor;
       
    57 
       
    58   /* audio/video state */
       
    59   gint channels;
       
    60   gint rate;                    /* Input samplerate */
       
    61   gint bps;
       
    62 
       
    63   /* framerate numerator & denominator */
       
    64   gint fps_n;
       
    65   gint fps_d;
       
    66   gint width;
       
    67   gint height;
       
    68   GstClockTime duration;
       
    69   guint outsize;
       
    70 
       
    71   /* samples per frame based on caps */
       
    72   guint spf;
       
    73 
       
    74   /* state stuff */
       
    75   GstAdapter *adapter;
       
    76   guint count;
       
    77 
       
    78   /* QoS stuff *//* with LOCK */
       
    79   gdouble proportion;
       
    80   GstClockTime earliest_time;
       
    81 };
       
    82 
       
    83 struct _GstVisualClass
       
    84 {
       
    85   GstElementClass parent_class;
       
    86 
       
    87   VisPluginRef *plugin;
       
    88 };
       
    89 
       
    90 GType gst_visual_get_type (void);
       
    91 
       
    92 
       
    93 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
       
    94     GST_PAD_SRC,
       
    95     GST_PAD_ALWAYS,
       
    96     GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN "; "
       
    97 #if G_BYTE_ORDER == G_BIG_ENDIAN
       
    98         GST_VIDEO_CAPS_RGB "; "
       
    99 #else
       
   100         GST_VIDEO_CAPS_BGR "; "
       
   101 #endif
       
   102         GST_VIDEO_CAPS_RGB_16)
       
   103     );
       
   104 
       
   105 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
       
   106     GST_PAD_SINK,
       
   107     GST_PAD_ALWAYS,
       
   108     GST_STATIC_CAPS ("audio/x-raw-int, "
       
   109         "width = (int) 16, "
       
   110         "depth = (int) 16, "
       
   111         "endianness = (int) BYTE_ORDER, "
       
   112         "signed = (boolean) TRUE, " "channels = (int) { 1, 2 }, "
       
   113 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
       
   114         "rate = (int) { 8000, 11250, 22500, 32000, 44100, 48000, 96000 }"
       
   115 #else
       
   116         "rate = (int) [ 1000, MAX ]"
       
   117 #endif
       
   118     )
       
   119     );
       
   120 
       
   121 
       
   122 static void gst_visual_class_init (gpointer g_class, gpointer class_data);
       
   123 static void gst_visual_init (GstVisual * visual);
       
   124 static void gst_visual_dispose (GObject * object);
       
   125 
       
   126 static GstStateChangeReturn gst_visual_change_state (GstElement * element,
       
   127     GstStateChange transition);
       
   128 static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer);
       
   129 static gboolean gst_visual_sink_event (GstPad * pad, GstEvent * event);
       
   130 static gboolean gst_visual_src_event (GstPad * pad, GstEvent * event);
       
   131 
       
   132 static gboolean gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps);
       
   133 static gboolean gst_visual_src_setcaps (GstPad * pad, GstCaps * caps);
       
   134 static GstCaps *gst_visual_getcaps (GstPad * pad);
       
   135 static void libvisual_log_handler (const char *message, const char *funcname,
       
   136     void *priv);
       
   137 
       
   138 static GstElementClass *parent_class = NULL;
       
   139 
       
   140 GType
       
   141 gst_visual_get_type (void)
       
   142 {
       
   143   static GType type = 0;
       
   144 
       
   145   if (G_UNLIKELY (type == 0)) {
       
   146     static const GTypeInfo info = {
       
   147       sizeof (GstVisualClass),
       
   148       NULL,
       
   149       NULL,
       
   150       gst_visual_class_init,
       
   151       NULL,
       
   152       NULL,
       
   153       sizeof (GstVisual),
       
   154       0,
       
   155       (GInstanceInitFunc) gst_visual_init,
       
   156     };
       
   157 
       
   158     type = g_type_register_static (GST_TYPE_ELEMENT, "GstVisual", &info, 0);
       
   159   }
       
   160   return type;
       
   161 }
       
   162 
       
   163 static void
       
   164 libvisual_log_handler (const char *message, const char *funcname, void *priv)
       
   165 {
       
   166   GST_CAT_LEVEL_LOG (libvisual_debug, (GstDebugLevel) (priv), NULL, "%s - %s",
       
   167       funcname, message);
       
   168 }
       
   169 
       
   170 static void
       
   171 gst_visual_class_init (gpointer g_class, gpointer class_data)
       
   172 {
       
   173   GstVisualClass *klass = GST_VISUAL_CLASS (g_class);
       
   174   GstElementClass *element = GST_ELEMENT_CLASS (g_class);
       
   175   GObjectClass *object = G_OBJECT_CLASS (g_class);
       
   176 
       
   177   klass->plugin = class_data;
       
   178 
       
   179   element->change_state = gst_visual_change_state;
       
   180 
       
   181   if (class_data == NULL) {
       
   182     parent_class = g_type_class_peek_parent (g_class);
       
   183   } else {
       
   184     GstElementDetails details = {
       
   185       NULL,
       
   186       "Visualization",
       
   187       klass->plugin->info->about,
       
   188       "Benjamin Otte <otte@gnome.org>"
       
   189     };
       
   190 
       
   191     details.longname = g_strdup_printf ("libvisual %s plugin v.%s",
       
   192         klass->plugin->info->name, klass->plugin->info->version);
       
   193 
       
   194     /* FIXME: improve to only register what plugin supports? */
       
   195     gst_element_class_add_pad_template (element,
       
   196         gst_static_pad_template_get (&src_template));
       
   197     gst_element_class_add_pad_template (element,
       
   198         gst_static_pad_template_get (&sink_template));
       
   199     gst_element_class_set_details (element, &details);
       
   200     g_free (details.longname);
       
   201   }
       
   202 
       
   203   object->dispose = gst_visual_dispose;
       
   204 }
       
   205 
       
   206 static void
       
   207 gst_visual_init (GstVisual * visual)
       
   208 {
       
   209   /* create the sink and src pads */
       
   210   visual->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
       
   211   gst_pad_set_setcaps_function (visual->sinkpad, gst_visual_sink_setcaps);
       
   212   gst_pad_set_chain_function (visual->sinkpad, gst_visual_chain);
       
   213   gst_pad_set_event_function (visual->sinkpad, gst_visual_sink_event);
       
   214   gst_element_add_pad (GST_ELEMENT (visual), visual->sinkpad);
       
   215 
       
   216   visual->srcpad = gst_pad_new_from_static_template (&src_template, "src");
       
   217   gst_pad_set_setcaps_function (visual->srcpad, gst_visual_src_setcaps);
       
   218   gst_pad_set_getcaps_function (visual->srcpad, gst_visual_getcaps);
       
   219   gst_pad_set_event_function (visual->srcpad, gst_visual_src_event);
       
   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_dispose (GObject * object)
       
   244 {
       
   245   GstVisual *visual = GST_VISUAL (object);
       
   246 
       
   247   if (visual->adapter) {
       
   248     g_object_unref (visual->adapter);
       
   249     visual->adapter = NULL;
       
   250   }
       
   251   gst_visual_clear_actors (visual);
       
   252 
       
   253   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
       
   254 }
       
   255 
       
   256 static void
       
   257 gst_visual_reset (GstVisual * visual)
       
   258 {
       
   259   visual->next_ts = -1;
       
   260   gst_adapter_clear (visual->adapter);
       
   261   gst_segment_init (&visual->segment, GST_FORMAT_UNDEFINED);
       
   262 
       
   263   GST_OBJECT_LOCK (visual);
       
   264   visual->proportion = 1.0;
       
   265   visual->earliest_time = -1;
       
   266   GST_OBJECT_UNLOCK (visual);
       
   267 }
       
   268 
       
   269 static GstCaps *
       
   270 gst_visual_getcaps (GstPad * pad)
       
   271 {
       
   272   GstCaps *ret;
       
   273   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
       
   274   int depths;
       
   275 
       
   276   if (!visual->actor) {
       
   277     ret = gst_caps_copy (gst_pad_get_pad_template_caps (visual->srcpad));
       
   278     goto beach;
       
   279   }
       
   280 
       
   281   ret = gst_caps_new_empty ();
       
   282   depths = visual_actor_get_supported_depth (visual->actor);
       
   283   if (depths < 0) {
       
   284     /* FIXME: set an error */
       
   285     goto beach;
       
   286   }
       
   287   if (depths == VISUAL_VIDEO_DEPTH_GL) {
       
   288     /* We can't handle GL only plugins */
       
   289     goto beach;
       
   290   }
       
   291 
       
   292   GST_DEBUG_OBJECT (visual, "libvisual plugin supports depths %u (0x%04x)",
       
   293       depths, depths);
       
   294   /* if (depths & VISUAL_VIDEO_DEPTH_32BIT) Always supports 32bit output */
       
   295   gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN));
       
   296 
       
   297   if (depths & VISUAL_VIDEO_DEPTH_24BIT) {
       
   298 #if G_BYTE_ORDER == G_BIG_ENDIAN
       
   299     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB));
       
   300 #else
       
   301     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_BGR));
       
   302 #endif
       
   303   }
       
   304   if (depths & VISUAL_VIDEO_DEPTH_16BIT) {
       
   305     gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB_16));
       
   306   }
       
   307 
       
   308 beach:
       
   309 
       
   310   GST_DEBUG_OBJECT (visual, "returning caps %" GST_PTR_FORMAT, ret);
       
   311   gst_object_unref (visual);
       
   312   return ret;
       
   313 }
       
   314 
       
   315 static gboolean
       
   316 gst_visual_src_setcaps (GstPad * pad, GstCaps * caps)
       
   317 {
       
   318   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
       
   319   GstStructure *structure;
       
   320   gint depth, pitch;
       
   321 
       
   322   structure = gst_caps_get_structure (caps, 0);
       
   323 
       
   324   GST_DEBUG_OBJECT (visual, "src pad got caps %" GST_PTR_FORMAT, caps);
       
   325 
       
   326   if (!gst_structure_get_int (structure, "width", &visual->width))
       
   327     goto error;
       
   328   if (!gst_structure_get_int (structure, "height", &visual->height))
       
   329     goto error;
       
   330   if (!gst_structure_get_int (structure, "bpp", &depth))
       
   331     goto error;
       
   332   if (!gst_structure_get_fraction (structure, "framerate", &visual->fps_n,
       
   333           &visual->fps_d))
       
   334     goto error;
       
   335 
       
   336   visual_video_set_depth (visual->video,
       
   337       visual_video_depth_enum_from_value (depth));
       
   338   visual_video_set_dimension (visual->video, visual->width, visual->height);
       
   339   pitch = GST_ROUND_UP_4 (visual->width * visual->video->bpp);
       
   340   visual_video_set_pitch (visual->video, pitch);
       
   341   visual_actor_video_negotiate (visual->actor, 0, FALSE, FALSE);
       
   342 
       
   343   /* precalc some values */
       
   344   visual->outsize = visual->video->height * pitch;
       
   345   visual->spf =
       
   346       gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
       
   347   visual->duration =
       
   348       gst_util_uint64_scale_int (GST_SECOND, visual->fps_d, visual->fps_n);
       
   349 
       
   350   gst_object_unref (visual);
       
   351   return TRUE;
       
   352 
       
   353   /* ERRORS */
       
   354 error:
       
   355   {
       
   356     GST_DEBUG_OBJECT (visual, "error parsing caps");
       
   357     gst_object_unref (visual);
       
   358     return FALSE;
       
   359   }
       
   360 }
       
   361 
       
   362 static gboolean
       
   363 gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps)
       
   364 {
       
   365   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
       
   366   GstStructure *structure;
       
   367 
       
   368   structure = gst_caps_get_structure (caps, 0);
       
   369 
       
   370   gst_structure_get_int (structure, "channels", &visual->channels);
       
   371   gst_structure_get_int (structure, "rate", &visual->rate);
       
   372 
       
   373   /* this is how many samples we need to fill one frame at the requested
       
   374    * framerate. */
       
   375   if (visual->fps_n != 0) {
       
   376     visual->spf =
       
   377         gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
       
   378   }
       
   379   visual->bps = visual->channels * sizeof (gint16);
       
   380 
       
   381   gst_object_unref (visual);
       
   382   return TRUE;
       
   383 }
       
   384 
       
   385 static gboolean
       
   386 gst_vis_src_negotiate (GstVisual * visual)
       
   387 {
       
   388   GstCaps *othercaps, *target, *intersect;
       
   389   GstStructure *structure;
       
   390   GstCaps *caps;
       
   391 
       
   392   caps = gst_pad_get_caps (visual->srcpad);
       
   393 
       
   394   /* see what the peer can do */
       
   395   othercaps = gst_pad_peer_get_caps (visual->srcpad);
       
   396   if (othercaps) {
       
   397     intersect = gst_caps_intersect (othercaps, caps);
       
   398     gst_caps_unref (othercaps);
       
   399     gst_caps_unref (caps);
       
   400 
       
   401     if (gst_caps_is_empty (intersect))
       
   402       goto no_format;
       
   403 
       
   404     target = gst_caps_copy_nth (intersect, 0);
       
   405     gst_caps_unref (intersect);
       
   406   } else {
       
   407     /* need a copy, we'll be modifying it when fixating */
       
   408     target = gst_caps_copy (caps);
       
   409     gst_caps_unref (caps);
       
   410   }
       
   411 
       
   412   /* fixate in case something is not fixed. This does nothing if the value is
       
   413    * already fixed. For video we always try to fixate to something like
       
   414    * 320x240x30 by convention. */
       
   415   structure = gst_caps_get_structure (target, 0);
       
   416   gst_structure_fixate_field_nearest_int (structure, "width", 320);
       
   417   gst_structure_fixate_field_nearest_int (structure, "height", 240);
       
   418   gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
       
   419 
       
   420   gst_pad_set_caps (visual->srcpad, target);
       
   421   gst_caps_unref (target);
       
   422 
       
   423   return TRUE;
       
   424 
       
   425   /* ERRORS */
       
   426 no_format:
       
   427   {
       
   428     GST_ELEMENT_ERROR (visual, STREAM, FORMAT, (NULL),
       
   429         ("could not negotiate output format"));
       
   430     gst_caps_unref (intersect);
       
   431     return FALSE;
       
   432   }
       
   433 }
       
   434 
       
   435 static gboolean
       
   436 gst_visual_sink_event (GstPad * pad, GstEvent * event)
       
   437 {
       
   438   GstVisual *visual;
       
   439   gboolean res;
       
   440 
       
   441   visual = GST_VISUAL (gst_pad_get_parent (pad));
       
   442 
       
   443   switch (GST_EVENT_TYPE (event)) {
       
   444     case GST_EVENT_FLUSH_START:
       
   445       res = gst_pad_push_event (visual->srcpad, event);
       
   446       break;
       
   447     case GST_EVENT_FLUSH_STOP:
       
   448       /* reset QoS and adapter. */
       
   449       gst_visual_reset (visual);
       
   450       res = gst_pad_push_event (visual->srcpad, event);
       
   451       break;
       
   452     case GST_EVENT_NEWSEGMENT:
       
   453     {
       
   454       GstFormat format;
       
   455       gdouble rate, arate;
       
   456       gint64 start, stop, time;
       
   457       gboolean update;
       
   458 
       
   459       /* the newsegment values are used to clip the input samples
       
   460        * and to convert the incomming timestamps to running time so
       
   461        * we can do QoS */
       
   462       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
       
   463           &start, &stop, &time);
       
   464 
       
   465       /* now configure the values */
       
   466       gst_segment_set_newsegment_full (&visual->segment, update,
       
   467           rate, arate, format, start, stop, time);
       
   468 
       
   469       /* and forward */
       
   470       res = gst_pad_push_event (visual->srcpad, event);
       
   471       break;
       
   472     }
       
   473     default:
       
   474       res = gst_pad_push_event (visual->srcpad, event);
       
   475       break;
       
   476   }
       
   477 
       
   478   gst_object_unref (visual);
       
   479   return res;
       
   480 }
       
   481 
       
   482 static gboolean
       
   483 gst_visual_src_event (GstPad * pad, GstEvent * event)
       
   484 {
       
   485   GstVisual *visual;
       
   486   gboolean res;
       
   487 
       
   488   visual = GST_VISUAL (gst_pad_get_parent (pad));
       
   489 
       
   490   switch (GST_EVENT_TYPE (event)) {
       
   491     case GST_EVENT_QOS:
       
   492     {
       
   493       gdouble proportion;
       
   494       GstClockTimeDiff diff;
       
   495       GstClockTime timestamp;
       
   496 
       
   497       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
       
   498 
       
   499       /* save stuff for the _chain function */
       
   500       GST_OBJECT_LOCK (visual);
       
   501       visual->proportion = proportion;
       
   502       if (diff >= 0)
       
   503         /* we're late, this is a good estimate for next displayable
       
   504          * frame (see part-qos.txt) */
       
   505         visual->earliest_time = timestamp + 2 * diff + visual->duration;
       
   506       else
       
   507         visual->earliest_time = timestamp + diff;
       
   508 
       
   509       GST_OBJECT_UNLOCK (visual);
       
   510 
       
   511       res = gst_pad_push_event (visual->sinkpad, event);
       
   512       break;
       
   513     }
       
   514     default:
       
   515       res = gst_pad_push_event (visual->sinkpad, event);
       
   516       break;
       
   517   }
       
   518 
       
   519   gst_object_unref (visual);
       
   520   return res;
       
   521 }
       
   522 
       
   523 /* allocate and output buffer, if no format was negotiated, this
       
   524  * function will negotiate one. After calling this function, a
       
   525  * reverse negotiation could have happened. */
       
   526 static GstFlowReturn
       
   527 get_buffer (GstVisual * visual, GstBuffer ** outbuf)
       
   528 {
       
   529   GstFlowReturn ret;
       
   530 
       
   531   /* we don't know an output format yet, pick one */
       
   532   if (GST_PAD_CAPS (visual->srcpad) == NULL) {
       
   533     if (!gst_vis_src_negotiate (visual))
       
   534       return GST_FLOW_NOT_NEGOTIATED;
       
   535   }
       
   536 
       
   537   GST_DEBUG_OBJECT (visual, "allocating output buffer with caps %"
       
   538       GST_PTR_FORMAT, GST_PAD_CAPS (visual->srcpad));
       
   539 
       
   540   /* now allocate a buffer with the last negotiated format. 
       
   541    * Downstream could renegotiate a new format, which will trigger
       
   542    * our setcaps function on the source pad. */
       
   543   ret =
       
   544       gst_pad_alloc_buffer_and_set_caps (visual->srcpad,
       
   545       GST_BUFFER_OFFSET_NONE, visual->outsize,
       
   546       GST_PAD_CAPS (visual->srcpad), outbuf);
       
   547 
       
   548   /* no buffer allocated, we don't care why. */
       
   549   if (ret != GST_FLOW_OK)
       
   550     return ret;
       
   551 
       
   552   return GST_FLOW_OK;
       
   553 }
       
   554 
       
   555 static GstFlowReturn
       
   556 gst_visual_chain (GstPad * pad, GstBuffer * buffer)
       
   557 {
       
   558   GstBuffer *outbuf = NULL;
       
   559   guint i;
       
   560   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
       
   561   GstFlowReturn ret = GST_FLOW_OK;
       
   562   guint avail;
       
   563 
       
   564   GST_DEBUG_OBJECT (visual, "chain function called");
       
   565 
       
   566   /* If we don't have an output format yet, preallocate a buffer to try and
       
   567    * set one */
       
   568   if (GST_PAD_CAPS (visual->srcpad) == NULL) {
       
   569     ret = get_buffer (visual, &outbuf);
       
   570     if (ret != GST_FLOW_OK) {
       
   571       gst_buffer_unref (buffer);
       
   572       goto beach;
       
   573     }
       
   574   }
       
   575 
       
   576   /* resync on DISCONT */
       
   577   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
       
   578     gst_adapter_clear (visual->adapter);
       
   579     visual->next_ts = -1;
       
   580   }
       
   581 
       
   582   /* Match timestamps from the incoming audio */
       
   583   if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE)
       
   584     visual->next_ts = GST_BUFFER_TIMESTAMP (buffer);
       
   585 
       
   586   GST_DEBUG_OBJECT (visual,
       
   587       "Input buffer has %d samples, time=%" G_GUINT64_FORMAT,
       
   588       GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer));
       
   589 
       
   590   gst_adapter_push (visual->adapter, buffer);
       
   591 
       
   592   while (TRUE) {
       
   593     gboolean need_skip;
       
   594     const guint16 *data;
       
   595 
       
   596     GST_DEBUG_OBJECT (visual, "processing buffer");
       
   597 
       
   598     avail = gst_adapter_available (visual->adapter);
       
   599     GST_DEBUG_OBJECT (visual, "avail now %u", avail);
       
   600 
       
   601     /* we need at least 512 samples */
       
   602     if (avail < 512 * visual->bps)
       
   603       break;
       
   604 
       
   605     /* we need at least enough samples to make one frame */
       
   606     if (avail < visual->spf * visual->bps)
       
   607       break;
       
   608 
       
   609     if (visual->next_ts != -1) {
       
   610       gint64 qostime;
       
   611 
       
   612       /* QoS is done on running time */
       
   613       qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME,
       
   614           visual->next_ts);
       
   615 
       
   616       GST_OBJECT_LOCK (visual);
       
   617       /* check for QoS, don't compute buffers that are known to be late */
       
   618       need_skip = visual->earliest_time != -1 &&
       
   619           qostime <= visual->earliest_time;
       
   620       GST_OBJECT_UNLOCK (visual);
       
   621 
       
   622       if (need_skip) {
       
   623         GST_WARNING_OBJECT (visual,
       
   624             "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
       
   625             GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time));
       
   626         goto skip;
       
   627       }
       
   628     }
       
   629 
       
   630     /* Read 512 samples per channel */
       
   631     data =
       
   632         (const guint16 *) gst_adapter_peek (visual->adapter, 512 * visual->bps);
       
   633 
       
   634 #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
       
   635     {
       
   636       VisBuffer *lbuf, *rbuf;
       
   637       guint16 ldata[512], rdata[512];
       
   638       VisAudioSampleRateType rate;
       
   639 
       
   640       lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL);
       
   641       rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL);
       
   642 
       
   643       if (visual->channels == 2) {
       
   644         for (i = 0; i < 512; i++) {
       
   645           ldata[i] = *data++;
       
   646           rdata[i] = *data++;
       
   647         }
       
   648       } else {
       
   649         for (i = 0; i < 512; i++) {
       
   650           ldata[i] = *data;
       
   651           rdata[i] = *data++;
       
   652         }
       
   653       }
       
   654 
       
   655       switch (visual->rate) {
       
   656         case 8000:
       
   657           rate = VISUAL_AUDIO_SAMPLE_RATE_8000;
       
   658           break;
       
   659         case 11250:
       
   660           rate = VISUAL_AUDIO_SAMPLE_RATE_11250;
       
   661           break;
       
   662         case 22500:
       
   663           rate = VISUAL_AUDIO_SAMPLE_RATE_22500;
       
   664           break;
       
   665         case 32000:
       
   666           rate = VISUAL_AUDIO_SAMPLE_RATE_32000;
       
   667           break;
       
   668         case 44100:
       
   669           rate = VISUAL_AUDIO_SAMPLE_RATE_44100;
       
   670           break;
       
   671         case 48000:
       
   672           rate = VISUAL_AUDIO_SAMPLE_RATE_48000;
       
   673           break;
       
   674         case 96000:
       
   675           rate = VISUAL_AUDIO_SAMPLE_RATE_96000;
       
   676           break;
       
   677         default:
       
   678           visual_object_unref (VISUAL_OBJECT (lbuf));
       
   679           visual_object_unref (VISUAL_OBJECT (rbuf));
       
   680           GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate);
       
   681           ret = GST_FLOW_ERROR;
       
   682           goto beach;
       
   683           break;
       
   684       }
       
   685 
       
   686       visual_audio_samplepool_input_channel (visual->audio->samplepool,
       
   687           lbuf,
       
   688           rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_LEFT);
       
   689       visual_audio_samplepool_input_channel (visual->audio->samplepool,
       
   690           rbuf,
       
   691           rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_RIGHT);
       
   692 
       
   693       visual_object_unref (VISUAL_OBJECT (lbuf));
       
   694       visual_object_unref (VISUAL_OBJECT (rbuf));
       
   695 
       
   696     }
       
   697 #else
       
   698     if (visual->channels == 2) {
       
   699       for (i = 0; i < 512; i++) {
       
   700         visual->audio->plugpcm[0][i] = *data++;
       
   701         visual->audio->plugpcm[1][i] = *data++;
       
   702       }
       
   703     } else {
       
   704       for (i = 0; i < 512; i++) {
       
   705         visual->audio->plugpcm[0][i] = *data;
       
   706         visual->audio->plugpcm[1][i] = *data++;
       
   707       }
       
   708     }
       
   709 #endif
       
   710 
       
   711     /* alloc a buffer if we don't have one yet, this happens
       
   712      * when we pushed a buffer in this while loop before */
       
   713     if (outbuf == NULL) {
       
   714       ret = get_buffer (visual, &outbuf);
       
   715       if (ret != GST_FLOW_OK) {
       
   716         goto beach;
       
   717       }
       
   718     }
       
   719     visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf));
       
   720     visual_audio_analyze (visual->audio);
       
   721     visual_actor_run (visual->actor, visual->audio);
       
   722     visual_video_set_buffer (visual->video, NULL);
       
   723     GST_DEBUG_OBJECT (visual, "rendered one frame");
       
   724 
       
   725     GST_BUFFER_TIMESTAMP (outbuf) = visual->next_ts;
       
   726     GST_BUFFER_DURATION (outbuf) = visual->duration;
       
   727 
       
   728     ret = gst_pad_push (visual->srcpad, outbuf);
       
   729     outbuf = NULL;
       
   730 
       
   731   skip:
       
   732     /* interpollate next timestamp */
       
   733     if (visual->next_ts != -1)
       
   734       visual->next_ts += visual->duration;
       
   735 
       
   736     GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input",
       
   737         visual->spf);
       
   738 
       
   739     /* Flush out the number of samples per frame */
       
   740     gst_adapter_flush (visual->adapter, visual->spf * visual->bps);
       
   741 
       
   742     /* quit the loop if something was wrong */
       
   743     if (ret != GST_FLOW_OK)
       
   744       break;
       
   745   }
       
   746 
       
   747 beach:
       
   748 
       
   749   if (outbuf != NULL)
       
   750     gst_buffer_unref (outbuf);
       
   751 
       
   752   gst_object_unref (visual);
       
   753 
       
   754   return ret;
       
   755 }
       
   756 
       
   757 static GstStateChangeReturn
       
   758 gst_visual_change_state (GstElement * element, GstStateChange transition)
       
   759 {
       
   760   GstVisual *visual = GST_VISUAL (element);
       
   761   GstStateChangeReturn ret;
       
   762 
       
   763   switch (transition) {
       
   764     case GST_STATE_CHANGE_NULL_TO_READY:
       
   765       visual->actor =
       
   766           visual_actor_new (GST_VISUAL_GET_CLASS (visual)->plugin->info->
       
   767           plugname);
       
   768       visual->video = visual_video_new ();
       
   769       visual->audio = visual_audio_new ();
       
   770       /* can't have a play without actors */
       
   771       if (!visual->actor || !visual->video)
       
   772         goto no_actors;
       
   773 
       
   774       if (visual_actor_realize (visual->actor) != 0)
       
   775         goto no_realize;
       
   776 
       
   777       visual_actor_set_video (visual->actor, visual->video);
       
   778       break;
       
   779     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
   780       gst_visual_reset (visual);
       
   781       break;
       
   782     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       
   783       break;
       
   784     default:
       
   785       break;
       
   786   }
       
   787 
       
   788   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
   789 
       
   790   switch (transition) {
       
   791     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       
   792       break;
       
   793     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
   794       break;
       
   795     case GST_STATE_CHANGE_READY_TO_NULL:
       
   796       gst_visual_clear_actors (visual);
       
   797       break;
       
   798     default:
       
   799       break;
       
   800   }
       
   801 
       
   802   return ret;
       
   803 
       
   804   /* ERRORS */
       
   805 no_actors:
       
   806   {
       
   807     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
       
   808         ("could not create actors"));
       
   809     gst_visual_clear_actors (visual);
       
   810     return GST_STATE_CHANGE_FAILURE;
       
   811   }
       
   812 no_realize:
       
   813   {
       
   814     GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
       
   815         ("could not realize actor"));
       
   816     gst_visual_clear_actors (visual);
       
   817     return GST_STATE_CHANGE_FAILURE;
       
   818   }
       
   819 }
       
   820 
       
   821 static void
       
   822 make_valid_name (char *name)
       
   823 {
       
   824   /*
       
   825    * Replace invalid chars with _ in the type name
       
   826    */
       
   827   static const gchar extra_chars[] = "-_+";
       
   828   gchar *p = name;
       
   829 
       
   830   for (; *p; p++) {
       
   831     int valid = ((p[0] >= 'A' && p[0] <= 'Z') ||
       
   832         (p[0] >= 'a' && p[0] <= 'z') ||
       
   833         (p[0] >= '0' && p[0] <= '9') || strchr (extra_chars, p[0]));
       
   834     if (!valid)
       
   835       *p = '_';
       
   836   }
       
   837 }
       
   838 
       
   839 static gboolean
       
   840 gst_visual_actor_plugin_is_gl (VisObject * plugin, const gchar * name)
       
   841 {
       
   842   gboolean is_gl;
       
   843   gint depth;
       
   844 
       
   845 #if !defined(VISUAL_API_VERSION)
       
   846 
       
   847   depth = VISUAL_PLUGIN_ACTOR (plugin)->depth;
       
   848   is_gl = (depth == VISUAL_VIDEO_DEPTH_GL);
       
   849 
       
   850 #elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
       
   851 
       
   852   depth = VISUAL_ACTOR_PLUGIN (plugin)->vidoptions.depth;
       
   853   /* FIXME: how to figure this out correctly in 0.4? */
       
   854   is_gl = (depth & VISUAL_VIDEO_DEPTH_GL) == VISUAL_VIDEO_DEPTH_GL;
       
   855 
       
   856 #else
       
   857 # error what libvisual version is this?
       
   858 #endif
       
   859 
       
   860   if (!is_gl) {
       
   861     GST_DEBUG ("plugin %s is not a GL plugin (%d), registering", name, depth);
       
   862   } else {
       
   863     GST_DEBUG ("plugin %s is a GL plugin (%d), ignoring", name, depth);
       
   864   }
       
   865 
       
   866   return is_gl;
       
   867 }
       
   868 
       
   869 static gboolean
       
   870 plugin_init (GstPlugin * plugin)
       
   871 {
       
   872   guint i, count;
       
   873   VisList *list;
       
   874 
       
   875   GST_DEBUG_CATEGORY_INIT (libvisual_debug, "libvisual", 0,
       
   876       "libvisual audio visualisations");
       
   877 
       
   878   visual_log_set_verboseness (VISUAL_LOG_VERBOSENESS_LOW);
       
   879   visual_log_set_info_handler (libvisual_log_handler, (void *) GST_LEVEL_INFO);
       
   880   visual_log_set_warning_handler (libvisual_log_handler,
       
   881       (void *) GST_LEVEL_WARNING);
       
   882   visual_log_set_critical_handler (libvisual_log_handler,
       
   883       (void *) GST_LEVEL_ERROR);
       
   884   visual_log_set_error_handler (libvisual_log_handler,
       
   885       (void *) GST_LEVEL_ERROR);
       
   886 
       
   887   if (!visual_is_initialized ())
       
   888     if (visual_init (NULL, NULL) != 0)
       
   889       return FALSE;
       
   890 
       
   891   list = visual_actor_get_list ();
       
   892 
       
   893 #if !defined(VISUAL_API_VERSION)
       
   894   count = visual_list_count (list);
       
   895 #elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
       
   896   count = visual_collection_size (VISUAL_COLLECTION (list));
       
   897 #endif
       
   898 
       
   899   for (i = 0; i < count; i++) {
       
   900     VisPluginRef *ref = visual_list_get (list, i);
       
   901     VisPluginData *visplugin = NULL;
       
   902     gboolean skip = FALSE;
       
   903     GType type;
       
   904     gchar *name;
       
   905     GTypeInfo info = {
       
   906       sizeof (GstVisualClass),
       
   907       NULL,
       
   908       NULL,
       
   909       gst_visual_class_init,
       
   910       NULL,
       
   911       ref,
       
   912       sizeof (GstVisual),
       
   913       0,
       
   914       NULL
       
   915     };
       
   916 
       
   917     visplugin = visual_plugin_load (ref);
       
   918 
       
   919     if (ref->info->plugname == NULL)
       
   920       continue;
       
   921 
       
   922     /* Blacklist some plugins */
       
   923     if (strcmp (ref->info->plugname, "gstreamer") == 0 ||
       
   924         strcmp (ref->info->plugname, "gdkpixbuf") == 0) {
       
   925       skip = TRUE;
       
   926     } else {
       
   927       /* Ignore plugins that only support GL output for now */
       
   928       skip = gst_visual_actor_plugin_is_gl (visplugin->info->plugin,
       
   929           visplugin->info->plugname);
       
   930     }
       
   931 
       
   932     visual_plugin_unload (visplugin);
       
   933 
       
   934     if (!skip) {
       
   935       name = g_strdup_printf ("GstVisual%s", ref->info->plugname);
       
   936       make_valid_name (name);
       
   937       type = g_type_register_static (GST_TYPE_VISUAL, name, &info, 0);
       
   938       g_free (name);
       
   939 
       
   940       name = g_strdup_printf ("libvisual_%s", ref->info->plugname);
       
   941       make_valid_name (name);
       
   942       if (!gst_element_register (plugin, name, GST_RANK_NONE, type)) {
       
   943         g_free (name);
       
   944         return FALSE;
       
   945       }
       
   946       g_free (name);
       
   947     }
       
   948   }
       
   949 
       
   950   return TRUE;
       
   951 }
       
   952 
       
   953 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
       
   954     GST_VERSION_MINOR,
       
   955     "libvisual",
       
   956     "libvisual visualization plugins",
       
   957     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)