gst_plugins_base/gst/adder/gstadder.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
    21  * Boston, MA 02111-1307, USA.
    21  * Boston, MA 02111-1307, USA.
    22  */
    22  */
    23 /**
    23 /**
    24  * SECTION:element-adder
    24  * SECTION:element-adder
    25  *
    25  *
    26  * The adder allows to mix several streams into one by adding the data.
    26  * <refsect2>
       
    27  * <para>
       
    28  * The Adder allows to mix several streams into one by adding the data.
    27  * Mixed data is clamped to the min/max values of the data format.
    29  * Mixed data is clamped to the min/max values of the data format.
    28  *
    30  * </para>
    29  * The adder currently mixes all data received on the sinkpads as soon as
       
    30  * possible without trying to synchronize the streams.
       
    31  *
       
    32  * <refsect2>
       
    33  * <title>Example launch line</title>
    31  * <title>Example launch line</title>
    34  * |[
    32  * <para>
       
    33  * <programlisting>
    35  * gst-launch audiotestsrc freq=100 ! adder name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
    34  * gst-launch audiotestsrc freq=100 ! adder name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
    36  * ]| This pipeline produces two sine waves mixed together.
    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>
    37  * </refsect2>
    42  * </refsect2>
    38  *
    43  *
    39  * Last reviewed on 2006-05-09 (0.10.7)
    44  * Last reviewed on 2006-05-09 (0.10.7)
    40  */
    45  */
    41 /* Element-Checklist-Version: 5 */
    46 /* Element-Checklist-Version: 5 */
    44 #include "config.h"
    49 #include "config.h"
    45 #endif
    50 #endif
    46 #include "gstadder.h"
    51 #include "gstadder.h"
    47 #include <gst/audio/audio.h>
    52 #include <gst/audio/audio.h>
    48 #include <string.h>             /* strcmp */
    53 #include <string.h>             /* strcmp */
    49 /*#include <liboil/liboil.h>*/
    54 
       
    55 #ifdef __SYMBIAN32__
       
    56 #include <glib_global.h>
       
    57 #endif
    50 
    58 
    51 /* highest positive/lowest negative x-bit value we can use for clamping */
    59 /* highest positive/lowest negative x-bit value we can use for clamping */
    52 #define MAX_INT_32  ((gint32) (0x7fffffff))
    60 #define MAX_INT_32  ((gint32) (0x7fffffff))
    53 #define MAX_INT_16  ((gint16) (0x7fff))
    61 #define MAX_INT_16  ((gint16) (0x7fff))
    54 #define MAX_INT_8   ((gint8)  (0x7f))
    62 #define MAX_INT_8   ((gint8)  (0x7f))
    61 #define MIN_INT_8   ((gint8)  (0x80))
    69 #define MIN_INT_8   ((gint8)  (0x80))
    62 #define MIN_UINT_32 ((guint32)(0x00000000))
    70 #define MIN_UINT_32 ((guint32)(0x00000000))
    63 #define MIN_UINT_16 ((guint16)(0x0000))
    71 #define MIN_UINT_16 ((guint16)(0x0000))
    64 #define MIN_UINT_8  ((guint8) (0x00))
    72 #define MIN_UINT_8  ((guint8) (0x00))
    65 
    73 
    66 enum
       
    67 {
       
    68   PROP_0,
       
    69   PROP_FILTER_CAPS
       
    70 };
       
    71 
       
    72 #define GST_CAT_DEFAULT gst_adder_debug
    74 #define GST_CAT_DEFAULT gst_adder_debug
    73 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
    75 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
    74 
    76 
    75 /* elementfactory information */
    77 /* elementfactory information */
    76 
    78 static const GstElementDetails adder_details = GST_ELEMENT_DETAILS ("Adder",
    77 #define CAPS \
    79     "Generic/Audio",
    78   "audio/x-raw-int, " \
    80     "Add N audio channels together",
    79   "rate = (int) [ 1, MAX ], " \
    81     "Thomas <thomas@apestaart.org>");
    80   "channels = (int) [ 1, MAX ], " \
       
    81   "endianness = (int) BYTE_ORDER, " \
       
    82   "width = (int) 32, " \
       
    83   "depth = (int) 32, " \
       
    84   "signed = (boolean) { true, false } ;" \
       
    85   "audio/x-raw-int, " \
       
    86   "rate = (int) [ 1, MAX ], " \
       
    87   "channels = (int) [ 1, MAX ], " \
       
    88   "endianness = (int) BYTE_ORDER, " \
       
    89   "width = (int) 16, " \
       
    90   "depth = (int) 16, " \
       
    91   "signed = (boolean) { true, false } ;" \
       
    92   "audio/x-raw-int, " \
       
    93   "rate = (int) [ 1, MAX ], " \
       
    94   "channels = (int) [ 1, MAX ], " \
       
    95   "endianness = (int) BYTE_ORDER, " \
       
    96   "width = (int) 8, " \
       
    97   "depth = (int) 8, " \
       
    98   "signed = (boolean) { true, false } ;" \
       
    99   "audio/x-raw-float, " \
       
   100   "rate = (int) [ 1, MAX ], " \
       
   101   "channels = (int) [ 1, MAX ], " \
       
   102   "endianness = (int) BYTE_ORDER, " \
       
   103   "width = (int) { 32, 64 }"
       
   104 
    82 
   105 static GstStaticPadTemplate gst_adder_src_template =
    83 static GstStaticPadTemplate gst_adder_src_template =
   106 GST_STATIC_PAD_TEMPLATE ("src",
    84     GST_STATIC_PAD_TEMPLATE ("src",
   107     GST_PAD_SRC,
    85     GST_PAD_SRC,
   108     GST_PAD_ALWAYS,
    86     GST_PAD_ALWAYS,
   109     GST_STATIC_CAPS (CAPS)
    87     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
       
    88         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
   110     );
    89     );
   111 
    90 
   112 static GstStaticPadTemplate gst_adder_sink_template =
    91 static GstStaticPadTemplate gst_adder_sink_template =
   113 GST_STATIC_PAD_TEMPLATE ("sink%d",
    92     GST_STATIC_PAD_TEMPLATE ("sink%d",
   114     GST_PAD_SINK,
    93     GST_PAD_SINK,
   115     GST_PAD_REQUEST,
    94     GST_PAD_REQUEST,
   116     GST_STATIC_CAPS (CAPS)
    95     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
       
    96         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
   117     );
    97     );
   118 
    98 
   119 static void gst_adder_class_init (GstAdderClass * klass);
    99 static void gst_adder_class_init (GstAdderClass * klass);
   120 static void gst_adder_init (GstAdder * adder);
   100 static void gst_adder_init (GstAdder * adder);
   121 static void gst_adder_dispose (GObject * object);
   101 static void gst_adder_finalize (GObject * object);
   122 static void gst_adder_set_property (GObject * object, guint prop_id,
       
   123     const GValue * value, GParamSpec * pspec);
       
   124 static void gst_adder_get_property (GObject * object, guint prop_id,
       
   125     GValue * value, GParamSpec * pspec);
       
   126 
   102 
   127 static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
   103 static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
   128 static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
   104 static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
   129 static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
   105 static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
   130 static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
   106 static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
   164         "audio channel mixing element");
   140         "audio channel mixing element");
   165   }
   141   }
   166   return adder_type;
   142   return adder_type;
   167 }
   143 }
   168 
   144 
   169 /* clipping versions (for int)
   145 /* clipping versions */
   170  * FIXME: what about: oil_add_s16 (out, out, in, bytes / sizeof (type))
       
   171  */
       
   172 #define MAKE_FUNC(name,type,ttype,min,max)                      \
   146 #define MAKE_FUNC(name,type,ttype,min,max)                      \
   173 static void name (type *out, type *in, gint bytes) {            \
   147 static void name (type *out, type *in, gint bytes) {            \
   174   gint i;                                                       \
   148   gint i;                                                       \
   175   ttype add;                                                    \
   149   for (i = 0; i < bytes / sizeof (type); i++)                   \
   176   for (i = 0; i < bytes / sizeof (type); i++) {                 \
   150     out[i] = CLAMP ((ttype)out[i] + (ttype)in[i], min, max);    \
   177     add = (ttype)out[i] + (ttype)in[i];                         \
       
   178     out[i] = CLAMP (add, min, max);                             \
       
   179   }                                                             \
       
   180 }
       
   181 
       
   182 /* unsigned versions (for int) */
       
   183 #define MAKE_FUNC_US(name,type,ttype,max)                       \
       
   184 static void name (type *out, type *in, gint bytes) {            \
       
   185   gint i;                                                       \
       
   186   ttype add;                                                    \
       
   187   for (i = 0; i < bytes / sizeof (type); i++) {                 \
       
   188     add = (ttype)out[i] + (ttype)in[i];                         \
       
   189     out[i] = ((add <= max) ? add : max);                        \
       
   190   }                                                             \
       
   191 }
   151 }
   192 
   152 
   193 /* non-clipping versions (for float) */
   153 /* non-clipping versions (for float) */
   194 #define MAKE_FUNC_NC(name,type)                                 \
   154 #define MAKE_FUNC_NC(name,type,ttype)                           \
   195 static void name (type *out, type *in, gint bytes) {            \
   155 static void name (type *out, type *in, gint bytes) {            \
   196   gint i;                                                       \
   156   gint i;                                                       \
   197   for (i = 0; i < bytes / sizeof (type); i++)                   \
   157   for (i = 0; i < bytes / sizeof (type); i++)                   \
   198     out[i] += in[i];                                            \
   158     out[i] = (ttype)out[i] + (ttype)in[i];                      \
   199 }
   159 }
   200 
       
   201 #if 0
       
   202 /* right now, the liboil function don't seems to be faster on x86
       
   203  * time gst-launch audiotestsrc num-buffers=50000 ! audio/x-raw-float ! adder name=m ! fakesink audiotestsrc num-buffers=50000 ! audio/x-raw-float ! m.
       
   204  * time gst-launch audiotestsrc num-buffers=50000 ! audio/x-raw-float,width=32 ! adder name=m ! fakesink audiotestsrc num-buffers=50000 ! audio/x-raw-float,width=32 ! m.
       
   205  */
       
   206 static void
       
   207 add_float32 (gfloat * out, gfloat * in, gint bytes)
       
   208 {
       
   209   oil_add_f32 (out, out, in, bytes / sizeof (gfloat));
       
   210 }
       
   211 
       
   212 static void
       
   213 add_float64 (gdouble * out, gdouble * in, gint bytes)
       
   214 {
       
   215   oil_add_f64 (out, out, in, bytes / sizeof (gdouble));
       
   216 }
       
   217 #endif
       
   218 
   160 
   219 /* *INDENT-OFF* */
   161 /* *INDENT-OFF* */
   220 MAKE_FUNC (add_int32, gint32, gint64, MIN_INT_32, MAX_INT_32)
   162 MAKE_FUNC (add_int32, gint32, gint64, MIN_INT_32, MAX_INT_32)
   221 MAKE_FUNC (add_int16, gint16, gint32, MIN_INT_16, MAX_INT_16)
   163 MAKE_FUNC (add_int16, gint16, gint32, MIN_INT_16, MAX_INT_16)
   222 MAKE_FUNC (add_int8, gint8, gint16, MIN_INT_8, MAX_INT_8)
   164 MAKE_FUNC (add_int8, gint8, gint16, MIN_INT_8, MAX_INT_8)
   223 MAKE_FUNC_US (add_uint32, guint32, guint64, MAX_UINT_32)
   165 MAKE_FUNC (add_uint32, guint32, guint64, MIN_UINT_32, MAX_UINT_32)
   224 MAKE_FUNC_US (add_uint16, guint16, guint32, MAX_UINT_16)
   166 MAKE_FUNC (add_uint16, guint16, guint32, MIN_UINT_16, MAX_UINT_16)
   225 MAKE_FUNC_US (add_uint8, guint8, guint16, MAX_UINT_8)
   167 MAKE_FUNC (add_uint8, guint8, guint16, MIN_UINT_8, MAX_UINT_8)
   226 MAKE_FUNC_NC (add_float64, gdouble)
   168 MAKE_FUNC_NC (add_float64, gdouble, gdouble)
   227 MAKE_FUNC_NC (add_float32, gfloat)
   169 MAKE_FUNC_NC (add_float32, gfloat, gfloat)
   228 /* *INDENT-ON* */
   170 /* *INDENT-ON* */
   229 
   171 
   230 /* we can only accept caps that we and downstream can handle.
   172 /* we can only accept caps that we and downstream can handle. */
   231  * if we have filtercaps set, use those to constrain the target caps.
       
   232  */
       
   233 static GstCaps *
   173 static GstCaps *
   234 gst_adder_sink_getcaps (GstPad * pad)
   174 gst_adder_sink_getcaps (GstPad * pad)
   235 {
   175 {
   236   GstAdder *adder;
   176   GstAdder *adder;
   237   GstCaps *result, *peercaps, *sinkcaps;
   177   GstCaps *result, *peercaps, *sinkcaps;
   239   adder = GST_ADDER (GST_PAD_PARENT (pad));
   179   adder = GST_ADDER (GST_PAD_PARENT (pad));
   240 
   180 
   241   GST_OBJECT_LOCK (adder);
   181   GST_OBJECT_LOCK (adder);
   242   /* get the downstream possible caps */
   182   /* get the downstream possible caps */
   243   peercaps = gst_pad_peer_get_caps (adder->srcpad);
   183   peercaps = gst_pad_peer_get_caps (adder->srcpad);
   244 
       
   245   /* get the allowed caps on this sinkpad, we use the fixed caps function so
   184   /* get the allowed caps on this sinkpad, we use the fixed caps function so
   246    * that it does not call recursively in this function. */
   185    * that it does not call recursively in this function. */
   247   sinkcaps = gst_pad_get_fixed_caps_func (pad);
   186   sinkcaps = gst_pad_get_fixed_caps_func (pad);
   248   if (peercaps) {
   187   if (peercaps) {
   249     /* restrict with filter-caps if any */
       
   250     if (adder->filter_caps) {
       
   251       result = gst_caps_intersect (peercaps, adder->filter_caps);
       
   252       gst_caps_unref (peercaps);
       
   253       peercaps = result;
       
   254     }
       
   255     /* if the peer has caps, intersect */
   188     /* if the peer has caps, intersect */
   256     GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
   189     GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
   257     result = gst_caps_intersect (peercaps, sinkcaps);
   190     result = gst_caps_intersect (peercaps, sinkcaps);
   258     gst_caps_unref (peercaps);
   191     gst_caps_unref (peercaps);
   259     gst_caps_unref (sinkcaps);
   192     gst_caps_unref (sinkcaps);
   263     GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
   196     GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
   264     result = sinkcaps;
   197     result = sinkcaps;
   265   }
   198   }
   266   GST_OBJECT_UNLOCK (adder);
   199   GST_OBJECT_UNLOCK (adder);
   267 
   200 
   268   GST_LOG_OBJECT (adder, "getting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
       
   269       GST_PAD_NAME (pad), result);
       
   270 
       
   271   return result;
   201   return result;
   272 }
   202 }
   273 
   203 
   274 /* the first caps we receive on any of the sinkpads will define the caps for all
   204 /* the first caps we receive on any of the sinkpads will define the caps for all
   275  * the other sinkpads because we can only mix streams with the same caps.
   205  * the other sinkpads because we can only mix streams with the same caps.
   276  */
   206  * */
   277 static gboolean
   207 static gboolean
   278 gst_adder_setcaps (GstPad * pad, GstCaps * caps)
   208 gst_adder_setcaps (GstPad * pad, GstCaps * caps)
   279 {
   209 {
   280   GstAdder *adder;
   210   GstAdder *adder;
   281   GList *pads;
   211   GList *pads;
   303 
   233 
   304   /* parse caps now */
   234   /* parse caps now */
   305   structure = gst_caps_get_structure (caps, 0);
   235   structure = gst_caps_get_structure (caps, 0);
   306   media_type = gst_structure_get_name (structure);
   236   media_type = gst_structure_get_name (structure);
   307   if (strcmp (media_type, "audio/x-raw-int") == 0) {
   237   if (strcmp (media_type, "audio/x-raw-int") == 0) {
       
   238     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format int");
   308     adder->format = GST_ADDER_FORMAT_INT;
   239     adder->format = GST_ADDER_FORMAT_INT;
   309     gst_structure_get_int (structure, "width", &adder->width);
   240     gst_structure_get_int (structure, "width", &adder->width);
   310     gst_structure_get_int (structure, "depth", &adder->depth);
   241     gst_structure_get_int (structure, "depth", &adder->depth);
   311     gst_structure_get_int (structure, "endianness", &adder->endianness);
   242     gst_structure_get_int (structure, "endianness", &adder->endianness);
   312     gst_structure_get_boolean (structure, "signed", &adder->is_signed);
   243     gst_structure_get_boolean (structure, "signed", &adder->is_signed);
   313 
       
   314     GST_INFO_OBJECT (pad, "parse_caps sets adder to format int, %d bit",
       
   315         adder->width);
       
   316 
   244 
   317     if (adder->endianness != G_BYTE_ORDER)
   245     if (adder->endianness != G_BYTE_ORDER)
   318       goto not_supported;
   246       goto not_supported;
   319 
   247 
   320     switch (adder->width) {
   248     switch (adder->width) {
   332         break;
   260         break;
   333       default:
   261       default:
   334         goto not_supported;
   262         goto not_supported;
   335     }
   263     }
   336   } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
   264   } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
       
   265     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format float");
   337     adder->format = GST_ADDER_FORMAT_FLOAT;
   266     adder->format = GST_ADDER_FORMAT_FLOAT;
   338     gst_structure_get_int (structure, "width", &adder->width);
   267     gst_structure_get_int (structure, "width", &adder->width);
   339     gst_structure_get_int (structure, "endianness", &adder->endianness);
       
   340 
       
   341     GST_INFO_OBJECT (pad, "parse_caps sets adder to format float, %d bit",
       
   342         adder->width);
       
   343 
       
   344     if (adder->endianness != G_BYTE_ORDER)
       
   345       goto not_supported;
       
   346 
   268 
   347     switch (adder->width) {
   269     switch (adder->width) {
   348       case 32:
   270       case 32:
   349         adder->func = (GstAdderFunction) add_float32;
   271         adder->func = (GstAdderFunction) add_float32;
   350         break;
   272         break;
   406   done = FALSE;
   328   done = FALSE;
   407 
   329 
   408   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
   330   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
   409   while (!done) {
   331   while (!done) {
   410     GstIteratorResult ires;
   332     GstIteratorResult ires;
   411 
       
   412     gpointer item;
   333     gpointer item;
   413 
   334 
   414     ires = gst_iterator_next (it, &item);
   335     ires = gst_iterator_next (it, &item);
   415     switch (ires) {
   336     switch (ires) {
   416       case GST_ITERATOR_DONE:
   337       case GST_ITERATOR_DONE:
   417         done = TRUE;
   338         done = TRUE;
   418         break;
   339         break;
   419       case GST_ITERATOR_OK:
   340       case GST_ITERATOR_OK:
   420       {
   341       {
   421         GstPad *pad = GST_PAD_CAST (item);
   342         GstPad *pad = GST_PAD_CAST (item);
   422 
       
   423         gint64 duration;
   343         gint64 duration;
   424 
   344 
   425         /* ask sink peer for duration */
   345         /* ask sink peer for duration */
   426         res &= gst_pad_query_peer_duration (pad, &format, &duration);
   346         res &= gst_pad_query_peer_duration (pad, &format, &duration);
   427         /* take max from all valid return values */
   347         /* take max from all valid return values */
   433           }
   353           }
   434           /* else see if bigger than current max */
   354           /* else see if bigger than current max */
   435           else if (duration > max)
   355           else if (duration > max)
   436             max = duration;
   356             max = duration;
   437         }
   357         }
   438         gst_object_unref (pad);
       
   439         break;
   358         break;
   440       }
   359       }
   441       case GST_ITERATOR_RESYNC:
   360       case GST_ITERATOR_RESYNC:
   442         max = -1;
   361         max = -1;
   443         res = TRUE;
   362         res = TRUE;
   444         gst_iterator_resync (it);
       
   445         break;
   363         break;
   446       default:
   364       default:
   447         res = FALSE;
   365         res = FALSE;
   448         done = TRUE;
   366         done = TRUE;
   449         break;
   367         break;
   451   }
   369   }
   452   gst_iterator_free (it);
   370   gst_iterator_free (it);
   453 
   371 
   454   if (res) {
   372   if (res) {
   455     /* and store the max */
   373     /* and store the max */
   456     GST_DEBUG_OBJECT (adder, "Total duration in format %s: %"
       
   457         GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
       
   458     gst_query_set_duration (query, format, max);
   374     gst_query_set_duration (query, format, max);
   459   }
       
   460 
       
   461   return res;
       
   462 }
       
   463 
       
   464 static gboolean
       
   465 gst_adder_query_latency (GstAdder * adder, GstQuery * query)
       
   466 {
       
   467   GstClockTime min, max;
       
   468   gboolean live;
       
   469   gboolean res;
       
   470   GstIterator *it;
       
   471   gboolean done;
       
   472 
       
   473   res = TRUE;
       
   474   done = FALSE;
       
   475 
       
   476   live = FALSE;
       
   477   min = 0;
       
   478   max = GST_CLOCK_TIME_NONE;
       
   479 
       
   480   /* Take maximum of all latency values */
       
   481   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
       
   482   while (!done) {
       
   483     GstIteratorResult ires;
       
   484 
       
   485     gpointer item;
       
   486 
       
   487     ires = gst_iterator_next (it, &item);
       
   488     switch (ires) {
       
   489       case GST_ITERATOR_DONE:
       
   490         done = TRUE;
       
   491         break;
       
   492       case GST_ITERATOR_OK:
       
   493       {
       
   494         GstPad *pad = GST_PAD_CAST (item);
       
   495         GstQuery *peerquery;
       
   496         GstClockTime min_cur, max_cur;
       
   497         gboolean live_cur;
       
   498 
       
   499         peerquery = gst_query_new_latency ();
       
   500 
       
   501         /* Ask peer for latency */
       
   502         res &= gst_pad_peer_query (pad, peerquery);
       
   503 
       
   504         /* take max from all valid return values */
       
   505         if (res) {
       
   506           gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
       
   507 
       
   508           if (min_cur > min)
       
   509             min = min_cur;
       
   510 
       
   511           if (max_cur != GST_CLOCK_TIME_NONE &&
       
   512               ((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
       
   513                   (max == GST_CLOCK_TIME_NONE)))
       
   514             max = max_cur;
       
   515 
       
   516           live = live || live_cur;
       
   517         }
       
   518 
       
   519         gst_query_unref (peerquery);
       
   520         gst_object_unref (pad);
       
   521         break;
       
   522       }
       
   523       case GST_ITERATOR_RESYNC:
       
   524         live = FALSE;
       
   525         min = 0;
       
   526         max = GST_CLOCK_TIME_NONE;
       
   527         res = TRUE;
       
   528         gst_iterator_resync (it);
       
   529         break;
       
   530       default:
       
   531         res = FALSE;
       
   532         done = TRUE;
       
   533         break;
       
   534     }
       
   535   }
       
   536   gst_iterator_free (it);
       
   537 
       
   538   if (res) {
       
   539     /* store the results */
       
   540     GST_DEBUG_OBJECT (adder, "Calculated total latency: live %s, min %"
       
   541         GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
       
   542         (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
       
   543     gst_query_set_latency (query, live, min, max);
       
   544   }
   375   }
   545 
   376 
   546   return res;
   377   return res;
   547 }
   378 }
   548 
   379 
   575       break;
   406       break;
   576     }
   407     }
   577     case GST_QUERY_DURATION:
   408     case GST_QUERY_DURATION:
   578       res = gst_adder_query_duration (adder, query);
   409       res = gst_adder_query_duration (adder, query);
   579       break;
   410       break;
   580     case GST_QUERY_LATENCY:
       
   581       res = gst_adder_query_latency (adder, query);
       
   582       break;
       
   583     default:
   411     default:
   584       /* FIXME, needs a custom query handler because we have multiple
   412       /* FIXME, needs a custom query handler because we have multiple
   585        * sinkpads */
   413        * sinkpads */
   586       res = gst_pad_query_default (pad, query);
   414       res = gst_pad_query_default (pad, query);
   587       break;
   415       break;
   589 
   417 
   590   gst_object_unref (adder);
   418   gst_object_unref (adder);
   591   return res;
   419   return res;
   592 }
   420 }
   593 
   421 
   594 typedef struct
       
   595 {
       
   596   GstEvent *event;
       
   597   gboolean flush;
       
   598 } EventData;
       
   599 
       
   600 static gboolean
   422 static gboolean
   601 forward_event_func (GstPad * pad, GValue * ret, EventData * data)
   423 forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
   602 {
   424 {
   603   GstEvent *event = data->event;
       
   604 
       
   605   gst_event_ref (event);
   425   gst_event_ref (event);
   606   GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
   426   GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
   607   if (!gst_pad_push_event (pad, event)) {
   427   if (!gst_pad_push_event (pad, event)) {
   608     g_value_set_boolean (ret, FALSE);
   428     g_value_set_boolean (ret, FALSE);
   609     GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
   429     GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
   610         event, GST_EVENT_TYPE_NAME (event));
   430         event, GST_EVENT_TYPE_NAME (event));
   611     /* quick hack to unflush the pads, ideally we need a way to just unflush
       
   612      * this single collect pad */
       
   613     if (data->flush)
       
   614       gst_pad_send_event (pad, gst_event_new_flush_stop ());
       
   615   } else {
   431   } else {
   616     GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
   432     GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
   617         event, GST_EVENT_TYPE_NAME (event));
   433         event, GST_EVENT_TYPE_NAME (event));
   618   }
   434   }
   619   gst_object_unref (pad);
   435   gst_object_unref (pad);
   620 
       
   621   /* continue on other pads, even if one failed */
       
   622   return TRUE;
   436   return TRUE;
   623 }
   437 }
   624 
   438 
   625 /* forwards the event to all sinkpads, takes ownership of the
   439 /* forwards the event to all sinkpads, takes ownership of the
   626  * event
   440  * event
   627  *
   441  *
   628  * Returns: TRUE if the event could be forwarded on all
   442  * Returns: TRUE if the event could be forwarded on all
   629  * sinkpads.
   443  * sinkpads.
   630  */
   444  */
   631 static gboolean
   445 static gboolean
   632 forward_event (GstAdder * adder, GstEvent * event, gboolean flush)
   446 forward_event (GstAdder * adder, GstEvent * event)
   633 {
   447 {
   634   gboolean ret;
   448   gboolean ret;
   635   GstIterator *it;
   449   GstIterator *it;
   636   GstIteratorResult ires;
       
   637   GValue vret = { 0 };
   450   GValue vret = { 0 };
   638   EventData data;
       
   639 
   451 
   640   GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
   452   GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
   641       GST_EVENT_TYPE_NAME (event));
   453       GST_EVENT_TYPE_NAME (event));
   642 
   454 
   643   ret = TRUE;
   455   ret = TRUE;
   644   data.event = event;
       
   645   data.flush = flush;
       
   646 
   456 
   647   g_value_init (&vret, G_TYPE_BOOLEAN);
   457   g_value_init (&vret, G_TYPE_BOOLEAN);
   648   g_value_set_boolean (&vret, TRUE);
   458   g_value_set_boolean (&vret, TRUE);
   649   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
   459   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
   650   while (TRUE) {
   460   gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
   651     ires = gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
   461       event);
   652         &vret, &data);
       
   653     switch (ires) {
       
   654       case GST_ITERATOR_RESYNC:
       
   655         GST_WARNING ("resync");
       
   656         gst_iterator_resync (it);
       
   657         g_value_set_boolean (&vret, TRUE);
       
   658         break;
       
   659       case GST_ITERATOR_OK:
       
   660       case GST_ITERATOR_DONE:
       
   661         ret = g_value_get_boolean (&vret);
       
   662         goto done;
       
   663       default:
       
   664         ret = FALSE;
       
   665         goto done;
       
   666     }
       
   667   }
       
   668 done:
       
   669   gst_iterator_free (it);
   462   gst_iterator_free (it);
   670   GST_LOG_OBJECT (adder, "Forwarded event %p (%s), ret=%d", event,
       
   671       GST_EVENT_TYPE_NAME (event), ret);
       
   672   gst_event_unref (event);
   463   gst_event_unref (event);
       
   464 
       
   465   ret = g_value_get_boolean (&vret);
   673 
   466 
   674   return ret;
   467   return ret;
   675 }
   468 }
   676 
   469 
   677 static gboolean
   470 static gboolean
   681   gboolean result;
   474   gboolean result;
   682 
   475 
   683   adder = GST_ADDER (gst_pad_get_parent (pad));
   476   adder = GST_ADDER (gst_pad_get_parent (pad));
   684 
   477 
   685   switch (GST_EVENT_TYPE (event)) {
   478   switch (GST_EVENT_TYPE (event)) {
       
   479     case GST_EVENT_QOS:
       
   480       /* QoS might be tricky */
       
   481       result = FALSE;
       
   482       break;
   686     case GST_EVENT_SEEK:
   483     case GST_EVENT_SEEK:
   687     {
   484     {
   688       GstSeekFlags flags;
   485       GstSeekFlags flags;
   689       GstSeekType curtype;
   486       GstSeekType curtype;
   690       gint64 cur;
   487       gint64 cur;
   691       gboolean flush;
       
   692 
   488 
   693       /* parse the seek parameters */
   489       /* parse the seek parameters */
   694       gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
   490       gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
   695           &cur, NULL, NULL);
   491           &cur, NULL, NULL);
   696 
   492 
   697       flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;
       
   698 
       
   699       /* check if we are flushing */
   493       /* check if we are flushing */
   700       if (flush) {
   494       if (flags & GST_SEEK_FLAG_FLUSH) {
   701         /* make sure we accept nothing anymore and return WRONG_STATE */
   495         /* make sure we accept nothing anymore and return WRONG_STATE */
   702         gst_collect_pads_set_flushing (adder->collect, TRUE);
   496         gst_collect_pads_set_flushing (adder->collect, TRUE);
   703 
   497 
   704         /* flushing seek, start flush downstream, the flush will be done
   498         /* flushing seek, start flush downstream, the flush will be done
   705          * when all pads received a FLUSH_STOP. */
   499          * when all pads received a FLUSH_STOP. */
   706         gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
   500         gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
   707       }
   501       }
   708       GST_DEBUG_OBJECT (adder, "handling seek event: %" GST_PTR_FORMAT, event);
       
   709 
   502 
   710       /* now wait for the collected to be finished and mark a new
   503       /* now wait for the collected to be finished and mark a new
   711        * segment. After we have the lock, no collect function is running and no
   504        * segment */
   712        * new collect function will be called for as long as we're flushing. */
       
   713       GST_OBJECT_LOCK (adder->collect);
   505       GST_OBJECT_LOCK (adder->collect);
   714       if (curtype == GST_SEEK_TYPE_SET)
   506       if (curtype == GST_SEEK_TYPE_SET)
   715         adder->segment_position = cur;
   507         adder->segment_position = cur;
   716       else
   508       else
   717         adder->segment_position = 0;
   509         adder->segment_position = 0;
   718       /* make sure we push a new segment, to inform about new basetime
       
   719        * see FIXME in gst_adder_collected() */
       
   720       adder->segment_pending = TRUE;
   510       adder->segment_pending = TRUE;
   721       if (flush) {
       
   722         /* Yes, we need to call _set_flushing again *WHEN* the streaming threads
       
   723          * have stopped so that the cookie gets properly updated. */
       
   724         gst_collect_pads_set_flushing (adder->collect, TRUE);
       
   725       }
       
   726       /* we might have a pending flush_stop event now. This event will either be
       
   727        * sent by an upstream element when it completes the seek or we will push
       
   728        * one in the collected callback ourself */
       
   729       adder->flush_stop_pending = flush;
       
   730       GST_OBJECT_UNLOCK (adder->collect);
   511       GST_OBJECT_UNLOCK (adder->collect);
   731       GST_DEBUG_OBJECT (adder, "forwarding seek event: %" GST_PTR_FORMAT,
   512 
   732           event);
   513       result = forward_event (adder, event);
   733 
       
   734       result = forward_event (adder, event, flush);
       
   735       if (!result) {
       
   736         /* seek failed. maybe source is a live source. */
       
   737         GST_DEBUG_OBJECT (adder, "seeking failed");
       
   738       }
       
   739       /* FIXME: ideally we would like to send a flush-stop event from here but
       
   740        * collectpads does not have a method that allows us to do that. Instead
       
   741        * we forward all flush-stop events we receive on the sinkpads. We might
       
   742        * be sending too many flush-stop events. */
       
   743       break;
   514       break;
   744     }
   515     }
   745     case GST_EVENT_QOS:
       
   746       /* QoS might be tricky */
       
   747       result = FALSE;
       
   748       break;
       
   749     case GST_EVENT_NAVIGATION:
   516     case GST_EVENT_NAVIGATION:
   750       /* navigation is rather pointless. */
   517       /* navigation is rather pointless. */
   751       result = FALSE;
   518       result = FALSE;
   752       break;
   519       break;
   753     default:
   520     default:
   754       /* just forward the rest for now */
   521       /* just forward the rest for now */
   755       GST_DEBUG_OBJECT (adder, "forward unhandled event: %s",
   522       result = forward_event (adder, event);
   756           GST_EVENT_TYPE_NAME (event));
       
   757       result = forward_event (adder, event, FALSE);
       
   758       break;
   523       break;
   759   }
   524   }
   760   gst_object_unref (adder);
   525   gst_object_unref (adder);
   761 
   526 
   762   return result;
   527   return result;
   764 
   529 
   765 static gboolean
   530 static gboolean
   766 gst_adder_sink_event (GstPad * pad, GstEvent * event)
   531 gst_adder_sink_event (GstPad * pad, GstEvent * event)
   767 {
   532 {
   768   GstAdder *adder;
   533   GstAdder *adder;
   769   gboolean ret = TRUE;
   534   gboolean ret;
   770 
   535 
   771   adder = GST_ADDER (gst_pad_get_parent (pad));
   536   adder = GST_ADDER (gst_pad_get_parent (pad));
   772 
   537 
   773   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
   538   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
   774       GST_DEBUG_PAD_NAME (pad));
   539       GST_DEBUG_PAD_NAME (pad));
   775 
   540 
   776   switch (GST_EVENT_TYPE (event)) {
   541   switch (GST_EVENT_TYPE (event)) {
   777     case GST_EVENT_FLUSH_STOP:
   542     case GST_EVENT_FLUSH_STOP:
   778       /* we received a flush-stop. The collect_event function will push the
   543       /* mark a pending new segment. This event is synchronized
   779        * event past our element. We simply forward all flush-stop events, even
   544        * with the streaming thread so we can safely update the
   780        * when no flush-stop was pendingk, this is required because collectpads
   545        * variable without races. It's somewhat weird because we
   781        * does not provide an API to handle-but-not-forward the flush-stop.
   546        * assume the collectpads forwarded the FLUSH_STOP past us
   782        * We unset the pending flush-stop flag so that we don't send anymore
   547        * and downstream (using our source pad, the bastard!).
   783        * flush-stop from the collect function later.
       
   784        */
   548        */
   785       GST_OBJECT_LOCK (adder->collect);
       
   786       adder->segment_pending = TRUE;
   549       adder->segment_pending = TRUE;
   787       adder->flush_stop_pending = FALSE;
   550       break;
   788       /* Clear pending tags */
       
   789       if (adder->pending_events) {
       
   790         g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL);
       
   791         g_list_free (adder->pending_events);
       
   792         adder->pending_events = NULL;
       
   793       }
       
   794       GST_OBJECT_UNLOCK (adder->collect);
       
   795       break;
       
   796     case GST_EVENT_TAG:
       
   797       GST_OBJECT_LOCK (adder->collect);
       
   798       /* collectpads is a pile of horse manure. */
       
   799       adder->pending_events = g_list_append (adder->pending_events, event);
       
   800       GST_OBJECT_UNLOCK (adder->collect);
       
   801       goto beach;
       
   802     default:
   551     default:
   803       break;
   552       break;
   804   }
   553   }
   805 
   554 
   806   /* now GstCollectPads can take care of the rest, e.g. EOS */
   555   /* now GstCollectPads can take care of the rest, e.g. EOS */
   807   ret = adder->collect_event (pad, event);
   556   ret = adder->collect_event (pad, event);
   808 
   557 
   809 beach:
       
   810   gst_object_unref (adder);
   558   gst_object_unref (adder);
   811   return ret;
   559   return ret;
   812 }
   560 }
   813 
   561 
   814 static void
   562 static void
   815 gst_adder_class_init (GstAdderClass * klass)
   563 gst_adder_class_init (GstAdderClass * klass)
   816 {
   564 {
   817   GObjectClass *gobject_class = (GObjectClass *) klass;
   565   GObjectClass *gobject_class;
   818   GstElementClass *gstelement_class = (GstElementClass *) klass;
   566   GstElementClass *gstelement_class;
   819 
   567 
   820   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_adder_set_property);
   568   gobject_class = (GObjectClass *) klass;
   821   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_adder_get_property);
   569 
   822   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_adder_dispose);
   570   gobject_class->finalize = gst_adder_finalize;
       
   571 
       
   572   gstelement_class = (GstElementClass *) klass;
   823 
   573 
   824   gst_element_class_add_pad_template (gstelement_class,
   574   gst_element_class_add_pad_template (gstelement_class,
   825       gst_static_pad_template_get (&gst_adder_src_template));
   575       gst_static_pad_template_get (&gst_adder_src_template));
   826   gst_element_class_add_pad_template (gstelement_class,
   576   gst_element_class_add_pad_template (gstelement_class,
   827       gst_static_pad_template_get (&gst_adder_sink_template));
   577       gst_static_pad_template_get (&gst_adder_sink_template));
   828   gst_element_class_set_details_simple (gstelement_class, "Adder",
   578   gst_element_class_set_details (gstelement_class, &adder_details);
   829       "Generic/Audio",
       
   830       "Add N audio channels together",
       
   831       "Thomas Vander Stichele <thomas at apestaart dot org>");
       
   832 
   579 
   833   parent_class = g_type_class_peek_parent (klass);
   580   parent_class = g_type_class_peek_parent (klass);
   834 
   581 
   835   /**
   582   gstelement_class->request_new_pad = gst_adder_request_new_pad;
   836    * GstAdder:caps:
   583   gstelement_class->release_pad = gst_adder_release_pad;
   837    *
   584   gstelement_class->change_state = gst_adder_change_state;
   838    * Since: 0.10.24
       
   839    */
       
   840   g_object_class_install_property (gobject_class, PROP_FILTER_CAPS,
       
   841       g_param_spec_boxed ("caps", "Target caps",
       
   842           "Set target format for mixing (NULL means ANY). "
       
   843           "Setting this property takes a reference to the supplied GstCaps "
       
   844           "object.", GST_TYPE_CAPS,
       
   845           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
       
   846 
       
   847   gstelement_class->request_new_pad =
       
   848       GST_DEBUG_FUNCPTR (gst_adder_request_new_pad);
       
   849   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_adder_release_pad);
       
   850   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_adder_change_state);
       
   851 }
   585 }
   852 
   586 
   853 static void
   587 static void
   854 gst_adder_init (GstAdder * adder)
   588 gst_adder_init (GstAdder * adder)
   855 {
   589 {
   856   GstPadTemplate *template;
   590   GstPadTemplate *template;
   857 
   591 
   858   template = gst_static_pad_template_get (&gst_adder_src_template);
   592   template = gst_static_pad_template_get (&gst_adder_src_template);
   859   adder->srcpad = gst_pad_new_from_template (template, "src");
   593   adder->srcpad = gst_pad_new_from_template (template, "src");
   860   gst_object_unref (template);
   594   gst_object_unref (template);
   861 
       
   862   gst_pad_set_getcaps_function (adder->srcpad,
   595   gst_pad_set_getcaps_function (adder->srcpad,
   863       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
   596       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
   864   gst_pad_set_setcaps_function (adder->srcpad,
   597   gst_pad_set_setcaps_function (adder->srcpad,
   865       GST_DEBUG_FUNCPTR (gst_adder_setcaps));
   598       GST_DEBUG_FUNCPTR (gst_adder_setcaps));
   866   gst_pad_set_query_function (adder->srcpad,
   599   gst_pad_set_query_function (adder->srcpad,
   871 
   604 
   872   adder->format = GST_ADDER_FORMAT_UNSET;
   605   adder->format = GST_ADDER_FORMAT_UNSET;
   873   adder->padcount = 0;
   606   adder->padcount = 0;
   874   adder->func = NULL;
   607   adder->func = NULL;
   875 
   608 
   876   adder->filter_caps = gst_caps_new_any ();
       
   877 
       
   878   /* keep track of the sinkpads requested */
   609   /* keep track of the sinkpads requested */
   879   adder->collect = gst_collect_pads_new ();
   610   adder->collect = gst_collect_pads_new ();
   880   gst_collect_pads_set_function (adder->collect,
   611   gst_collect_pads_set_function (adder->collect,
   881       GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
   612       GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
   882 }
   613 }
   883 
   614 
   884 static void
   615 static void
   885 gst_adder_dispose (GObject * object)
   616 gst_adder_finalize (GObject * object)
   886 {
   617 {
   887   GstAdder *adder = GST_ADDER (object);
   618   GstAdder *adder = GST_ADDER (object);
   888 
   619 
   889   if (adder->collect) {
   620   gst_object_unref (adder->collect);
   890     gst_object_unref (adder->collect);
   621   adder->collect = NULL;
   891     adder->collect = NULL;
   622 
   892   }
   623   G_OBJECT_CLASS (parent_class)->finalize (object);
   893   gst_caps_replace (&adder->filter_caps, NULL);
   624 }
   894   if (adder->pending_events) {
       
   895     g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL);
       
   896     g_list_free (adder->pending_events);
       
   897     adder->pending_events = NULL;
       
   898   }
       
   899 
       
   900   G_OBJECT_CLASS (parent_class)->dispose (object);
       
   901 }
       
   902 
       
   903 static void
       
   904 gst_adder_set_property (GObject * object, guint prop_id,
       
   905     const GValue * value, GParamSpec * pspec)
       
   906 {
       
   907   GstAdder *adder = GST_ADDER (object);
       
   908 
       
   909   switch (prop_id) {
       
   910     case PROP_FILTER_CAPS:{
       
   911       GstCaps *new_caps;
       
   912       GstCaps *old_caps;
       
   913       const GstCaps *new_caps_val = gst_value_get_caps (value);
       
   914 
       
   915       if (new_caps_val == NULL) {
       
   916         new_caps = gst_caps_new_any ();
       
   917       } else {
       
   918         new_caps = (GstCaps *) new_caps_val;
       
   919         gst_caps_ref (new_caps);
       
   920       }
       
   921 
       
   922       GST_OBJECT_LOCK (adder);
       
   923       old_caps = adder->filter_caps;
       
   924       adder->filter_caps = new_caps;
       
   925       GST_OBJECT_UNLOCK (adder);
       
   926 
       
   927       gst_caps_unref (old_caps);
       
   928 
       
   929       GST_DEBUG_OBJECT (adder, "set new caps %" GST_PTR_FORMAT, new_caps);
       
   930       break;
       
   931     }
       
   932     default:
       
   933       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   934       break;
       
   935   }
       
   936 }
       
   937 
       
   938 static void
       
   939 gst_adder_get_property (GObject * object, guint prop_id, GValue * value,
       
   940     GParamSpec * pspec)
       
   941 {
       
   942   GstAdder *adder = GST_ADDER (object);
       
   943 
       
   944   switch (prop_id) {
       
   945     case PROP_FILTER_CAPS:
       
   946       GST_OBJECT_LOCK (adder);
       
   947       gst_value_set_caps (value, adder->filter_caps);
       
   948       GST_OBJECT_UNLOCK (adder);
       
   949       break;
       
   950     default:
       
   951       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   952       break;
       
   953   }
       
   954 }
       
   955 
       
   956 
   625 
   957 static GstPad *
   626 static GstPad *
   958 gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
   627 gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
   959     const gchar * unused)
   628     const gchar * unused)
   960 {
   629 {
  1023 
   692 
  1024 static GstFlowReturn
   693 static GstFlowReturn
  1025 gst_adder_collected (GstCollectPads * pads, gpointer user_data)
   694 gst_adder_collected (GstCollectPads * pads, gpointer user_data)
  1026 {
   695 {
  1027   /*
   696   /*
  1028    * combine streams by adding data values
   697    * combine channels by adding sample values
  1029    * basic algorithm :
   698    * basic algorithm :
  1030    * - this function is called when all pads have a buffer
   699    * - this function is called when all pads have a buffer
  1031    * - get available bytes on all pads.
   700    * - get available bytes on all pads.
  1032    * - repeat for each input pad :
   701    * - repeat for each input pad :
  1033    *   - read available bytes, copy or add to target buffer
   702    *   - read available bytes, copy or add to target buffer
  1034    *   - if there's an EOS event, remove the input channel
   703    *   - if there's an EOS event, remove the input channel
  1035    * - push out the output buffer
   704    * - push out the output buffer
  1036    *
       
  1037    * todo:
       
  1038    * - would be nice to have a mixing mode, where instead of adding we mix
       
  1039    *   - for float we could downscale after collect loop
       
  1040    *   - for int we need to downscale each input to avoid clipping or
       
  1041    *     mix into a temp (float) buffer and scale afterwards as well
       
  1042    */
   705    */
  1043   GstAdder *adder;
   706   GstAdder *adder;
       
   707   guint size;
  1044   GSList *collected;
   708   GSList *collected;
       
   709   GstBuffer *outbuf;
  1045   GstFlowReturn ret;
   710   GstFlowReturn ret;
  1046   GstBuffer *outbuf = NULL;
   711   gpointer outbytes;
  1047   gpointer outdata = NULL;
       
  1048   guint outsize;
       
  1049   gboolean empty = TRUE;
   712   gboolean empty = TRUE;
  1050 
   713 
  1051   adder = GST_ADDER (user_data);
   714   adder = GST_ADDER (user_data);
  1052 
   715 
  1053   /* this is fatal */
   716   /* this is fatal */
  1054   if (G_UNLIKELY (adder->func == NULL))
   717   if (G_UNLIKELY (adder->func == NULL))
  1055     goto not_negotiated;
   718     goto not_negotiated;
  1056 
   719 
  1057   if (adder->flush_stop_pending) {
   720   /* get available bytes for reading, this can be 0 which could mean
  1058     gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop ());
   721    * empty buffers or EOS, which we will catch when we loop over the
  1059     adder->flush_stop_pending = FALSE;
   722    * pads. */
  1060   }
   723   size = gst_collect_pads_available (pads);
  1061 
       
  1062   /* get available bytes for reading, this can be 0 which could mean empty
       
  1063    * buffers or EOS, which we will catch when we loop over the pads. */
       
  1064   outsize = gst_collect_pads_available (pads);
       
  1065 
   724 
  1066   GST_LOG_OBJECT (adder,
   725   GST_LOG_OBJECT (adder,
  1067       "starting to cycle through channels, %d bytes available (bps = %d)",
   726       "starting to cycle through channels, %d bytes available (bps = %d)", size,
  1068       outsize, adder->bps);
   727       adder->bps);
       
   728 
       
   729   outbuf = NULL;
       
   730   outbytes = NULL;
  1069 
   731 
  1070   for (collected = pads->data; collected; collected = g_slist_next (collected)) {
   732   for (collected = pads->data; collected; collected = g_slist_next (collected)) {
  1071     GstCollectData *collect_data;
   733     GstCollectData *data;
       
   734     guint8 *bytes;
       
   735     guint len;
  1072     GstBuffer *inbuf;
   736     GstBuffer *inbuf;
  1073     guint8 *indata;
   737 
  1074     guint insize;
   738     data = (GstCollectData *) collected->data;
  1075 
       
  1076     collect_data = (GstCollectData *) collected->data;
       
  1077 
   739 
  1078     /* get a subbuffer of size bytes */
   740     /* get a subbuffer of size bytes */
  1079     inbuf = gst_collect_pads_take_buffer (pads, collect_data, outsize);
   741     inbuf = gst_collect_pads_take_buffer (pads, data, size);
  1080     /* NULL means EOS or an empty buffer so we still need to flush in
   742     /* NULL means EOS or an empty buffer so we still need to flush in
  1081      * case of an empty buffer. */
   743      * case of an empty buffer. */
  1082     if (inbuf == NULL) {
   744     if (inbuf == NULL) {
  1083       GST_LOG_OBJECT (adder, "channel %p: no bytes available", collect_data);
   745       GST_LOG_OBJECT (adder, "channel %p: no bytes available", data);
  1084       continue;
   746       goto next;
  1085     }
   747     }
  1086 
   748 
  1087     indata = GST_BUFFER_DATA (inbuf);
   749     bytes = GST_BUFFER_DATA (inbuf);
  1088     insize = GST_BUFFER_SIZE (inbuf);
   750     len = GST_BUFFER_SIZE (inbuf);
  1089 
   751 
  1090     if (outbuf == NULL) {
   752     if (outbuf == NULL) {
  1091       GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes",
   753       GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes",
  1092           collect_data, outsize);
   754           data, size);
  1093 
   755 
  1094       /* first buffer, alloc outsize.
   756       /* first buffer, alloc size bytes. FIXME, we can easily subbuffer
  1095        * FIXME: we can easily subbuffer and _make_writable.
   757        * and _make_writable. */
  1096        * FIXME: only create empty buffer for first non-gap buffer, so that we
   758       outbuf = gst_buffer_new_and_alloc (size);
  1097        * only use adder function when really adding
   759       outbytes = GST_BUFFER_DATA (outbuf);
  1098        */
       
  1099       outbuf = gst_buffer_new_and_alloc (outsize);
       
  1100       outdata = GST_BUFFER_DATA (outbuf);
       
  1101       gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
   760       gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
  1102 
   761 
  1103       if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
   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 
  1104         GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p",
   767         GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p",
  1105             collect_data, insize, indata);
   768             data, len, bytes);
  1106         /* clear if we are only going to fill a partial buffer */
   769 
  1107         if (G_UNLIKELY (outsize > insize))
       
  1108           memset ((guint8 *) outdata + insize, 0, outsize - insize);
       
  1109         /* and copy the data into it */
   770         /* and copy the data into it */
  1110         memcpy (outdata, indata, insize);
   771         memcpy (outbytes, bytes, len);
  1111         empty = FALSE;
   772         empty = FALSE;
  1112       } else {
   773       } else {
  1113         /* clear whole buffer */
       
  1114         GST_LOG_OBJECT (adder, "channel %p: zeroing %d bytes from data %p",
   774         GST_LOG_OBJECT (adder, "channel %p: zeroing %d bytes from data %p",
  1115             collect_data, insize, indata);
   775             data, len, bytes);
  1116         memset (outdata, 0, outsize);
   776         memset (outbytes, 0, size);
  1117       }
   777       }
  1118     } else {
   778     } else {
  1119       if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
   779       if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
  1120         GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
   780         GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
  1121             collect_data, insize, indata);
   781             data, len, bytes);
  1122         /* further buffers, need to add them */
   782         /* other buffers, need to add them */
  1123         adder->func ((gpointer) outdata, (gpointer) indata, insize);
   783         adder->func ((gpointer) outbytes, (gpointer) bytes, len);
  1124         empty = FALSE;
   784         empty = FALSE;
  1125       } else {
   785       } else {
  1126         GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p",
   786         GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p",
  1127             collect_data, insize, indata);
   787             data, len, bytes);
  1128       }
   788       }
  1129     }
   789     }
  1130     gst_buffer_unref (inbuf);
   790   next:
       
   791     if (inbuf)
       
   792       gst_buffer_unref (inbuf);
  1131   }
   793   }
  1132 
   794 
  1133   /* can only happen when no pads to collect or all EOS */
   795   /* can only happen when no pads to collect or all EOS */
  1134   if (outbuf == NULL)
   796   if (outbuf == NULL)
  1135     goto eos;
   797     goto eos;
  1154      * match.
   816      * match.
  1155      */
   817      */
  1156     event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
   818     event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
  1157         1.0, GST_FORMAT_TIME, adder->timestamp, -1, adder->segment_position);
   819         1.0, GST_FORMAT_TIME, adder->timestamp, -1, adder->segment_position);
  1158 
   820 
  1159     if (event) {
   821     gst_pad_push_event (adder->srcpad, event);
  1160       if (!gst_pad_push_event (adder->srcpad, event)) {
   822     adder->segment_pending = FALSE;
  1161         GST_WARNING_OBJECT (adder->srcpad, "Sending event  %p (%s) failed.",
   823     adder->segment_position = 0;
  1162             event, GST_EVENT_TYPE_NAME (event));
       
  1163       }
       
  1164       adder->segment_pending = FALSE;
       
  1165       adder->segment_position = 0;
       
  1166     } else {
       
  1167       GST_WARNING_OBJECT (adder->srcpad, "Creating new segment event for "
       
  1168           "start:%" G_GINT64_FORMAT "  pos:%" G_GINT64_FORMAT " failed",
       
  1169           adder->timestamp, adder->segment_position);
       
  1170     }
       
  1171   }
       
  1172 
       
  1173   if (G_UNLIKELY (adder->pending_events)) {
       
  1174     GList *tmp = adder->pending_events;
       
  1175 
       
  1176     while (tmp) {
       
  1177       GstEvent *ev = (GstEvent *) tmp->data;
       
  1178 
       
  1179       gst_pad_push_event (adder->srcpad, ev);
       
  1180       tmp = g_list_next (tmp);
       
  1181     }
       
  1182     g_list_free (adder->pending_events);
       
  1183     adder->pending_events = NULL;
       
  1184   }
   824   }
  1185 
   825 
  1186   /* set timestamps on the output buffer */
   826   /* set timestamps on the output buffer */
  1187   GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
   827   GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
  1188   GST_BUFFER_OFFSET (outbuf) = adder->offset;
   828   GST_BUFFER_OFFSET (outbuf) = adder->offset;
  1189 
   829 
  1190   /* for the next timestamp, use the sample counter, which will
   830   /* for the next timestamp, use the sample counter, which will
  1191    * never accumulate rounding errors */
   831    * never accumulate rounding errors */
  1192   adder->offset += outsize / adder->bps;
   832   adder->offset += size / adder->bps;
  1193   adder->timestamp = gst_util_uint64_scale_int (adder->offset,
   833   adder->timestamp = gst_util_uint64_scale_int (adder->offset,
  1194       GST_SECOND, adder->rate);
   834       GST_SECOND, adder->rate);
  1195 
   835 
  1196   /* now we can set the duration of the buffer */
   836   /* now we can set the duration of the buffer */
  1197   GST_BUFFER_DURATION (outbuf) = adder->timestamp -
   837   GST_BUFFER_DURATION (outbuf) = adder->timestamp -
  1203 
   843 
  1204   /* send it out */
   844   /* send it out */
  1205   GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
   845   GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
  1206       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
   846       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
  1207   ret = gst_pad_push (adder->srcpad, outbuf);
   847   ret = gst_pad_push (adder->srcpad, outbuf);
  1208 
       
  1209   GST_LOG_OBJECT (adder, "pushed outbuf, result = %s", gst_flow_get_name (ret));
       
  1210 
   848 
  1211   return ret;
   849   return ret;
  1212 
   850 
  1213   /* ERRORS */
   851   /* ERRORS */
  1214 not_negotiated:
   852 not_negotiated:
  1237     case GST_STATE_CHANGE_NULL_TO_READY:
   875     case GST_STATE_CHANGE_NULL_TO_READY:
  1238       break;
   876       break;
  1239     case GST_STATE_CHANGE_READY_TO_PAUSED:
   877     case GST_STATE_CHANGE_READY_TO_PAUSED:
  1240       adder->timestamp = 0;
   878       adder->timestamp = 0;
  1241       adder->offset = 0;
   879       adder->offset = 0;
  1242       adder->flush_stop_pending = FALSE;
       
  1243       adder->segment_pending = TRUE;
   880       adder->segment_pending = TRUE;
  1244       adder->segment_position = 0;
   881       adder->segment_position = 0;
  1245       adder->segment_rate = 1.0;
   882       adder->segment_rate = 1.0;
  1246       gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
   883       gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
  1247       gst_collect_pads_start (adder->collect);
   884       gst_collect_pads_start (adder->collect);
  1269 
   906 
  1270 
   907 
  1271 static gboolean
   908 static gboolean
  1272 plugin_init (GstPlugin * plugin)
   909 plugin_init (GstPlugin * plugin)
  1273 {
   910 {
  1274   /*oil_init (); */
       
  1275 
       
  1276   if (!gst_element_register (plugin, "adder", GST_RANK_NONE, GST_TYPE_ADDER)) {
   911   if (!gst_element_register (plugin, "adder", GST_RANK_NONE, GST_TYPE_ADDER)) {
  1277     return FALSE;
   912     return FALSE;
  1278   }
   913   }
  1279 
   914 
  1280   return TRUE;
   915   return TRUE;