gst_plugins_base/gst/adder/gstadder.c
changeset 2 5505e8908944
parent 0 0e761a78d257
child 7 567bb019e3e3
equal deleted inserted replaced
1:4c282e7dd6d3 2:5505e8908944
       
     1 /* GStreamer
       
     2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
       
     3  *                    2001 Thomas <thomas@apestaart.org>
       
     4  *               2005,2006 Wim Taymans <wim@fluendo.com>
       
     5  *
       
     6  * adder.c: Adder element, N in, one out, samples are added
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Library General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Library General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Library General Public
       
    19  * License along with this library; if not, write to the
       
    20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    21  * Boston, MA 02111-1307, USA.
       
    22  */
       
    23 /**
       
    24  * SECTION:element-adder
       
    25  *
       
    26  * <refsect2>
       
    27  * <para>
       
    28  * The Adder allows to mix several streams into one by adding the data.
       
    29  * Mixed data is clamped to the min/max values of the data format.
       
    30  * </para>
       
    31  * <title>Example launch line</title>
       
    32  * <para>
       
    33  * <programlisting>
       
    34  * gst-launch audiotestsrc freq=100 ! adder name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
       
    35  * </programlisting>
       
    36  * This pipeline produces two sine waves mixed together.
       
    37  * </para>
       
    38  * <para>
       
    39  * The Adder currently mixes all data received on the sinkpads as soon as possible
       
    40  * without trying to synchronize the streams.
       
    41  * </para>
       
    42  * </refsect2>
       
    43  *
       
    44  * Last reviewed on 2006-05-09 (0.10.7)
       
    45  */
       
    46 /* Element-Checklist-Version: 5 */
       
    47 
       
    48 #ifdef HAVE_CONFIG_H
       
    49 #include "config.h"
       
    50 #endif
       
    51 #include "gstadder.h"
       
    52 #include <gst/audio/audio.h>
       
    53 #include <string.h>             /* strcmp */
       
    54 
       
    55 #ifdef __SYMBIAN32__
       
    56 #include <glib_global.h>
       
    57 #endif
       
    58 
       
    59 /* highest positive/lowest negative x-bit value we can use for clamping */
       
    60 #define MAX_INT_32  ((gint32) (0x7fffffff))
       
    61 #define MAX_INT_16  ((gint16) (0x7fff))
       
    62 #define MAX_INT_8   ((gint8)  (0x7f))
       
    63 #define MAX_UINT_32 ((guint32)(0xffffffff))
       
    64 #define MAX_UINT_16 ((guint16)(0xffff))
       
    65 #define MAX_UINT_8  ((guint8) (0xff))
       
    66 
       
    67 #define MIN_INT_32  ((gint32) (0x80000000))
       
    68 #define MIN_INT_16  ((gint16) (0x8000))
       
    69 #define MIN_INT_8   ((gint8)  (0x80))
       
    70 #define MIN_UINT_32 ((guint32)(0x00000000))
       
    71 #define MIN_UINT_16 ((guint16)(0x0000))
       
    72 #define MIN_UINT_8  ((guint8) (0x00))
       
    73 
       
    74 #define GST_CAT_DEFAULT gst_adder_debug
       
    75 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
       
    76 
       
    77 /* elementfactory information */
       
    78 static const GstElementDetails adder_details = GST_ELEMENT_DETAILS ("Adder",
       
    79     "Generic/Audio",
       
    80     "Add N audio channels together",
       
    81     "Thomas <thomas@apestaart.org>");
       
    82 
       
    83 static GstStaticPadTemplate gst_adder_src_template =
       
    84     GST_STATIC_PAD_TEMPLATE ("src",
       
    85     GST_PAD_SRC,
       
    86     GST_PAD_ALWAYS,
       
    87     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
       
    88         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
       
    89     );
       
    90 
       
    91 static GstStaticPadTemplate gst_adder_sink_template =
       
    92     GST_STATIC_PAD_TEMPLATE ("sink%d",
       
    93     GST_PAD_SINK,
       
    94     GST_PAD_REQUEST,
       
    95     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
       
    96         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
       
    97     );
       
    98 
       
    99 static void gst_adder_class_init (GstAdderClass * klass);
       
   100 static void gst_adder_init (GstAdder * adder);
       
   101 static void gst_adder_finalize (GObject * object);
       
   102 
       
   103 static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
       
   104 static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
       
   105 static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
       
   106 static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
       
   107 
       
   108 static GstPad *gst_adder_request_new_pad (GstElement * element,
       
   109     GstPadTemplate * temp, const gchar * unused);
       
   110 static void gst_adder_release_pad (GstElement * element, GstPad * pad);
       
   111 
       
   112 static GstStateChangeReturn gst_adder_change_state (GstElement * element,
       
   113     GstStateChange transition);
       
   114 
       
   115 static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
       
   116     gpointer user_data);
       
   117 
       
   118 static GstElementClass *parent_class = NULL;
       
   119 #ifdef __SYMBIAN32__
       
   120 EXPORT_C
       
   121 #endif
       
   122 
       
   123 
       
   124 GType
       
   125 gst_adder_get_type (void)
       
   126 {
       
   127   static GType adder_type = 0;
       
   128 
       
   129   if (G_UNLIKELY (adder_type == 0)) {
       
   130     static const GTypeInfo adder_info = {
       
   131       sizeof (GstAdderClass), NULL, NULL,
       
   132       (GClassInitFunc) gst_adder_class_init, NULL, NULL,
       
   133       sizeof (GstAdder), 0,
       
   134       (GInstanceInitFunc) gst_adder_init,
       
   135     };
       
   136 
       
   137     adder_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAdder",
       
   138         &adder_info, 0);
       
   139     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "adder", 0,
       
   140         "audio channel mixing element");
       
   141   }
       
   142   return adder_type;
       
   143 }
       
   144 
       
   145 /* clipping versions */
       
   146 #define MAKE_FUNC(name,type,ttype,min,max)                      \
       
   147 static void name (type *out, type *in, gint bytes) {            \
       
   148   gint i;                                                       \
       
   149   for (i = 0; i < bytes / sizeof (type); i++)                   \
       
   150     out[i] = CLAMP ((ttype)out[i] + (ttype)in[i], min, max);    \
       
   151 }
       
   152 
       
   153 /* non-clipping versions (for float) */
       
   154 #define MAKE_FUNC_NC(name,type,ttype)                           \
       
   155 static void name (type *out, type *in, gint bytes) {            \
       
   156   gint i;                                                       \
       
   157   for (i = 0; i < bytes / sizeof (type); i++)                   \
       
   158     out[i] = (ttype)out[i] + (ttype)in[i];                      \
       
   159 }
       
   160 
       
   161 /* *INDENT-OFF* */
       
   162 MAKE_FUNC (add_int32, gint32, gint64, MIN_INT_32, MAX_INT_32)
       
   163 MAKE_FUNC (add_int16, gint16, gint32, MIN_INT_16, MAX_INT_16)
       
   164 MAKE_FUNC (add_int8, gint8, gint16, MIN_INT_8, MAX_INT_8)
       
   165 MAKE_FUNC (add_uint32, guint32, guint64, MIN_UINT_32, MAX_UINT_32)
       
   166 MAKE_FUNC (add_uint16, guint16, guint32, MIN_UINT_16, MAX_UINT_16)
       
   167 MAKE_FUNC (add_uint8, guint8, guint16, MIN_UINT_8, MAX_UINT_8)
       
   168 MAKE_FUNC_NC (add_float64, gdouble, gdouble)
       
   169 MAKE_FUNC_NC (add_float32, gfloat, gfloat)
       
   170 /* *INDENT-ON* */
       
   171 
       
   172 /* we can only accept caps that we and downstream can handle. */
       
   173 static GstCaps *
       
   174 gst_adder_sink_getcaps (GstPad * pad)
       
   175 {
       
   176   GstAdder *adder;
       
   177   GstCaps *result, *peercaps, *sinkcaps;
       
   178 
       
   179   adder = GST_ADDER (GST_PAD_PARENT (pad));
       
   180 
       
   181   GST_OBJECT_LOCK (adder);
       
   182   /* get the downstream possible caps */
       
   183   peercaps = gst_pad_peer_get_caps (adder->srcpad);
       
   184   /* get the allowed caps on this sinkpad, we use the fixed caps function so
       
   185    * that it does not call recursively in this function. */
       
   186   sinkcaps = gst_pad_get_fixed_caps_func (pad);
       
   187   if (peercaps) {
       
   188     /* if the peer has caps, intersect */
       
   189     GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
       
   190     result = gst_caps_intersect (peercaps, sinkcaps);
       
   191     gst_caps_unref (peercaps);
       
   192     gst_caps_unref (sinkcaps);
       
   193   } else {
       
   194     /* the peer has no caps (or there is no peer), just use the allowed caps
       
   195      * of this sinkpad. */
       
   196     GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
       
   197     result = sinkcaps;
       
   198   }
       
   199   GST_OBJECT_UNLOCK (adder);
       
   200 
       
   201   return result;
       
   202 }
       
   203 
       
   204 /* the first caps we receive on any of the sinkpads will define the caps for all
       
   205  * the other sinkpads because we can only mix streams with the same caps.
       
   206  * */
       
   207 static gboolean
       
   208 gst_adder_setcaps (GstPad * pad, GstCaps * caps)
       
   209 {
       
   210   GstAdder *adder;
       
   211   GList *pads;
       
   212   GstStructure *structure;
       
   213   const char *media_type;
       
   214 
       
   215   adder = GST_ADDER (GST_PAD_PARENT (pad));
       
   216 
       
   217   GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
       
   218       GST_PAD_NAME (pad), caps);
       
   219 
       
   220   /* FIXME, see if the other pads can accept the format. Also lock the
       
   221    * format on the other pads to this new format. */
       
   222   GST_OBJECT_LOCK (adder);
       
   223   pads = GST_ELEMENT (adder)->pads;
       
   224   while (pads) {
       
   225     GstPad *otherpad = GST_PAD (pads->data);
       
   226 
       
   227     if (otherpad != pad) {
       
   228       gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
       
   229     }
       
   230     pads = g_list_next (pads);
       
   231   }
       
   232   GST_OBJECT_UNLOCK (adder);
       
   233 
       
   234   /* parse caps now */
       
   235   structure = gst_caps_get_structure (caps, 0);
       
   236   media_type = gst_structure_get_name (structure);
       
   237   if (strcmp (media_type, "audio/x-raw-int") == 0) {
       
   238     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format int");
       
   239     adder->format = GST_ADDER_FORMAT_INT;
       
   240     gst_structure_get_int (structure, "width", &adder->width);
       
   241     gst_structure_get_int (structure, "depth", &adder->depth);
       
   242     gst_structure_get_int (structure, "endianness", &adder->endianness);
       
   243     gst_structure_get_boolean (structure, "signed", &adder->is_signed);
       
   244 
       
   245     if (adder->endianness != G_BYTE_ORDER)
       
   246       goto not_supported;
       
   247 
       
   248     switch (adder->width) {
       
   249       case 8:
       
   250         adder->func = (adder->is_signed ?
       
   251             (GstAdderFunction) add_int8 : (GstAdderFunction) add_uint8);
       
   252         break;
       
   253       case 16:
       
   254         adder->func = (adder->is_signed ?
       
   255             (GstAdderFunction) add_int16 : (GstAdderFunction) add_uint16);
       
   256         break;
       
   257       case 32:
       
   258         adder->func = (adder->is_signed ?
       
   259             (GstAdderFunction) add_int32 : (GstAdderFunction) add_uint32);
       
   260         break;
       
   261       default:
       
   262         goto not_supported;
       
   263     }
       
   264   } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
       
   265     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format float");
       
   266     adder->format = GST_ADDER_FORMAT_FLOAT;
       
   267     gst_structure_get_int (structure, "width", &adder->width);
       
   268 
       
   269     switch (adder->width) {
       
   270       case 32:
       
   271         adder->func = (GstAdderFunction) add_float32;
       
   272         break;
       
   273       case 64:
       
   274         adder->func = (GstAdderFunction) add_float64;
       
   275         break;
       
   276       default:
       
   277         goto not_supported;
       
   278     }
       
   279   } else {
       
   280     goto not_supported;
       
   281   }
       
   282 
       
   283   gst_structure_get_int (structure, "channels", &adder->channels);
       
   284   gst_structure_get_int (structure, "rate", &adder->rate);
       
   285   /* precalc bps */
       
   286   adder->bps = (adder->width / 8) * adder->channels;
       
   287 
       
   288   return TRUE;
       
   289 
       
   290   /* ERRORS */
       
   291 not_supported:
       
   292   {
       
   293     GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
       
   294     return FALSE;
       
   295   }
       
   296 }
       
   297 
       
   298 /* FIXME, the duration query should reflect how long you will produce
       
   299  * data, that is the amount of stream time until you will emit EOS.
       
   300  *
       
   301  * For synchronized mixing this is always the max of all the durations
       
   302  * of upstream since we emit EOS when all of them finished.
       
   303  *
       
   304  * We don't do synchronized mixing so this really depends on where the
       
   305  * streams where punched in and what their relative offsets are against
       
   306  * eachother which we can get from the first timestamps we see.
       
   307  *
       
   308  * When we add a new stream (or remove a stream) the duration might
       
   309  * also become invalid again and we need to post a new DURATION
       
   310  * message to notify this fact to the parent.
       
   311  * For now we take the max of all the upstream elements so the simple
       
   312  * cases work at least somewhat.
       
   313  */
       
   314 static gboolean
       
   315 gst_adder_query_duration (GstAdder * adder, GstQuery * query)
       
   316 {
       
   317   gint64 max;
       
   318   gboolean res;
       
   319   GstFormat format;
       
   320   GstIterator *it;
       
   321   gboolean done;
       
   322 
       
   323   /* parse format */
       
   324   gst_query_parse_duration (query, &format, NULL);
       
   325 
       
   326   max = -1;
       
   327   res = TRUE;
       
   328   done = FALSE;
       
   329 
       
   330   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
       
   331   while (!done) {
       
   332     GstIteratorResult ires;
       
   333     gpointer item;
       
   334 
       
   335     ires = gst_iterator_next (it, &item);
       
   336     switch (ires) {
       
   337       case GST_ITERATOR_DONE:
       
   338         done = TRUE;
       
   339         break;
       
   340       case GST_ITERATOR_OK:
       
   341       {
       
   342         GstPad *pad = GST_PAD_CAST (item);
       
   343         gint64 duration;
       
   344 
       
   345         /* ask sink peer for duration */
       
   346         res &= gst_pad_query_peer_duration (pad, &format, &duration);
       
   347         /* take max from all valid return values */
       
   348         if (res) {
       
   349           /* valid unknown length, stop searching */
       
   350           if (duration == -1) {
       
   351             max = duration;
       
   352             done = TRUE;
       
   353           }
       
   354           /* else see if bigger than current max */
       
   355           else if (duration > max)
       
   356             max = duration;
       
   357         }
       
   358         break;
       
   359       }
       
   360       case GST_ITERATOR_RESYNC:
       
   361         max = -1;
       
   362         res = TRUE;
       
   363         break;
       
   364       default:
       
   365         res = FALSE;
       
   366         done = TRUE;
       
   367         break;
       
   368     }
       
   369   }
       
   370   gst_iterator_free (it);
       
   371 
       
   372   if (res) {
       
   373     /* and store the max */
       
   374     gst_query_set_duration (query, format, max);
       
   375   }
       
   376 
       
   377   return res;
       
   378 }
       
   379 
       
   380 static gboolean
       
   381 gst_adder_query (GstPad * pad, GstQuery * query)
       
   382 {
       
   383   GstAdder *adder = GST_ADDER (gst_pad_get_parent (pad));
       
   384   gboolean res = FALSE;
       
   385 
       
   386   switch (GST_QUERY_TYPE (query)) {
       
   387     case GST_QUERY_POSITION:
       
   388     {
       
   389       GstFormat format;
       
   390 
       
   391       gst_query_parse_position (query, &format, NULL);
       
   392 
       
   393       switch (format) {
       
   394         case GST_FORMAT_TIME:
       
   395           /* FIXME, bring to stream time, might be tricky */
       
   396           gst_query_set_position (query, format, adder->timestamp);
       
   397           res = TRUE;
       
   398           break;
       
   399         case GST_FORMAT_DEFAULT:
       
   400           gst_query_set_position (query, format, adder->offset);
       
   401           res = TRUE;
       
   402           break;
       
   403         default:
       
   404           break;
       
   405       }
       
   406       break;
       
   407     }
       
   408     case GST_QUERY_DURATION:
       
   409       res = gst_adder_query_duration (adder, query);
       
   410       break;
       
   411     default:
       
   412       /* FIXME, needs a custom query handler because we have multiple
       
   413        * sinkpads */
       
   414       res = gst_pad_query_default (pad, query);
       
   415       break;
       
   416   }
       
   417 
       
   418   gst_object_unref (adder);
       
   419   return res;
       
   420 }
       
   421 
       
   422 static gboolean
       
   423 forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
       
   424 {
       
   425   gst_event_ref (event);
       
   426   GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
       
   427   if (!gst_pad_push_event (pad, event)) {
       
   428     g_value_set_boolean (ret, FALSE);
       
   429     GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
       
   430         event, GST_EVENT_TYPE_NAME (event));
       
   431   } else {
       
   432     GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
       
   433         event, GST_EVENT_TYPE_NAME (event));
       
   434   }
       
   435   gst_object_unref (pad);
       
   436   return TRUE;
       
   437 }
       
   438 
       
   439 /* forwards the event to all sinkpads, takes ownership of the
       
   440  * event
       
   441  *
       
   442  * Returns: TRUE if the event could be forwarded on all
       
   443  * sinkpads.
       
   444  */
       
   445 static gboolean
       
   446 forward_event (GstAdder * adder, GstEvent * event)
       
   447 {
       
   448   gboolean ret;
       
   449   GstIterator *it;
       
   450   GValue vret = { 0 };
       
   451 
       
   452   GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
       
   453       GST_EVENT_TYPE_NAME (event));
       
   454 
       
   455   ret = TRUE;
       
   456 
       
   457   g_value_init (&vret, G_TYPE_BOOLEAN);
       
   458   g_value_set_boolean (&vret, TRUE);
       
   459   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
       
   460   gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
       
   461       event);
       
   462   gst_iterator_free (it);
       
   463   gst_event_unref (event);
       
   464 
       
   465   ret = g_value_get_boolean (&vret);
       
   466 
       
   467   return ret;
       
   468 }
       
   469 
       
   470 static gboolean
       
   471 gst_adder_src_event (GstPad * pad, GstEvent * event)
       
   472 {
       
   473   GstAdder *adder;
       
   474   gboolean result;
       
   475 
       
   476   adder = GST_ADDER (gst_pad_get_parent (pad));
       
   477 
       
   478   switch (GST_EVENT_TYPE (event)) {
       
   479     case GST_EVENT_QOS:
       
   480       /* QoS might be tricky */
       
   481       result = FALSE;
       
   482       break;
       
   483     case GST_EVENT_SEEK:
       
   484     {
       
   485       GstSeekFlags flags;
       
   486       GstSeekType curtype;
       
   487       gint64 cur;
       
   488 
       
   489       /* parse the seek parameters */
       
   490       gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
       
   491           &cur, NULL, NULL);
       
   492 
       
   493       /* check if we are flushing */
       
   494       if (flags & GST_SEEK_FLAG_FLUSH) {
       
   495         /* make sure we accept nothing anymore and return WRONG_STATE */
       
   496         gst_collect_pads_set_flushing (adder->collect, TRUE);
       
   497 
       
   498         /* flushing seek, start flush downstream, the flush will be done
       
   499          * when all pads received a FLUSH_STOP. */
       
   500         gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
       
   501       }
       
   502 
       
   503       /* now wait for the collected to be finished and mark a new
       
   504        * segment */
       
   505       GST_OBJECT_LOCK (adder->collect);
       
   506       if (curtype == GST_SEEK_TYPE_SET)
       
   507         adder->segment_position = cur;
       
   508       else
       
   509         adder->segment_position = 0;
       
   510       adder->segment_pending = TRUE;
       
   511       GST_OBJECT_UNLOCK (adder->collect);
       
   512 
       
   513       result = forward_event (adder, event);
       
   514       break;
       
   515     }
       
   516     case GST_EVENT_NAVIGATION:
       
   517       /* navigation is rather pointless. */
       
   518       result = FALSE;
       
   519       break;
       
   520     default:
       
   521       /* just forward the rest for now */
       
   522       result = forward_event (adder, event);
       
   523       break;
       
   524   }
       
   525   gst_object_unref (adder);
       
   526 
       
   527   return result;
       
   528 }
       
   529 
       
   530 static gboolean
       
   531 gst_adder_sink_event (GstPad * pad, GstEvent * event)
       
   532 {
       
   533   GstAdder *adder;
       
   534   gboolean ret;
       
   535 
       
   536   adder = GST_ADDER (gst_pad_get_parent (pad));
       
   537 
       
   538   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
       
   539       GST_DEBUG_PAD_NAME (pad));
       
   540 
       
   541   switch (GST_EVENT_TYPE (event)) {
       
   542     case GST_EVENT_FLUSH_STOP:
       
   543       /* mark a pending new segment. This event is synchronized
       
   544        * with the streaming thread so we can safely update the
       
   545        * variable without races. It's somewhat weird because we
       
   546        * assume the collectpads forwarded the FLUSH_STOP past us
       
   547        * and downstream (using our source pad, the bastard!).
       
   548        */
       
   549       adder->segment_pending = TRUE;
       
   550       break;
       
   551     default:
       
   552       break;
       
   553   }
       
   554 
       
   555   /* now GstCollectPads can take care of the rest, e.g. EOS */
       
   556   ret = adder->collect_event (pad, event);
       
   557 
       
   558   gst_object_unref (adder);
       
   559   return ret;
       
   560 }
       
   561 
       
   562 static void
       
   563 gst_adder_class_init (GstAdderClass * klass)
       
   564 {
       
   565   GObjectClass *gobject_class;
       
   566   GstElementClass *gstelement_class;
       
   567 
       
   568   gobject_class = (GObjectClass *) klass;
       
   569 
       
   570   gobject_class->finalize = gst_adder_finalize;
       
   571 
       
   572   gstelement_class = (GstElementClass *) klass;
       
   573 
       
   574   gst_element_class_add_pad_template (gstelement_class,
       
   575       gst_static_pad_template_get (&gst_adder_src_template));
       
   576   gst_element_class_add_pad_template (gstelement_class,
       
   577       gst_static_pad_template_get (&gst_adder_sink_template));
       
   578   gst_element_class_set_details (gstelement_class, &adder_details);
       
   579 
       
   580   parent_class = g_type_class_peek_parent (klass);
       
   581 
       
   582   gstelement_class->request_new_pad = gst_adder_request_new_pad;
       
   583   gstelement_class->release_pad = gst_adder_release_pad;
       
   584   gstelement_class->change_state = gst_adder_change_state;
       
   585 }
       
   586 
       
   587 static void
       
   588 gst_adder_init (GstAdder * adder)
       
   589 {
       
   590   GstPadTemplate *template;
       
   591 
       
   592   template = gst_static_pad_template_get (&gst_adder_src_template);
       
   593   adder->srcpad = gst_pad_new_from_template (template, "src");
       
   594   gst_object_unref (template);
       
   595   gst_pad_set_getcaps_function (adder->srcpad,
       
   596       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
       
   597   gst_pad_set_setcaps_function (adder->srcpad,
       
   598       GST_DEBUG_FUNCPTR (gst_adder_setcaps));
       
   599   gst_pad_set_query_function (adder->srcpad,
       
   600       GST_DEBUG_FUNCPTR (gst_adder_query));
       
   601   gst_pad_set_event_function (adder->srcpad,
       
   602       GST_DEBUG_FUNCPTR (gst_adder_src_event));
       
   603   gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
       
   604 
       
   605   adder->format = GST_ADDER_FORMAT_UNSET;
       
   606   adder->padcount = 0;
       
   607   adder->func = NULL;
       
   608 
       
   609   /* keep track of the sinkpads requested */
       
   610   adder->collect = gst_collect_pads_new ();
       
   611   gst_collect_pads_set_function (adder->collect,
       
   612       GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
       
   613 }
       
   614 
       
   615 static void
       
   616 gst_adder_finalize (GObject * object)
       
   617 {
       
   618   GstAdder *adder = GST_ADDER (object);
       
   619 
       
   620   gst_object_unref (adder->collect);
       
   621   adder->collect = NULL;
       
   622 
       
   623   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   624 }
       
   625 
       
   626 static GstPad *
       
   627 gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
       
   628     const gchar * unused)
       
   629 {
       
   630   gchar *name;
       
   631   GstAdder *adder;
       
   632   GstPad *newpad;
       
   633   gint padcount;
       
   634 
       
   635   if (templ->direction != GST_PAD_SINK)
       
   636     goto not_sink;
       
   637 
       
   638   adder = GST_ADDER (element);
       
   639 
       
   640   /* increment pad counter */
       
   641   padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
       
   642 
       
   643   name = g_strdup_printf ("sink%d", padcount);
       
   644   newpad = gst_pad_new_from_template (templ, name);
       
   645   GST_DEBUG_OBJECT (adder, "request new pad %s", name);
       
   646   g_free (name);
       
   647 
       
   648   gst_pad_set_getcaps_function (newpad,
       
   649       GST_DEBUG_FUNCPTR (gst_adder_sink_getcaps));
       
   650   gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_setcaps));
       
   651   gst_collect_pads_add_pad (adder->collect, newpad, sizeof (GstCollectData));
       
   652 
       
   653   /* FIXME: hacked way to override/extend the event function of
       
   654    * GstCollectPads; because it sets its own event function giving the
       
   655    * element no access to events */
       
   656   adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
       
   657   gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event));
       
   658 
       
   659   /* takes ownership of the pad */
       
   660   if (!gst_element_add_pad (GST_ELEMENT (adder), newpad))
       
   661     goto could_not_add;
       
   662 
       
   663   return newpad;
       
   664 
       
   665   /* errors */
       
   666 not_sink:
       
   667   {
       
   668     g_warning ("gstadder: request new pad that is not a SINK pad\n");
       
   669     return NULL;
       
   670   }
       
   671 could_not_add:
       
   672   {
       
   673     GST_DEBUG_OBJECT (adder, "could not add pad");
       
   674     gst_collect_pads_remove_pad (adder->collect, newpad);
       
   675     gst_object_unref (newpad);
       
   676     return NULL;
       
   677   }
       
   678 }
       
   679 
       
   680 static void
       
   681 gst_adder_release_pad (GstElement * element, GstPad * pad)
       
   682 {
       
   683   GstAdder *adder;
       
   684 
       
   685   adder = GST_ADDER (element);
       
   686 
       
   687   GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
       
   688 
       
   689   gst_collect_pads_remove_pad (adder->collect, pad);
       
   690   gst_element_remove_pad (element, pad);
       
   691 }
       
   692 
       
   693 static GstFlowReturn
       
   694 gst_adder_collected (GstCollectPads * pads, gpointer user_data)
       
   695 {
       
   696   /*
       
   697    * combine channels by adding sample values
       
   698    * basic algorithm :
       
   699    * - this function is called when all pads have a buffer
       
   700    * - get available bytes on all pads.
       
   701    * - repeat for each input pad :
       
   702    *   - read available bytes, copy or add to target buffer
       
   703    *   - if there's an EOS event, remove the input channel
       
   704    * - push out the output buffer
       
   705    */
       
   706   GstAdder *adder;
       
   707   guint size;
       
   708   GSList *collected;
       
   709   GstBuffer *outbuf;
       
   710   GstFlowReturn ret;
       
   711   gpointer outbytes;
       
   712   gboolean empty = TRUE;
       
   713 
       
   714   adder = GST_ADDER (user_data);
       
   715 
       
   716   /* this is fatal */
       
   717   if (G_UNLIKELY (adder->func == NULL))
       
   718     goto not_negotiated;
       
   719 
       
   720   /* get available bytes for reading, this can be 0 which could mean
       
   721    * empty buffers or EOS, which we will catch when we loop over the
       
   722    * pads. */
       
   723   size = gst_collect_pads_available (pads);
       
   724 
       
   725   GST_LOG_OBJECT (adder,
       
   726       "starting to cycle through channels, %d bytes available (bps = %d)", size,
       
   727       adder->bps);
       
   728 
       
   729   outbuf = NULL;
       
   730   outbytes = NULL;
       
   731 
       
   732   for (collected = pads->data; collected; collected = g_slist_next (collected)) {
       
   733     GstCollectData *data;
       
   734     guint8 *bytes;
       
   735     guint len;
       
   736     GstBuffer *inbuf;
       
   737 
       
   738     data = (GstCollectData *) collected->data;
       
   739 
       
   740     /* get a subbuffer of size bytes */
       
   741     inbuf = gst_collect_pads_take_buffer (pads, data, size);
       
   742     /* NULL means EOS or an empty buffer so we still need to flush in
       
   743      * case of an empty buffer. */
       
   744     if (inbuf == NULL) {
       
   745       GST_LOG_OBJECT (adder, "channel %p: no bytes available", data);
       
   746       goto next;
       
   747     }
       
   748 
       
   749     bytes = GST_BUFFER_DATA (inbuf);
       
   750     len = GST_BUFFER_SIZE (inbuf);
       
   751 
       
   752     if (outbuf == NULL) {
       
   753       GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes",
       
   754           data, size);
       
   755 
       
   756       /* first buffer, alloc size bytes. FIXME, we can easily subbuffer
       
   757        * and _make_writable. */
       
   758       outbuf = gst_buffer_new_and_alloc (size);
       
   759       outbytes = GST_BUFFER_DATA (outbuf);
       
   760       gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
       
   761 
       
   762       if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
       
   763         /* clear if we are only going to fill a partial buffer */
       
   764         if (G_UNLIKELY (size > len))
       
   765           memset (outbytes, 0, size);
       
   766 
       
   767         GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p",
       
   768             data, len, bytes);
       
   769 
       
   770         /* and copy the data into it */
       
   771         memcpy (outbytes, bytes, len);
       
   772         empty = FALSE;
       
   773       } else {
       
   774         GST_LOG_OBJECT (adder, "channel %p: zeroing %d bytes from data %p",
       
   775             data, len, bytes);
       
   776         memset (outbytes, 0, size);
       
   777       }
       
   778     } else {
       
   779       if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
       
   780         GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
       
   781             data, len, bytes);
       
   782         /* other buffers, need to add them */
       
   783         adder->func ((gpointer) outbytes, (gpointer) bytes, len);
       
   784         empty = FALSE;
       
   785       } else {
       
   786         GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p",
       
   787             data, len, bytes);
       
   788       }
       
   789     }
       
   790   next:
       
   791     if (inbuf)
       
   792       gst_buffer_unref (inbuf);
       
   793   }
       
   794 
       
   795   /* can only happen when no pads to collect or all EOS */
       
   796   if (outbuf == NULL)
       
   797     goto eos;
       
   798 
       
   799   /* our timestamping is very simple, just an ever incrementing
       
   800    * counter, the new segment time will take care of their respective
       
   801    * stream time. */
       
   802   if (adder->segment_pending) {
       
   803     GstEvent *event;
       
   804 
       
   805     /* FIXME, use rate/applied_rate as set on all sinkpads.
       
   806      * - currently we just set rate as received from last seek-event
       
   807      * We could potentially figure out the duration as well using
       
   808      * the current segment positions and the stated stop positions.
       
   809      * Also we just start from stream time 0 which is rather
       
   810      * weird. For non-synchronized mixing, the time should be
       
   811      * the min of the stream times of all received segments,
       
   812      * rationale being that the duration is at least going to
       
   813      * be as long as the earliest stream we start mixing. This
       
   814      * would also be correct for synchronized mixing but then
       
   815      * the later streams would be delayed until the stream times
       
   816      * match.
       
   817      */
       
   818     event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
       
   819         1.0, GST_FORMAT_TIME, adder->timestamp, -1, adder->segment_position);
       
   820 
       
   821     gst_pad_push_event (adder->srcpad, event);
       
   822     adder->segment_pending = FALSE;
       
   823     adder->segment_position = 0;
       
   824   }
       
   825 
       
   826   /* set timestamps on the output buffer */
       
   827   GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
       
   828   GST_BUFFER_OFFSET (outbuf) = adder->offset;
       
   829 
       
   830   /* for the next timestamp, use the sample counter, which will
       
   831    * never accumulate rounding errors */
       
   832   adder->offset += size / adder->bps;
       
   833   adder->timestamp = gst_util_uint64_scale_int (adder->offset,
       
   834       GST_SECOND, adder->rate);
       
   835 
       
   836   /* now we can set the duration of the buffer */
       
   837   GST_BUFFER_DURATION (outbuf) = adder->timestamp -
       
   838       GST_BUFFER_TIMESTAMP (outbuf);
       
   839 
       
   840   /* if we only processed silence, mark output again as silence */
       
   841   if (empty)
       
   842     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
       
   843 
       
   844   /* send it out */
       
   845   GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
       
   846       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
       
   847   ret = gst_pad_push (adder->srcpad, outbuf);
       
   848 
       
   849   return ret;
       
   850 
       
   851   /* ERRORS */
       
   852 not_negotiated:
       
   853   {
       
   854     GST_ELEMENT_ERROR (adder, STREAM, FORMAT, (NULL),
       
   855         ("Unknown data received, not negotiated"));
       
   856     return GST_FLOW_NOT_NEGOTIATED;
       
   857   }
       
   858 eos:
       
   859   {
       
   860     GST_DEBUG_OBJECT (adder, "no data available, must be EOS");
       
   861     gst_pad_push_event (adder->srcpad, gst_event_new_eos ());
       
   862     return GST_FLOW_UNEXPECTED;
       
   863   }
       
   864 }
       
   865 
       
   866 static GstStateChangeReturn
       
   867 gst_adder_change_state (GstElement * element, GstStateChange transition)
       
   868 {
       
   869   GstAdder *adder;
       
   870   GstStateChangeReturn ret;
       
   871 
       
   872   adder = GST_ADDER (element);
       
   873 
       
   874   switch (transition) {
       
   875     case GST_STATE_CHANGE_NULL_TO_READY:
       
   876       break;
       
   877     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
   878       adder->timestamp = 0;
       
   879       adder->offset = 0;
       
   880       adder->segment_pending = TRUE;
       
   881       adder->segment_position = 0;
       
   882       adder->segment_rate = 1.0;
       
   883       gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
       
   884       gst_collect_pads_start (adder->collect);
       
   885       break;
       
   886     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       
   887       break;
       
   888     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
   889       /* need to unblock the collectpads before calling the
       
   890        * parent change_state so that streaming can finish */
       
   891       gst_collect_pads_stop (adder->collect);
       
   892       break;
       
   893     default:
       
   894       break;
       
   895   }
       
   896 
       
   897   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
   898 
       
   899   switch (transition) {
       
   900     default:
       
   901       break;
       
   902   }
       
   903 
       
   904   return ret;
       
   905 }
       
   906 
       
   907 
       
   908 static gboolean
       
   909 plugin_init (GstPlugin * plugin)
       
   910 {
       
   911   if (!gst_element_register (plugin, "adder", GST_RANK_NONE, GST_TYPE_ADDER)) {
       
   912     return FALSE;
       
   913   }
       
   914 
       
   915   return TRUE;
       
   916 }
       
   917 
       
   918 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
       
   919     GST_VERSION_MINOR,
       
   920     "adder",
       
   921     "Adds multiple streams",
       
   922     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
       
   923    
       
   924 #ifdef __SYMBIAN32__
       
   925 EXPORT_C 
       
   926 #endif
       
   927 GstPluginDesc* _GST_PLUGIN_DESC()
       
   928 {
       
   929 	return &gst_plugin_desc;
       
   930 }