[svn r793] -created playbinmaemo element; autoplug for nokia devices trunk
authorrenatofilho
Sat Jul 14 17:20:54 2007 +0100 (2007-07-14)
branchtrunk
changeset 787e42706ada231
parent 786 a4529d0f8ede
child 788 357b301e2d23
[svn r793] -created playbinmaemo element; autoplug for nokia devices
gst-gmyth/Makefile.am
gst-gmyth/configure.ac
gst-gmyth/decodebin2/Makefile.am
gst-gmyth/decodebin2/gstdecodebin2.c
gst-gmyth/decodebin2/gstplay-marshal.c
gst-gmyth/decodebin2/gstplay-marshal.h
gst-gmyth/multiqueue/Makefile.am
gst-gmyth/multiqueue/gstdataqueue.c
gst-gmyth/multiqueue/gstdataqueue.h
gst-gmyth/multiqueue/gstmultiqueue.c
gst-gmyth/multiqueue/gstmultiqueue.h
gst-gmyth/playbinmaemo/Makefile.am
gst-gmyth/playbinmaemo/gstplaybinmaemo.c
gst-gmyth/playbinmaemo/gstplaybinmaemo.h
     1.1 --- a/gst-gmyth/Makefile.am	Thu Jul 05 13:43:24 2007 +0100
     1.2 +++ b/gst-gmyth/Makefile.am	Sat Jul 14 17:20:54 2007 +0100
     1.3 @@ -1,9 +1,15 @@
     1.4  SUBDIRS = \
     1.5  	mythsrc \
     1.6  	nuvdemux \
     1.7 -	concatmux
     1.8 +	concatmux \
     1.9 +	playbinmaemo \
    1.10 +	decodebin2 \
    1.11 +	multiqueue
    1.12  
    1.13  DIST_SUBDIRS = \
    1.14  	mythsrc \
    1.15  	nuvdemux \
    1.16 -	concatmux
    1.17 +	concatmux \
    1.18 +	playbinmaemo \
    1.19 +	decodebin2 \
    1.20 +	multiqueue
     2.1 --- a/gst-gmyth/configure.ac	Thu Jul 05 13:43:24 2007 +0100
     2.2 +++ b/gst-gmyth/configure.ac	Sat Jul 14 17:20:54 2007 +0100
     2.3 @@ -120,6 +120,14 @@
     2.4  AC_SUBST(GMYTH_CFLAGS)
     2.5  AC_SUBST(GMYTH_LIBS)
     2.6  
     2.7 +PKG_CHECK_MODULES(X11, x11, HAVE_X11=yes,HAVE_X11=no)
     2.8 +if test "x$HAVE_X11" = "xno"; then
     2.9 +  AC_MSG_ERROR(you need x11-dev installed)
    2.10 +fi
    2.11 +AC_SUBST(X11_CFLAGS)
    2.12 +AC_SUBST(X11_LIBS)
    2.13 +
    2.14 +
    2.15  dnl set the plugindir where plugins should be installed
    2.16  plugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR"
    2.17  AC_SUBST(plugindir)
    2.18 @@ -136,6 +144,9 @@
    2.19      Makefile \
    2.20      nuvdemux/Makefile \
    2.21      mythsrc/Makefile \
    2.22 -    concatmux/Makefile
    2.23 +    concatmux/Makefile \
    2.24 +    playbinmaemo/Makefile \
    2.25 +    decodebin2/Makefile \
    2.26 +    multiqueue/Makefile
    2.27  )
    2.28  
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/gst-gmyth/decodebin2/Makefile.am	Sat Jul 14 17:20:54 2007 +0100
     3.3 @@ -0,0 +1,23 @@
     3.4 +plugin_LTLIBRARIES = libgstdecodebin2.la
     3.5 +
     3.6 +libgstdecodebin2_la_SOURCES =	\
     3.7 +	gstdecodebin2.c \
     3.8 +	gstplay-marshal.c
     3.9 +
    3.10 +libgstdecodebin2_la_CFLAGS = \
    3.11 +	$(GST_CFLAGS) \
    3.12 +	$(GST_BASE_CFLAGS) \
    3.13 +	$(GST_PLUGINS_BASE_CFLAGS)
    3.14 +
    3.15 +libgstdecodebin2_la_LIBADD = \
    3.16 +	$(GST_LIBS_LIBS)
    3.17 +
    3.18 +libgstdecodebin2_la_LDFLAGS = \
    3.19 +	$(GST_LIBS) \
    3.20 +	$(GST_PLUGIN_LDFLAGS) \
    3.21 +	$(GST_BASE_LIBS) \
    3.22 +	$(GST_PLUGINS_BASE_LIBS)
    3.23 +
    3.24 +noinst_HEADERS = \
    3.25 +	gstplay-marshal.h
    3.26 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/gst-gmyth/decodebin2/gstdecodebin2.c	Sat Jul 14 17:20:54 2007 +0100
     4.3 @@ -0,0 +1,2111 @@
     4.4 +/* GStreamer
     4.5 + * Copyright (C) <2006> Edward Hervey <edward@fluendo.com>
     4.6 + *
     4.7 + * This library is free software; you can redistribute it and/or
     4.8 + * modify it under the terms of the GNU Library General Public
     4.9 + * License as published by the Free Software Foundation; either
    4.10 + * version 2 of the License, or (at your option) any later version.
    4.11 + *
    4.12 + * This library is distributed in the hope that it will be useful,
    4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    4.15 + * Library General Public License for more details.
    4.16 + *
    4.17 + * You should have received a copy of the GNU Library General Public
    4.18 + * License along with this library; if not, write to the
    4.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    4.20 + * Boston, MA 02111-1307, USA.
    4.21 + */
    4.22 +
    4.23 +/**
    4.24 + * SECTION:element-decodebin2
    4.25 + * @short_description: Next-generation automatic decoding bin
    4.26 + *
    4.27 + * #GstBin that auto-magically constructs a decoding pipeline using available
    4.28 + * decoders and demuxers via auto-plugging.
    4.29 + *
    4.30 + * At this stage, decodebin2 is considered UNSTABLE. The API provided in the
    4.31 + * signals is expected to change in the near future. 
    4.32 + *
    4.33 + * To try out decodebin2, you can set the USE_DECODEBIN2 environment 
    4.34 + * variable (USE_DECODEBIN2=1 for example). This will cause playbin to use
    4.35 + * decodebin2 instead of the older decodebin for its internal auto-plugging.
    4.36 + */
    4.37 +
    4.38 +#ifdef HAVE_CONFIG_H
    4.39 +#include "config.h"
    4.40 +#endif
    4.41 +
    4.42 +#include <string.h>
    4.43 +#include <gst/gst.h>
    4.44 +
    4.45 +#include "gstplay-marshal.h"
    4.46 +
    4.47 +/* generic templates */
    4.48 +static GstStaticPadTemplate decoder_bin_sink_template =
    4.49 +GST_STATIC_PAD_TEMPLATE ("sink",
    4.50 +    GST_PAD_SINK,
    4.51 +    GST_PAD_ALWAYS,
    4.52 +    GST_STATIC_CAPS_ANY);
    4.53 +
    4.54 +static GstStaticPadTemplate decoder_bin_src_template =
    4.55 +GST_STATIC_PAD_TEMPLATE ("src%d",
    4.56 +    GST_PAD_SRC,
    4.57 +    GST_PAD_SOMETIMES,
    4.58 +    GST_STATIC_CAPS_ANY);
    4.59 +
    4.60 +GST_DEBUG_CATEGORY_STATIC (gst_decode_bin_debug);
    4.61 +#define GST_CAT_DEFAULT gst_decode_bin_debug
    4.62 +
    4.63 +typedef struct _GstDecodeGroup GstDecodeGroup;
    4.64 +typedef struct _GstDecodePad GstDecodePad;
    4.65 +typedef struct _GstDecodeBin GstDecodeBin;
    4.66 +typedef struct _GstDecodeBin GstDecodeBin2;
    4.67 +typedef struct _GstDecodeBinClass GstDecodeBinClass;
    4.68 +
    4.69 +#define GST_TYPE_DECODE_BIN             (gst_decode_bin_get_type())
    4.70 +#define GST_DECODE_BIN_CAST(obj)        ((GstDecodeBin*)(obj))
    4.71 +#define GST_DECODE_BIN(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECODE_BIN,GstDecodeBin))
    4.72 +#define GST_DECODE_BIN_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DECODE_BIN,GstDecodeBinClass))
    4.73 +#define GST_IS_DECODE_BIN(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DECODE_BIN))
    4.74 +#define GST_IS_DECODE_BIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECODE_BIN))
    4.75 +
    4.76 +/**
    4.77 + *  GstDecodeBin2:
    4.78 + *
    4.79 + *  The opaque #DecodeBin2 data structure
    4.80 + */
    4.81 +struct _GstDecodeBin
    4.82 +{
    4.83 +  GstBin bin;                   /* we extend GstBin */
    4.84 +
    4.85 +  GstElement *typefind;         /* this holds the typefind object */
    4.86 +  GstElement *fakesink;
    4.87 +
    4.88 +  GMutex *lock;                 /* Protects activegroup and groups */
    4.89 +  GstDecodeGroup *activegroup;  /* group currently active */
    4.90 +  GList *groups;                /* List of non-active GstDecodeGroups, sorted in
    4.91 +                                 * order of creation. */
    4.92 +  GList *oldgroups;             /* List of no-longer-used GstDecodeGroups. 
    4.93 +                                 * Should be freed in dispose */
    4.94 +  gint nbpads;                  /* unique identifier for source pads */
    4.95 +  GstCaps *caps;                /* caps on which to stop decoding */
    4.96 +
    4.97 +  GList *factories;             /* factories we can use for selecting elements */
    4.98 +};
    4.99 +
   4.100 +struct _GstDecodeBinClass
   4.101 +{
   4.102 +  GstBinClass parent_class;
   4.103 +
   4.104 +  /* signal we fire when a new pad has been decoded into raw audio/video */
   4.105 +  void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
   4.106 +  /* signal we fire when a pad has been removed */
   4.107 +  void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
   4.108 +  /* signal fired when we found a pad that we cannot decode */
   4.109 +  void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
   4.110 +  /* signal fired to know if we continue trying to decode the given caps */
   4.111 +    gboolean (*autoplug_continue) (GstElement * element, GstCaps * caps);
   4.112 +  /* signal fired to reorder the proposed list of factories */
   4.113 +    gboolean (*autoplug_sort) (GstElement * element, GstCaps * caps,
   4.114 +      GList ** list);
   4.115 +};
   4.116 +
   4.117 +/* signals */
   4.118 +enum
   4.119 +{
   4.120 +  SIGNAL_NEW_DECODED_PAD,
   4.121 +  SIGNAL_REMOVED_DECODED_PAD,
   4.122 +  SIGNAL_UNKNOWN_TYPE,
   4.123 +  SIGNAL_AUTOPLUG_CONTINUE,
   4.124 +  SIGNAL_AUTOPLUG_SORT,
   4.125 +  LAST_SIGNAL
   4.126 +};
   4.127 +
   4.128 +/* Properties */
   4.129 +enum
   4.130 +{
   4.131 +  PROP_0,
   4.132 +  PROP_CAPS,
   4.133 +};
   4.134 +
   4.135 +static GstBinClass *parent_class;
   4.136 +static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
   4.137 +
   4.138 +static const GstElementDetails gst_decode_bin_details =
   4.139 +GST_ELEMENT_DETAILS ("Decoder Bin",
   4.140 +    "Generic/Bin/Decoder",
   4.141 +    "Autoplug and decode to raw media",
   4.142 +    "Edward Hervey <edward@fluendo.com>");
   4.143 +
   4.144 +
   4.145 +static gboolean add_fakesink (GstDecodeBin * decode_bin);
   4.146 +static void remove_fakesink (GstDecodeBin * decode_bin);
   4.147 +
   4.148 +static void type_found (GstElement * typefind, guint probability,
   4.149 +    GstCaps * caps, GstDecodeBin * decode_bin);
   4.150 +
   4.151 +static gboolean gst_decode_bin_autoplug_continue (GstElement * element,
   4.152 +    GstCaps * caps);
   4.153 +static gboolean gst_decode_bin_autoplug_sort (GstElement * element,
   4.154 +    GstCaps * caps, GList ** list);
   4.155 +static void gst_decode_bin_set_property (GObject * object, guint prop_id,
   4.156 +    const GValue * value, GParamSpec * pspec);
   4.157 +static void gst_decode_bin_get_property (GObject * object, guint prop_id,
   4.158 +    GValue * value, GParamSpec * pspec);
   4.159 +static void gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps);
   4.160 +static GstCaps *gst_decode_bin_get_caps (GstDecodeBin * dbin);
   4.161 +
   4.162 +static GstPad *find_sink_pad (GstElement * element);
   4.163 +static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element,
   4.164 +    GstStateChange transition);
   4.165 +
   4.166 +#define DECODE_BIN_LOCK(dbin) G_STMT_START {				\
   4.167 +    GST_LOG_OBJECT (dbin,						\
   4.168 +		    "locking from thread %p",				\
   4.169 +		    g_thread_self ());					\
   4.170 +    g_mutex_lock (GST_DECODE_BIN_CAST(dbin)->lock);			\
   4.171 +    GST_LOG_OBJECT (dbin,						\
   4.172 +		    "locked from thread %p",				\
   4.173 +		    g_thread_self ());					\
   4.174 +} G_STMT_END
   4.175 +
   4.176 +#define DECODE_BIN_UNLOCK(dbin) G_STMT_START {				\
   4.177 +    GST_LOG_OBJECT (dbin,						\
   4.178 +		    "unlocking from thread %p",				\
   4.179 +		    g_thread_self ());					\
   4.180 +    g_mutex_unlock (GST_DECODE_BIN_CAST(dbin)->lock);			\
   4.181 +} G_STMT_END
   4.182 +
   4.183 +/* GstDecodeGroup
   4.184 + *
   4.185 + * Streams belonging to the same group/chain of a media file
   4.186 + *
   4.187 + */
   4.188 +
   4.189 +struct _GstDecodeGroup
   4.190 +{
   4.191 +  GstDecodeBin *dbin;
   4.192 +  GMutex *lock;
   4.193 +  GstElement *multiqueue;
   4.194 +  gboolean exposed;             /* TRUE if this group is exposed */
   4.195 +  gboolean drained;             /* TRUE if EOS went throug all endpads */
   4.196 +  gboolean blocked;             /* TRUE if all endpads are blocked */
   4.197 +  gboolean complete;            /* TRUE if we are not expecting anymore streams 
   4.198 +                                 * on this group */
   4.199 +  gulong overrunsig;
   4.200 +  gulong underrunsig;
   4.201 +  guint nbdynamic;              /* number of dynamic pads in the group. */
   4.202 +
   4.203 +  GList *endpads;               /* List of GstDecodePad of source pads to be exposed */
   4.204 +  GList *ghosts;                /* List of GstGhostPad for the endpads */
   4.205 +};
   4.206 +
   4.207 +#define GROUP_MUTEX_LOCK(group) G_STMT_START {				\
   4.208 +    GST_LOG_OBJECT (group->dbin,					\
   4.209 +		    "locking group %p from thread %p",			\
   4.210 +		    group, g_thread_self ());				\
   4.211 +    g_mutex_lock (group->lock);						\
   4.212 +    GST_LOG_OBJECT (group->dbin,					\
   4.213 +		    "locked group %p from thread %p",			\
   4.214 +		    group, g_thread_self ());				\
   4.215 +} G_STMT_END
   4.216 +
   4.217 +#define GROUP_MUTEX_UNLOCK(group) G_STMT_START {                        \
   4.218 +    GST_LOG_OBJECT (group->dbin,					\
   4.219 +		    "unlocking group %p from thread %p",		\
   4.220 +		    group, g_thread_self ());				\
   4.221 +    g_mutex_unlock (group->lock);					\
   4.222 +} G_STMT_END
   4.223 +
   4.224 +
   4.225 +static GstDecodeGroup *gst_decode_group_new (GstDecodeBin * decode_bin);
   4.226 +static GstPad *gst_decode_group_control_demuxer_pad (GstDecodeGroup * group,
   4.227 +    GstPad * pad);
   4.228 +static gboolean gst_decode_group_control_source_pad (GstDecodeGroup * group,
   4.229 +    GstPad * pad);
   4.230 +static gboolean gst_decode_group_expose (GstDecodeGroup * group);
   4.231 +static void gst_decode_group_check_if_blocked (GstDecodeGroup * group);
   4.232 +static void gst_decode_group_set_complete (GstDecodeGroup * group);
   4.233 +static void gst_decode_group_hide (GstDecodeGroup * group);
   4.234 +static void gst_decode_group_free (GstDecodeGroup * group);
   4.235 +
   4.236 +/* GstDecodePad
   4.237 + *
   4.238 + * GstPad private used for source pads of groups
   4.239 + */
   4.240 +
   4.241 +struct _GstDecodePad
   4.242 +{
   4.243 +  GstPad *pad;
   4.244 +  GstDecodeGroup *group;
   4.245 +  gboolean blocked;
   4.246 +  gboolean drained;
   4.247 +};
   4.248 +
   4.249 +static GstDecodePad *gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad,
   4.250 +    gboolean block);
   4.251 +static void source_pad_blocked_cb (GstPad * pad, gboolean blocked,
   4.252 +    GstDecodePad * dpad);
   4.253 +
   4.254 +/* TempPadStruct
   4.255 + * Internal structure used for pads which have more than one structure.
   4.256 + */
   4.257 +typedef struct _TempPadStruct
   4.258 +{
   4.259 +  GstDecodeBin *dbin;
   4.260 +  GstDecodeGroup *group;
   4.261 +} TempPadStruct;
   4.262 +
   4.263 +/********************************
   4.264 + * Standard GObject boilerplate *
   4.265 + ********************************/
   4.266 +
   4.267 +static void gst_decode_bin_class_init (GstDecodeBinClass * klass);
   4.268 +static void gst_decode_bin_init (GstDecodeBin * decode_bin);
   4.269 +static void gst_decode_bin_dispose (GObject * object);
   4.270 +static void gst_decode_bin_finalize (GObject * object);
   4.271 +
   4.272 +static GType
   4.273 +gst_decode_bin_get_type (void)
   4.274 +{
   4.275 +  static GType gst_decode_bin_type = 0;
   4.276 +
   4.277 +  if (!gst_decode_bin_type) {
   4.278 +    static const GTypeInfo gst_decode_bin_info = {
   4.279 +      sizeof (GstDecodeBinClass),
   4.280 +      NULL,
   4.281 +      NULL,
   4.282 +      (GClassInitFunc) gst_decode_bin_class_init,
   4.283 +      NULL,
   4.284 +      NULL,
   4.285 +      sizeof (GstDecodeBin),
   4.286 +      0,
   4.287 +      (GInstanceInitFunc) gst_decode_bin_init,
   4.288 +      NULL
   4.289 +    };
   4.290 +
   4.291 +    gst_decode_bin_type =
   4.292 +        g_type_register_static (GST_TYPE_BIN, "GstDecodeBin2",
   4.293 +        &gst_decode_bin_info, 0);
   4.294 +  }
   4.295 +
   4.296 +  return gst_decode_bin_type;
   4.297 +}
   4.298 +
   4.299 +static gboolean
   4.300 +_gst_boolean_accumulator (GSignalInvocationHint * ihint,
   4.301 +    GValue * return_accu, const GValue * handler_return, gpointer dummy)
   4.302 +{
   4.303 +  gboolean myboolean;
   4.304 +
   4.305 +  myboolean = g_value_get_boolean (handler_return);
   4.306 +  if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
   4.307 +    g_value_set_boolean (return_accu, myboolean);
   4.308 +
   4.309 +  /* stop emission if FALSE */
   4.310 +  return myboolean;
   4.311 +}
   4.312 +
   4.313 +static void
   4.314 +gst_decode_bin_class_init (GstDecodeBinClass * klass)
   4.315 +{
   4.316 +  GObjectClass *gobject_klass;
   4.317 +  GstElementClass *gstelement_klass;
   4.318 +  GstBinClass *gstbin_klass;
   4.319 +
   4.320 +  gobject_klass = (GObjectClass *) klass;
   4.321 +  gstelement_klass = (GstElementClass *) klass;
   4.322 +  gstbin_klass = (GstBinClass *) klass;
   4.323 +
   4.324 +  parent_class = g_type_class_peek_parent (klass);
   4.325 +
   4.326 +  gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
   4.327 +  gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_decode_bin_finalize);
   4.328 +  gobject_klass->set_property = GST_DEBUG_FUNCPTR (gst_decode_bin_set_property);
   4.329 +  gobject_klass->get_property = GST_DEBUG_FUNCPTR (gst_decode_bin_get_property);
   4.330 +
   4.331 +  /**
   4.332 +   * GstDecodeBin2::new-decoded-pad:
   4.333 +   * @pad: the newly created pad
   4.334 +   * @islast: #TRUE if this is the last pad to be added. Deprecated.
   4.335 +   *
   4.336 +   * This signal gets emitted as soon as a new pad of the same type as one of
   4.337 +   * the valid 'raw' types is added.
   4.338 +   */
   4.339 +
   4.340 +  gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD] =
   4.341 +      g_signal_new ("new-decoded-pad", G_TYPE_FROM_CLASS (klass),
   4.342 +      G_SIGNAL_RUN_LAST,
   4.343 +      G_STRUCT_OFFSET (GstDecodeBinClass, new_decoded_pad), NULL, NULL,
   4.344 +      gst_play_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, GST_TYPE_PAD,
   4.345 +      G_TYPE_BOOLEAN);
   4.346 +
   4.347 +  /**
   4.348 +   * GstDecodeBin2::removed-decoded-pad:
   4.349 +   * @pad: the pad that was removed
   4.350 +   *
   4.351 +   * This signal is emitted when a 'final' caps pad has been removed.
   4.352 +   */
   4.353 +
   4.354 +  gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD] =
   4.355 +      g_signal_new ("removed-decoded-pad", G_TYPE_FROM_CLASS (klass),
   4.356 +      G_SIGNAL_RUN_LAST,
   4.357 +      G_STRUCT_OFFSET (GstDecodeBinClass, removed_decoded_pad), NULL, NULL,
   4.358 +      gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
   4.359 +
   4.360 +  /**
   4.361 +   * GstDecodeBin2::unknown-type:
   4.362 +   * @pad: the new pad containing caps that cannot be resolved to a 'final' stream type.
   4.363 +   * @caps: the #GstCaps of the pad that cannot be resolved.
   4.364 +   *
   4.365 +   * This signal is emitted when a pad for which there is no further possible
   4.366 +   * decoding is added to the decodebin.
   4.367 +   */
   4.368 +
   4.369 +  gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] =
   4.370 +      g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass),
   4.371 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
   4.372 +      NULL, NULL, gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2,
   4.373 +      GST_TYPE_PAD, GST_TYPE_CAPS);
   4.374 +
   4.375 +  /**
   4.376 +   * GstDecodeBin2::autoplug-continue:
   4.377 +   * @caps: The #GstCaps found.
   4.378 +   *
   4.379 +   * This signal is emitted whenever decodebin2 finds a new stream. It is
   4.380 +   * emitted before looking for any elements that can handle that stream.
   4.381 +   *
   4.382 +   * Returns: #TRUE if you wish decodebin2 to look for elements that can
   4.383 +   * handle the given @caps. If #FALSE, those caps will be considered as
   4.384 +   * final and the pad will be exposed as such (see 'new-decoded-pad'
   4.385 +   * signal).
   4.386 +   */
   4.387 +
   4.388 +  gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE] =
   4.389 +      g_signal_new ("autoplug-continue", G_TYPE_FROM_CLASS (klass),
   4.390 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_continue),
   4.391 +      _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT,
   4.392 +      G_TYPE_BOOLEAN, 1, GST_TYPE_CAPS);
   4.393 +
   4.394 +  /**
   4.395 +   * GstDecodeBin2::autoplug-sort:
   4.396 +   * @caps: The #GstCaps.
   4.397 +   * @factories: A #GList of possible #GstElementFactory to use.
   4.398 +   *
   4.399 +   * This signal is emitted once decodebin2 has found all the possible
   4.400 +   * #GstElementFactory that can be used to handle the given @caps.
   4.401 +   *
   4.402 +   * UNSTABLE API. Will change soon.
   4.403 +   *
   4.404 +   * Returns: #TRUE if you wish decodebin2 to start trying to decode
   4.405 +   * the given @caps with the list of factories. #FALSE if you do not want
   4.406 +   * these #GstCaps, if so the pad will be exposed as unknown (see
   4.407 +   * 'unknown-type' signal).
   4.408 +   */
   4.409 +
   4.410 +  gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT] =
   4.411 +      g_signal_new ("autoplug-sort", G_TYPE_FROM_CLASS (klass),
   4.412 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_sort),
   4.413 +      _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT_POINTER,
   4.414 +      G_TYPE_BOOLEAN, 2, GST_TYPE_CAPS, G_TYPE_POINTER);
   4.415 +
   4.416 +  g_object_class_install_property (gobject_klass, PROP_CAPS,
   4.417 +      g_param_spec_boxed ("caps", "Caps", "The caps on which to stop decoding.",
   4.418 +          GST_TYPE_CAPS, G_PARAM_READWRITE));
   4.419 +
   4.420 +  klass->autoplug_continue =
   4.421 +      GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_continue);
   4.422 +  klass->autoplug_sort = GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_sort);
   4.423 +
   4.424 +  gst_element_class_add_pad_template (gstelement_klass,
   4.425 +      gst_static_pad_template_get (&decoder_bin_sink_template));
   4.426 +  gst_element_class_add_pad_template (gstelement_klass,
   4.427 +      gst_static_pad_template_get (&decoder_bin_src_template));
   4.428 +
   4.429 +  gst_element_class_set_details (gstelement_klass, &gst_decode_bin_details);
   4.430 +
   4.431 +  gstelement_klass->change_state =
   4.432 +      GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
   4.433 +}
   4.434 +
   4.435 +/* the filter function for selecting the elements we can use in
   4.436 + * autoplugging */
   4.437 +static gboolean
   4.438 +gst_decode_bin_factory_filter (GstPluginFeature * feature,
   4.439 +    GstDecodeBin * decode_bin)
   4.440 +{
   4.441 +  guint rank;
   4.442 +  const gchar *klass;
   4.443 +
   4.444 +  /* we only care about element factories */
   4.445 +  if (!GST_IS_ELEMENT_FACTORY (feature))
   4.446 +    return FALSE;
   4.447 +
   4.448 +  klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
   4.449 +  /* only demuxers, decoders and parsers can play */
   4.450 +  if (strstr (klass, "Demux") == NULL &&
   4.451 +      strstr (klass, "Decoder") == NULL && strstr (klass, "Parse") == NULL) {
   4.452 +    return FALSE;
   4.453 +  }
   4.454 +
   4.455 +  /* only select elements with autoplugging rank */
   4.456 +  rank = gst_plugin_feature_get_rank (feature);
   4.457 +  if (rank < GST_RANK_MARGINAL)
   4.458 +    return FALSE;
   4.459 +
   4.460 +  return TRUE;
   4.461 +}
   4.462 +
   4.463 +/* function used to sort element features */
   4.464 +static gint
   4.465 +compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
   4.466 +{
   4.467 +  gint diff;
   4.468 +  const gchar *rname1, *rname2;
   4.469 +
   4.470 +  diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
   4.471 +  if (diff != 0)
   4.472 +    return diff;
   4.473 +
   4.474 +  rname1 = gst_plugin_feature_get_name (f1);
   4.475 +  rname2 = gst_plugin_feature_get_name (f2);
   4.476 +
   4.477 +  diff = strcmp (rname2, rname1);
   4.478 +
   4.479 +  return diff;
   4.480 +}
   4.481 +
   4.482 +static void
   4.483 +print_feature (GstPluginFeature * feature)
   4.484 +{
   4.485 +  const gchar *rname;
   4.486 +
   4.487 +  rname = gst_plugin_feature_get_name (feature);
   4.488 +
   4.489 +  GST_DEBUG ("%s", rname);
   4.490 +}
   4.491 +
   4.492 +static void
   4.493 +gst_decode_bin_init (GstDecodeBin * decode_bin)
   4.494 +{
   4.495 +  GList *factories;
   4.496 +
   4.497 +  /* first filter out the interesting element factories */
   4.498 +  factories = gst_default_registry_feature_filter (
   4.499 +      (GstPluginFeatureFilter) gst_decode_bin_factory_filter,
   4.500 +      FALSE, decode_bin);
   4.501 +
   4.502 +  /* sort them according to their ranks */
   4.503 +  decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
   4.504 +  /* do some debugging */
   4.505 +  g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
   4.506 +
   4.507 +
   4.508 +  /* we create the typefind element only once */
   4.509 +  decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
   4.510 +  if (!decode_bin->typefind) {
   4.511 +    g_warning ("can't find typefind element, decodebin will not work");
   4.512 +  } else {
   4.513 +    GstPad *pad;
   4.514 +    GstPad *gpad;
   4.515 +
   4.516 +    /* add the typefind element */
   4.517 +    if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind)) {
   4.518 +      g_warning ("Could not add typefind element, decodebin will not work");
   4.519 +      gst_object_unref (decode_bin->typefind);
   4.520 +      decode_bin->typefind = NULL;
   4.521 +    }
   4.522 +
   4.523 +    /* get the sinkpad */
   4.524 +    pad = gst_element_get_pad (decode_bin->typefind, "sink");
   4.525 +
   4.526 +    /* ghost the sink pad to ourself */
   4.527 +    gpad = gst_ghost_pad_new ("sink", pad);
   4.528 +    gst_pad_set_active (gpad, TRUE);
   4.529 +    gst_element_add_pad (GST_ELEMENT (decode_bin), gpad);
   4.530 +
   4.531 +    gst_object_unref (pad);
   4.532 +
   4.533 +    /* connect a signal to find out when the typefind element found
   4.534 +     * a type */
   4.535 +    g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
   4.536 +        G_CALLBACK (type_found), decode_bin);
   4.537 +  }
   4.538 +
   4.539 +  decode_bin->lock = g_mutex_new ();
   4.540 +  decode_bin->activegroup = NULL;
   4.541 +  decode_bin->groups = NULL;
   4.542 +
   4.543 +  decode_bin->caps =
   4.544 +      gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray;"
   4.545 +      "audio/x-raw-int;audio/x-raw-float;" "text/plain;text/x-pango-markup");
   4.546 +
   4.547 +  add_fakesink (decode_bin);
   4.548 +
   4.549 +  /* FILLME */
   4.550 +}
   4.551 +
   4.552 +static void
   4.553 +gst_decode_bin_dispose (GObject * object)
   4.554 +{
   4.555 +  GstDecodeBin *decode_bin;
   4.556 +  GList *tmp;
   4.557 +
   4.558 +  decode_bin = GST_DECODE_BIN (object);
   4.559 +
   4.560 +  if (decode_bin->factories)
   4.561 +    gst_plugin_feature_list_free (decode_bin->factories);
   4.562 +  decode_bin->factories = NULL;
   4.563 +
   4.564 +  if (decode_bin->activegroup) {
   4.565 +    gst_decode_group_free (decode_bin->activegroup);
   4.566 +    decode_bin->activegroup = NULL;
   4.567 +  }
   4.568 +
   4.569 +  /* remove groups */
   4.570 +  for (tmp = decode_bin->groups; tmp; tmp = g_list_next (tmp)) {
   4.571 +    GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
   4.572 +
   4.573 +    gst_decode_group_free (group);
   4.574 +  }
   4.575 +  g_list_free (decode_bin->groups);
   4.576 +  decode_bin->groups = NULL;
   4.577 +
   4.578 +  for (tmp = decode_bin->oldgroups; tmp; tmp = g_list_next (tmp)) {
   4.579 +    GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
   4.580 +
   4.581 +    gst_decode_group_free (group);
   4.582 +  }
   4.583 +  g_list_free (decode_bin->oldgroups);
   4.584 +  decode_bin->oldgroups = NULL;
   4.585 +
   4.586 +  if (decode_bin->caps)
   4.587 +    gst_caps_unref (decode_bin->caps);
   4.588 +  decode_bin->caps = NULL;
   4.589 +  remove_fakesink (decode_bin);
   4.590 +
   4.591 +  G_OBJECT_CLASS (parent_class)->dispose (object);
   4.592 +}
   4.593 +
   4.594 +static void
   4.595 +gst_decode_bin_finalize (GObject * object)
   4.596 +{
   4.597 +  GstDecodeBin *decode_bin;
   4.598 +
   4.599 +  decode_bin = GST_DECODE_BIN (object);
   4.600 +
   4.601 +  if (decode_bin->lock) {
   4.602 +    g_mutex_free (decode_bin->lock);
   4.603 +    decode_bin->lock = NULL;
   4.604 +  }
   4.605 +
   4.606 +  G_OBJECT_CLASS (parent_class)->finalize (object);
   4.607 +}
   4.608 +
   4.609 +static void
   4.610 +gst_decode_bin_set_property (GObject * object, guint prop_id,
   4.611 +    const GValue * value, GParamSpec * pspec)
   4.612 +{
   4.613 +  GstDecodeBin *dbin;
   4.614 +
   4.615 +  dbin = GST_DECODE_BIN (object);
   4.616 +
   4.617 +  switch (prop_id) {
   4.618 +    case PROP_CAPS:
   4.619 +      gst_decode_bin_set_caps (dbin, (GstCaps *) g_value_dup_boxed (value));
   4.620 +      break;
   4.621 +    default:
   4.622 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   4.623 +      break;
   4.624 +  }
   4.625 +}
   4.626 +
   4.627 +static void
   4.628 +gst_decode_bin_get_property (GObject * object, guint prop_id,
   4.629 +    GValue * value, GParamSpec * pspec)
   4.630 +{
   4.631 +  GstDecodeBin *dbin;
   4.632 +
   4.633 +  dbin = GST_DECODE_BIN (object);
   4.634 +  switch (prop_id) {
   4.635 +    case PROP_CAPS:{
   4.636 +      g_value_take_boxed (value, gst_decode_bin_get_caps (dbin));
   4.637 +      break;
   4.638 +    }
   4.639 +    default:
   4.640 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   4.641 +      break;
   4.642 +  }
   4.643 +
   4.644 +}
   4.645 +
   4.646 +/* _set_caps
   4.647 + * Changes the caps on which decodebin will stop decoding.
   4.648 + * Will unref the previously set one. The refcount of the given caps will be
   4.649 + * taken.
   4.650 + * @caps can be NULL.
   4.651 + *
   4.652 + * MT-safe
   4.653 + */
   4.654 +
   4.655 +static void
   4.656 +gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps)
   4.657 +{
   4.658 +  GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps);
   4.659 +
   4.660 +  DECODE_BIN_LOCK (dbin);
   4.661 +  if (dbin->caps)
   4.662 +    gst_caps_unref (dbin->caps);
   4.663 +  dbin->caps = caps;
   4.664 +  DECODE_BIN_UNLOCK (dbin);
   4.665 +}
   4.666 +
   4.667 +/* _get_caps
   4.668 + * Returns the currently configured caps on which decodebin will stop decoding.
   4.669 + * The returned caps (if not NULL), will have its refcount incremented.
   4.670 + *
   4.671 + * MT-safe
   4.672 + */
   4.673 +
   4.674 +static GstCaps *
   4.675 +gst_decode_bin_get_caps (GstDecodeBin * dbin)
   4.676 +{
   4.677 +  GstCaps *caps;
   4.678 +
   4.679 +  GST_DEBUG_OBJECT (dbin, "Getting currently set caps");
   4.680 +
   4.681 +  DECODE_BIN_LOCK (dbin);
   4.682 +  caps = dbin->caps;
   4.683 +  if (caps)
   4.684 +    gst_caps_ref (caps);
   4.685 +  DECODE_BIN_UNLOCK (dbin);
   4.686 +
   4.687 +  return caps;
   4.688 +}
   4.689 +
   4.690 +/*****
   4.691 + * Default autoplug signal handlers
   4.692 + *****/
   4.693 +
   4.694 +static gboolean
   4.695 +gst_decode_bin_autoplug_continue (GstElement * element, GstCaps * caps)
   4.696 +{
   4.697 +  return TRUE;
   4.698 +}
   4.699 +
   4.700 +static gboolean
   4.701 +gst_decode_bin_autoplug_sort (GstElement * element, GstCaps * caps,
   4.702 +    GList ** list)
   4.703 +{
   4.704 +  return TRUE;
   4.705 +}
   4.706 +
   4.707 +
   4.708 +
   4.709 +/********
   4.710 + * Discovery methods
   4.711 + *****/
   4.712 +
   4.713 +static gboolean are_raw_caps (GstDecodeBin * dbin, GstCaps * caps);
   4.714 +static gboolean is_demuxer_element (GstElement * srcelement);
   4.715 +static GList *find_compatibles (GstDecodeBin * decode_bin,
   4.716 +    const GstCaps * caps);
   4.717 +
   4.718 +static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src,
   4.719 +    GstPad * pad, GList * factories, GstDecodeGroup * group);
   4.720 +static gboolean connect_element (GstDecodeBin * dbin, GstElement * element,
   4.721 +    GstDecodeGroup * group);
   4.722 +static void expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
   4.723 +    GstDecodeGroup * group);
   4.724 +
   4.725 +static void pad_added_group_cb (GstElement * element, GstPad * pad,
   4.726 +    GstDecodeGroup * group);
   4.727 +static void pad_removed_group_cb (GstElement * element, GstPad * pad,
   4.728 +    GstDecodeGroup * group);
   4.729 +static void no_more_pads_group_cb (GstElement * element,
   4.730 +    GstDecodeGroup * group);
   4.731 +static void pad_added_cb (GstElement * element, GstPad * pad,
   4.732 +    GstDecodeBin * dbin);
   4.733 +static void pad_removed_cb (GstElement * element, GstPad * pad,
   4.734 +    GstDecodeBin * dbin);
   4.735 +static void no_more_pads_cb (GstElement * element, GstDecodeBin * dbin);
   4.736 +
   4.737 +static GstDecodeGroup *get_current_group (GstDecodeBin * dbin);
   4.738 +
   4.739 +static void
   4.740 +analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
   4.741 +    GstCaps * caps, GstDecodeGroup * group)
   4.742 +{
   4.743 +  gboolean apcontinue = TRUE;
   4.744 +  GList *factories = NULL;
   4.745 +  gboolean apsort = TRUE;
   4.746 +
   4.747 +  GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
   4.748 +      GST_DEBUG_PAD_NAME (pad), caps);
   4.749 +
   4.750 +  if ((caps == NULL) || gst_caps_is_empty (caps))
   4.751 +    goto unknown_type;
   4.752 +
   4.753 +  if (gst_caps_is_any (caps))
   4.754 +    goto any_caps;
   4.755 +
   4.756 +  /* 1. Emit 'autoplug-continue' */
   4.757 +  g_signal_emit (G_OBJECT (dbin),
   4.758 +      gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, caps, &apcontinue);
   4.759 +
   4.760 +  /* 1.a if autoplug-continue is FALSE or caps is a raw format, goto pad_is_final */
   4.761 +  if ((!apcontinue) || are_raw_caps (dbin, caps))
   4.762 +    goto expose_pad;
   4.763 +
   4.764 +  /* 1.b else if there's no compatible factory or 'autoplug-sort' returned FALSE, goto pad_not_used */
   4.765 +  if ((factories = find_compatibles (dbin, caps))) {
   4.766 +    /* emit autoplug-sort */
   4.767 +    g_signal_emit (G_OBJECT (dbin),
   4.768 +        gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT],
   4.769 +        0, caps, &factories, &apsort);
   4.770 +    if (!apsort) {
   4.771 +      g_list_free (factories);
   4.772 +      /* User doesn't want that pad */
   4.773 +      goto pad_not_wanted;
   4.774 +    }
   4.775 +  } else {
   4.776 +    /* no compatible factories */
   4.777 +    goto unknown_type;
   4.778 +  }
   4.779 +
   4.780 +  /* 1.c else goto pad_is_valid */
   4.781 +  GST_LOG_OBJECT (pad, "Let's continue discovery on this pad");
   4.782 +
   4.783 +  connect_pad (dbin, src, pad, factories, group);
   4.784 +  g_list_free (factories);
   4.785 +
   4.786 +  return;
   4.787 +
   4.788 +expose_pad:
   4.789 +  {
   4.790 +    GST_LOG_OBJECT (dbin, "Pad is final. autoplug-continue:%d", apcontinue);
   4.791 +    expose_pad (dbin, src, pad, group);
   4.792 +    return;
   4.793 +  }
   4.794 +
   4.795 +pad_not_wanted:
   4.796 +  {
   4.797 +    GST_LOG_OBJECT (pad, "User doesn't want this pad, stopping discovery");
   4.798 +    return;
   4.799 +  }
   4.800 +
   4.801 +unknown_type:
   4.802 +  {
   4.803 +    GST_LOG_OBJECT (pad, "Unknown type, firing signal");
   4.804 +    g_signal_emit (G_OBJECT (dbin),
   4.805 +        gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
   4.806 +
   4.807 +    /* Check if there are no pending groups, if so, remove fakesink */
   4.808 +    if (dbin->groups == NULL)
   4.809 +      remove_fakesink (dbin);
   4.810 +
   4.811 +    return;
   4.812 +  }
   4.813 +
   4.814 +any_caps:
   4.815 +  {
   4.816 +    GST_WARNING_OBJECT (pad,
   4.817 +        "pad has ANY caps, not able to autoplug to anything");
   4.818 +    /* FIXME : connect to caps notification */
   4.819 +    return;
   4.820 +  }
   4.821 +}
   4.822 +
   4.823 +
   4.824 +/* connect_pad:
   4.825 + *
   4.826 + * Try to connect the given pad to an element created from one of the factories,
   4.827 + * and recursively.
   4.828 + *
   4.829 + * Returns TRUE if an element was properly created and linked
   4.830 + */
   4.831 +
   4.832 +static gboolean
   4.833 +connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
   4.834 +    GList * factories, GstDecodeGroup * group)
   4.835 +{
   4.836 +  gboolean res = FALSE;
   4.837 +  GList *tmp;
   4.838 +
   4.839 +  g_return_val_if_fail (factories != NULL, FALSE);
   4.840 +  GST_DEBUG_OBJECT (dbin, "pad %s:%s , group:%p",
   4.841 +      GST_DEBUG_PAD_NAME (pad), group);
   4.842 +
   4.843 +  /* 1. is element demuxer or parser */
   4.844 +  if (is_demuxer_element (src)) {
   4.845 +    GstPad *mqpad;
   4.846 +
   4.847 +    GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
   4.848 +
   4.849 +    if (!group)
   4.850 +      if (!(group = get_current_group (dbin))) {
   4.851 +        group = gst_decode_group_new (dbin);
   4.852 +        DECODE_BIN_LOCK (dbin);
   4.853 +        dbin->groups = g_list_append (dbin->groups, group);
   4.854 +        DECODE_BIN_UNLOCK (dbin);
   4.855 +      }
   4.856 +
   4.857 +    if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
   4.858 +      goto beach;
   4.859 +    pad = mqpad;
   4.860 +  }
   4.861 +
   4.862 +  /* 2. Try to create an element and link to it */
   4.863 +  for (tmp = factories; tmp; tmp = g_list_next (tmp)) {
   4.864 +    GstElementFactory *factory = (GstElementFactory *) tmp->data;
   4.865 +    GstElement *element;
   4.866 +    GstPad *sinkpad;
   4.867 +
   4.868 +    /* 2.1. Try to create an element */
   4.869 +    if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
   4.870 +      GST_WARNING_OBJECT (dbin, "Could not create an element from %s",
   4.871 +          gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
   4.872 +      continue;
   4.873 +    }
   4.874 +
   4.875 +    /* 2.3. Find its sink pad */
   4.876 +    if (!(sinkpad = find_sink_pad (element))) {
   4.877 +      GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
   4.878 +          GST_ELEMENT_NAME (element));
   4.879 +      gst_object_unref (element);
   4.880 +      continue;
   4.881 +    }
   4.882 +
   4.883 +    /* 2.4 add it ... */
   4.884 +    if (!(gst_bin_add (GST_BIN (dbin), element))) {
   4.885 +      GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
   4.886 +          GST_ELEMENT_NAME (element));
   4.887 +      gst_object_unref (sinkpad);
   4.888 +      gst_object_unref (element);
   4.889 +      continue;
   4.890 +    }
   4.891 +
   4.892 +    /* ... activate it ... */
   4.893 +    if ((gst_element_set_state (element,
   4.894 +                GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
   4.895 +      GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
   4.896 +          GST_ELEMENT_NAME (element));
   4.897 +      gst_object_unref (sinkpad);
   4.898 +      gst_bin_remove (GST_BIN (dbin), element);
   4.899 +      continue;
   4.900 +    }
   4.901 +
   4.902 +    /* 2.5 ...and try to link */
   4.903 +    if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
   4.904 +      GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s",
   4.905 +          GST_DEBUG_PAD_NAME (sinkpad));
   4.906 +      gst_element_set_state (element, GST_STATE_NULL);
   4.907 +      gst_object_unref (sinkpad);
   4.908 +      gst_bin_remove (GST_BIN (dbin), element);
   4.909 +      continue;
   4.910 +    }
   4.911 +
   4.912 +    GST_LOG_OBJECT (dbin, "linked on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
   4.913 +
   4.914 +    /* link this element further */
   4.915 +    connect_element (dbin, element, group);
   4.916 +
   4.917 +    /* Bring the element to the state of the parent */
   4.918 +    if ((gst_element_set_state (element,
   4.919 +                GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
   4.920 +      GST_WARNING_OBJECT (dbin, "Couldn't set %s to PAUSED",
   4.921 +          GST_ELEMENT_NAME (element));
   4.922 +      gst_element_set_state (element, GST_STATE_NULL);
   4.923 +      gst_object_unref (sinkpad);
   4.924 +      gst_bin_remove (GST_BIN (dbin), element);
   4.925 +      continue;
   4.926 +    }
   4.927 +
   4.928 +    res = TRUE;
   4.929 +    break;
   4.930 +  }
   4.931 +
   4.932 +beach:
   4.933 +  return res;
   4.934 +}
   4.935 +
   4.936 +static gboolean
   4.937 +connect_element (GstDecodeBin * dbin, GstElement * element,
   4.938 +    GstDecodeGroup * group)
   4.939 +{
   4.940 +  GList *pads;
   4.941 +  gboolean res = TRUE;
   4.942 +  gboolean dynamic = FALSE;
   4.943 +  GList *to_connect = NULL;
   4.944 +
   4.945 +  GST_DEBUG_OBJECT (dbin, "Attempting to connect element %s [group:%p] further",
   4.946 +      GST_ELEMENT_NAME (element), group);
   4.947 +
   4.948 +  /* 1. Loop over pad templates, grabbing existing pads along the way */
   4.949 +  for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
   4.950 +      pads = g_list_next (pads)) {
   4.951 +    GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
   4.952 +    const gchar *templ_name;
   4.953 +
   4.954 +    /* we are only interested in source pads */
   4.955 +    if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
   4.956 +      continue;
   4.957 +
   4.958 +    templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
   4.959 +    GST_DEBUG_OBJECT (dbin, "got a source pad template %s", templ_name);
   4.960 +
   4.961 +    /* figure out what kind of pad this is */
   4.962 +    switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
   4.963 +      case GST_PAD_ALWAYS:
   4.964 +      {
   4.965 +        /* get the pad that we need to autoplug */
   4.966 +        GstPad *pad = gst_element_get_pad (element, templ_name);
   4.967 +
   4.968 +        if (pad) {
   4.969 +          GST_DEBUG_OBJECT (dbin, "got the pad for always template %s",
   4.970 +              templ_name);
   4.971 +          /* here is the pad, we need to autoplug it */
   4.972 +          to_connect = g_list_prepend (to_connect, pad);
   4.973 +        } else {
   4.974 +          /* strange, pad is marked as always but it's not
   4.975 +           * there. Fix the element */
   4.976 +          GST_WARNING_OBJECT (dbin,
   4.977 +              "could not get the pad for always template %s", templ_name);
   4.978 +        }
   4.979 +        break;
   4.980 +      }
   4.981 +      case GST_PAD_SOMETIMES:
   4.982 +      {
   4.983 +        /* try to get the pad to see if it is already created or
   4.984 +         * not */
   4.985 +        GstPad *pad = gst_element_get_pad (element, templ_name);
   4.986 +
   4.987 +        if (pad) {
   4.988 +          GST_DEBUG_OBJECT (dbin, "got the pad for sometimes template %s",
   4.989 +              templ_name);
   4.990 +          /* the pad is created, we need to autoplug it */
   4.991 +          to_connect = g_list_prepend (to_connect, pad);
   4.992 +        } else {
   4.993 +          GST_DEBUG_OBJECT (dbin,
   4.994 +              "did not get the sometimes pad of template %s", templ_name);
   4.995 +          /* we have an element that will create dynamic pads */
   4.996 +          dynamic = TRUE;
   4.997 +        }
   4.998 +        break;
   4.999 +      }
  4.1000 +      case GST_PAD_REQUEST:
  4.1001 +        /* ignore request pads */
  4.1002 +        GST_DEBUG_OBJECT (dbin, "ignoring request padtemplate %s", templ_name);
  4.1003 +        break;
  4.1004 +    }
  4.1005 +  }
  4.1006 +
  4.1007 +  /* 2. if there are more potential pads, connect to relevent signals */
  4.1008 +  if (dynamic) {
  4.1009 +    if (group) {
  4.1010 +      GST_LOG ("Adding signals to element %s in group %p",
  4.1011 +          GST_ELEMENT_NAME (element), group);
  4.1012 +      GROUP_MUTEX_LOCK (group);
  4.1013 +      group->nbdynamic++;
  4.1014 +      GST_LOG ("Group %p has now %d dynamic elements", group, group->nbdynamic);
  4.1015 +      GROUP_MUTEX_UNLOCK (group);
  4.1016 +      g_signal_connect (G_OBJECT (element), "pad-added",
  4.1017 +          G_CALLBACK (pad_added_group_cb), group);
  4.1018 +      g_signal_connect (G_OBJECT (element), "pad-removed",
  4.1019 +          G_CALLBACK (pad_removed_group_cb), group);
  4.1020 +      g_signal_connect (G_OBJECT (element), "no-more-pads",
  4.1021 +          G_CALLBACK (no_more_pads_group_cb), group);
  4.1022 +    } else {
  4.1023 +      /* This is a non-grouped element, the handlers are different */
  4.1024 +      g_signal_connect (G_OBJECT (element), "pad-added",
  4.1025 +          G_CALLBACK (pad_added_cb), dbin);
  4.1026 +      g_signal_connect (G_OBJECT (element), "pad-removed",
  4.1027 +          G_CALLBACK (pad_removed_cb), dbin);
  4.1028 +      g_signal_connect (G_OBJECT (element), "no-more-pads",
  4.1029 +          G_CALLBACK (no_more_pads_cb), dbin);
  4.1030 +    }
  4.1031 +  }
  4.1032 +
  4.1033 +  /* 3. for every available pad, connect it */
  4.1034 +  for (pads = to_connect; pads; pads = g_list_next (pads)) {
  4.1035 +    GstPad *pad = GST_PAD_CAST (pads->data);
  4.1036 +    GstCaps *caps;
  4.1037 +
  4.1038 +    caps = gst_pad_get_caps (pad);
  4.1039 +    analyze_new_pad (dbin, element, pad, caps, group);
  4.1040 +    if (caps)
  4.1041 +      gst_caps_unref (caps);
  4.1042 +
  4.1043 +    gst_object_unref (pad);
  4.1044 +  }
  4.1045 +  g_list_free (to_connect);
  4.1046 +
  4.1047 +  return res;
  4.1048 +}
  4.1049 +
  4.1050 +/* expose_pad:
  4.1051 + *
  4.1052 + * Expose the given pad on the group as a decoded pad.
  4.1053 + * If group is NULL, a GstDecodeGroup will be created and setup properly.
  4.1054 + */
  4.1055 +static void
  4.1056 +expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
  4.1057 +    GstDecodeGroup * group)
  4.1058 +{
  4.1059 +  gboolean newgroup = FALSE;
  4.1060 +  gboolean isdemux;
  4.1061 +
  4.1062 +  GST_DEBUG_OBJECT (dbin, "pad %s:%s, group:%p",
  4.1063 +      GST_DEBUG_PAD_NAME (pad), group);
  4.1064 +
  4.1065 +  if (!group)
  4.1066 +    if (!(group = get_current_group (dbin))) {
  4.1067 +      group = gst_decode_group_new (dbin);
  4.1068 +      DECODE_BIN_LOCK (dbin);
  4.1069 +      dbin->groups = g_list_append (dbin->groups, group);
  4.1070 +      DECODE_BIN_UNLOCK (dbin);
  4.1071 +      newgroup = TRUE;
  4.1072 +    }
  4.1073 +
  4.1074 +  isdemux = is_demuxer_element (src);
  4.1075 +
  4.1076 +  if (isdemux || newgroup) {
  4.1077 +    GstPad *mqpad;
  4.1078 +
  4.1079 +    GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
  4.1080 +
  4.1081 +    if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
  4.1082 +      goto beach;
  4.1083 +    pad = mqpad;
  4.1084 +  }
  4.1085 +
  4.1086 +  gst_decode_group_control_source_pad (group, pad);
  4.1087 +
  4.1088 +  if (newgroup && !isdemux) {
  4.1089 +    /* If we have discovered a raw pad and it doesn't belong to any group,
  4.1090 +     * that means there wasn't any demuxer. In that case, we consider the
  4.1091 +     * group as being complete. */
  4.1092 +    gst_decode_group_set_complete (group);
  4.1093 +  }
  4.1094 +beach:
  4.1095 +  return;
  4.1096 +}
  4.1097 +
  4.1098 +static void
  4.1099 +type_found (GstElement * typefind, guint probability,
  4.1100 +    GstCaps * caps, GstDecodeBin * decode_bin)
  4.1101 +{
  4.1102 +  GstPad *pad;
  4.1103 +
  4.1104 +  GST_STATE_LOCK (decode_bin);
  4.1105 +
  4.1106 +  GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
  4.1107 +
  4.1108 +  pad = gst_element_get_pad (typefind, "src");
  4.1109 +
  4.1110 +  analyze_new_pad (decode_bin, typefind, pad, caps, NULL);
  4.1111 +
  4.1112 +  gst_object_unref (pad);
  4.1113 +
  4.1114 +  GST_STATE_UNLOCK (decode_bin);
  4.1115 +  return;
  4.1116 +}
  4.1117 +
  4.1118 +static void
  4.1119 +pad_added_group_cb (GstElement * element, GstPad * pad, GstDecodeGroup * group)
  4.1120 +{
  4.1121 +  GstCaps *caps;
  4.1122 +  gboolean expose = FALSE;
  4.1123 +
  4.1124 +  GST_LOG_OBJECT (pad, "pad added, group:%p", group);
  4.1125 +
  4.1126 +  caps = gst_pad_get_caps (pad);
  4.1127 +  analyze_new_pad (group->dbin, element, pad, caps, group);
  4.1128 +  if (caps)
  4.1129 +    gst_caps_unref (caps);
  4.1130 +
  4.1131 +  GROUP_MUTEX_LOCK (group);
  4.1132 +  group->nbdynamic--;
  4.1133 +  GST_LOG ("Group %p has now %d dynamic objects", group, group->nbdynamic);
  4.1134 +  if (group->nbdynamic == 0)
  4.1135 +    expose = TRUE;
  4.1136 +  GROUP_MUTEX_UNLOCK (group);
  4.1137 +  if (expose) {
  4.1138 +    GST_LOG
  4.1139 +        ("That was the last dynamic object, now attempting to expose the group");
  4.1140 +    DECODE_BIN_LOCK (group->dbin);
  4.1141 +    gst_decode_group_expose (group);
  4.1142 +    DECODE_BIN_UNLOCK (group->dbin);
  4.1143 +  }
  4.1144 +}
  4.1145 +
  4.1146 +static void
  4.1147 +pad_removed_group_cb (GstElement * element, GstPad * pad,
  4.1148 +    GstDecodeGroup * group)
  4.1149 +{
  4.1150 +  GST_LOG_OBJECT (pad, "pad removed, group:%p", group);
  4.1151 +
  4.1152 +  /* In fact, we don't have to do anything here, the active group will be
  4.1153 +   * removed when the group's multiqueue is drained */
  4.1154 +}
  4.1155 +
  4.1156 +static void
  4.1157 +no_more_pads_group_cb (GstElement * element, GstDecodeGroup * group)
  4.1158 +{
  4.1159 +  GST_LOG_OBJECT (element, "no more pads, setting group %p to complete", group);
  4.1160 +
  4.1161 +  /* FIXME : FILLME */
  4.1162 +  gst_decode_group_set_complete (group);
  4.1163 +}
  4.1164 +
  4.1165 +static void
  4.1166 +pad_added_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
  4.1167 +{
  4.1168 +  GstCaps *caps;
  4.1169 +
  4.1170 +  GST_LOG_OBJECT (pad, "Pad added to non-grouped element");
  4.1171 +
  4.1172 +  caps = gst_pad_get_caps (pad);
  4.1173 +  analyze_new_pad (dbin, element, pad, caps, NULL);
  4.1174 +  if (caps)
  4.1175 +    gst_caps_unref (caps);
  4.1176 +}
  4.1177 +
  4.1178 +static void
  4.1179 +pad_removed_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
  4.1180 +{
  4.1181 +  GST_LOG_OBJECT (pad, "Pad removed from non-grouped element");
  4.1182 +}
  4.1183 +
  4.1184 +static void
  4.1185 +no_more_pads_cb (GstElement * element, GstDecodeBin * dbin)
  4.1186 +{
  4.1187 +  GstDecodeGroup *group;
  4.1188 +
  4.1189 +  GST_LOG_OBJECT (element, "No more pads, setting current group to complete");
  4.1190 +
  4.1191 +  /* Find the non-complete group, there should only be one */
  4.1192 +  if (!(group = get_current_group (dbin)))
  4.1193 +    goto no_group;
  4.1194 +
  4.1195 +  gst_decode_group_set_complete (group);
  4.1196 +  return;
  4.1197 +
  4.1198 +no_group:
  4.1199 +  {
  4.1200 +    GST_WARNING_OBJECT (dbin, "We couldn't find a non-completed group !!");
  4.1201 +    return;
  4.1202 +  }
  4.1203 +}
  4.1204 +
  4.1205 +/* this function runs through the element factories and returns a list
  4.1206 + * of all elements that are able to sink the given caps 
  4.1207 + */
  4.1208 +static GList *
  4.1209 +find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
  4.1210 +{
  4.1211 +  GList *factories;
  4.1212 +  GList *to_try = NULL;
  4.1213 +
  4.1214 +  /* loop over all the factories */
  4.1215 +  for (factories = decode_bin->factories; factories;
  4.1216 +      factories = g_list_next (factories)) {
  4.1217 +    GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
  4.1218 +    const GList *templates;
  4.1219 +    GList *walk;
  4.1220 +
  4.1221 +    /* get the templates from the element factory */
  4.1222 +    templates = gst_element_factory_get_static_pad_templates (factory);
  4.1223 +    for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
  4.1224 +      GstStaticPadTemplate *templ = walk->data;
  4.1225 +
  4.1226 +      /* we only care about the sink templates */
  4.1227 +      if (templ->direction == GST_PAD_SINK) {
  4.1228 +        GstCaps *intersect;
  4.1229 +        GstCaps *tmpl_caps;
  4.1230 +
  4.1231 +        /* try to intersect the caps with the caps of the template */
  4.1232 +        tmpl_caps = gst_static_caps_get (&templ->static_caps);
  4.1233 +
  4.1234 +        intersect = gst_caps_intersect (caps, tmpl_caps);
  4.1235 +        gst_caps_unref (tmpl_caps);
  4.1236 +
  4.1237 +        /* check if the intersection is empty */
  4.1238 +        if (!gst_caps_is_empty (intersect)) {
  4.1239 +          /* non empty intersection, we can use this element */
  4.1240 +          to_try = g_list_prepend (to_try, factory);
  4.1241 +          gst_caps_unref (intersect);
  4.1242 +          break;
  4.1243 +        }
  4.1244 +        gst_caps_unref (intersect);
  4.1245 +      }
  4.1246 +    }
  4.1247 +  }
  4.1248 +  to_try = g_list_reverse (to_try);
  4.1249 +
  4.1250 +  return to_try;
  4.1251 +}
  4.1252 +
  4.1253 +/* Decide whether an element is a demuxer based on the 
  4.1254 + * klass and number/type of src pad templates it has */
  4.1255 +static gboolean
  4.1256 +is_demuxer_element (GstElement * srcelement)
  4.1257 +{
  4.1258 +  GstElementFactory *srcfactory;
  4.1259 +  GstElementClass *elemclass;
  4.1260 +  GList *templates, *walk;
  4.1261 +  const gchar *klass;
  4.1262 +  gint potential_src_pads = 0;
  4.1263 +
  4.1264 +  srcfactory = gst_element_get_factory (srcelement);
  4.1265 +  klass = gst_element_factory_get_klass (srcfactory);
  4.1266 +
  4.1267 +  /* Can't be a demuxer unless it has Demux in the klass name */
  4.1268 +  if (!strstr (klass, "Demux"))
  4.1269 +    return FALSE;
  4.1270 +
  4.1271 +  /* Walk the src pad templates and count how many the element
  4.1272 +   * might produce */
  4.1273 +  elemclass = GST_ELEMENT_GET_CLASS (srcelement);
  4.1274 +
  4.1275 +  walk = templates = gst_element_class_get_pad_template_list (elemclass);
  4.1276 +  while (walk != NULL) {
  4.1277 +    GstPadTemplate *templ;
  4.1278 +
  4.1279 +    templ = (GstPadTemplate *) walk->data;
  4.1280 +    if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) {
  4.1281 +      switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
  4.1282 +        case GST_PAD_ALWAYS:
  4.1283 +        case GST_PAD_SOMETIMES:
  4.1284 +          if (strstr (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "%"))
  4.1285 +            potential_src_pads += 2;    /* Might make multiple pads */
  4.1286 +          else
  4.1287 +            potential_src_pads += 1;
  4.1288 +          break;
  4.1289 +        case GST_PAD_REQUEST:
  4.1290 +          potential_src_pads += 2;
  4.1291 +          break;
  4.1292 +      }
  4.1293 +    }
  4.1294 +    walk = g_list_next (walk);
  4.1295 +  }
  4.1296 +
  4.1297 +  if (potential_src_pads < 2)
  4.1298 +    return FALSE;
  4.1299 +
  4.1300 +  return TRUE;
  4.1301 +}
  4.1302 +
  4.1303 +/* Returns TRUE if the caps are raw, or if they are compatible with the caps 
  4.1304 + * specified in the 'caps' property 
  4.1305 + * 
  4.1306 + * The decodebin_lock should be taken !
  4.1307 + */
  4.1308 +static gboolean
  4.1309 +are_raw_caps (GstDecodeBin * dbin, GstCaps * caps)
  4.1310 +{
  4.1311 +  GstCaps *intersection;
  4.1312 +  gboolean res;
  4.1313 +
  4.1314 +  GST_LOG_OBJECT (dbin, "Checking with caps %" GST_PTR_FORMAT, caps);
  4.1315 +
  4.1316 +  intersection = gst_caps_intersect (dbin->caps, caps);
  4.1317 +
  4.1318 +  res = (!(gst_caps_is_empty (intersection)));
  4.1319 +
  4.1320 +  gst_caps_unref (intersection);
  4.1321 +
  4.1322 +  GST_LOG_OBJECT (dbin, "Caps are %sfinal caps", res ? "" : "not ");
  4.1323 +
  4.1324 +  return res;
  4.1325 +}
  4.1326 +
  4.1327 +
  4.1328 +/****
  4.1329 + * GstDecodeGroup functions
  4.1330 + ****/
  4.1331 +
  4.1332 +static void
  4.1333 +multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group)
  4.1334 +{
  4.1335 +  GST_LOG_OBJECT (group->dbin, "multiqueue is full");
  4.1336 +
  4.1337 +  /* if we haven't exposed the group, do it */
  4.1338 +  DECODE_BIN_LOCK (group->dbin);
  4.1339 +  gst_decode_group_expose (group);
  4.1340 +  DECODE_BIN_UNLOCK (group->dbin);
  4.1341 +}
  4.1342 +
  4.1343 +static void
  4.1344 +multi_queue_underrun_cb (GstElement * queue, GstDecodeGroup * group)
  4.1345 +{
  4.1346 +  GstDecodeBin *dbin = group->dbin;
  4.1347 +
  4.1348 +  GST_LOG_OBJECT (dbin, "multiqueue is empty for group %p", group);
  4.1349 +
  4.1350 +  /* Check if we need to activate another group */
  4.1351 +  DECODE_BIN_LOCK (dbin);
  4.1352 +  if ((group == dbin->activegroup) && dbin->groups) {
  4.1353 +    GST_DEBUG_OBJECT (dbin, "Switching to new group");
  4.1354 +    /* unexpose current active */
  4.1355 +    gst_decode_group_hide (group);
  4.1356 +
  4.1357 +    /* expose first group of groups */
  4.1358 +    gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
  4.1359 +  }
  4.1360 +  DECODE_BIN_UNLOCK (dbin);
  4.1361 +}
  4.1362 +
  4.1363 +/* gst_decode_group_new
  4.1364 + *
  4.1365 + * Creates a new GstDecodeGroup. It is up to the caller to add it to the list
  4.1366 + * of groups.
  4.1367 + */
  4.1368 +static GstDecodeGroup *
  4.1369 +gst_decode_group_new (GstDecodeBin * dbin)
  4.1370 +{
  4.1371 +  GstDecodeGroup *group;
  4.1372 +  GstElement *mq;
  4.1373 +
  4.1374 +  GST_LOG_OBJECT (dbin, "Creating new group");
  4.1375 +
  4.1376 +  if (!(mq = gst_element_factory_make ("multiqueue", NULL))) {
  4.1377 +    GST_WARNING ("Couldn't create multiqueue element");
  4.1378 +    return NULL;
  4.1379 +  }
  4.1380 +
  4.1381 +  g_object_set (G_OBJECT (mq),
  4.1382 +      "max-size-bytes", 2 * 1024 * 1024,
  4.1383 +      "max-size-time", 5 * GST_SECOND, "max-size-buffers", 0, NULL);
  4.1384 +
  4.1385 +  group = g_new0 (GstDecodeGroup, 1);
  4.1386 +  group->lock = g_mutex_new ();
  4.1387 +  group->dbin = dbin;
  4.1388 +  group->multiqueue = mq;
  4.1389 +  group->exposed = FALSE;
  4.1390 +  group->drained = FALSE;
  4.1391 +  group->blocked = FALSE;
  4.1392 +  group->complete = FALSE;
  4.1393 +  group->endpads = NULL;
  4.1394 +
  4.1395 +  group->overrunsig = g_signal_connect (G_OBJECT (mq), "overrun",
  4.1396 +      G_CALLBACK (multi_queue_overrun_cb), group);
  4.1397 +  group->underrunsig = g_signal_connect (G_OBJECT (mq), "underrun",
  4.1398 +      G_CALLBACK (multi_queue_underrun_cb), group);
  4.1399 +
  4.1400 +  gst_bin_add (GST_BIN (dbin), group->multiqueue);
  4.1401 +  gst_element_set_state (group->multiqueue, GST_STATE_PAUSED);
  4.1402 +
  4.1403 +  GST_LOG_OBJECT (dbin, "Returning new group %p", group);
  4.1404 +
  4.1405 +  return group;
  4.1406 +}
  4.1407 +
  4.1408 +/** get_current_group:
  4.1409 + *
  4.1410 + * Returns the current non-completed group.
  4.1411 + *
  4.1412 + * Returns NULL if no groups are available, or all groups are completed.
  4.1413 + */
  4.1414 +static GstDecodeGroup *
  4.1415 +get_current_group (GstDecodeBin * dbin)
  4.1416 +{
  4.1417 +  GList *tmp;
  4.1418 +  GstDecodeGroup *group = NULL;
  4.1419 +
  4.1420 +  DECODE_BIN_LOCK (dbin);
  4.1421 +  for (tmp = dbin->groups; tmp; tmp = g_list_next (tmp)) {
  4.1422 +    GstDecodeGroup *this = (GstDecodeGroup *) tmp->data;
  4.1423 +
  4.1424 +    GST_LOG_OBJECT (dbin, "group %p, complete:%d", this, this->complete);
  4.1425 +
  4.1426 +    if (!this->complete) {
  4.1427 +      group = this;
  4.1428 +      break;
  4.1429 +    }
  4.1430 +  }
  4.1431 +  DECODE_BIN_UNLOCK (dbin);
  4.1432 +
  4.1433 +  GST_LOG_OBJECT (dbin, "Returning group %p", group);
  4.1434 +
  4.1435 +  return group;
  4.1436 +}
  4.1437 +
  4.1438 +static gboolean
  4.1439 +group_demuxer_event_probe (GstPad * pad, GstEvent * event,
  4.1440 +    GstDecodeGroup * group)
  4.1441 +{
  4.1442 +  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
  4.1443 +    GST_DEBUG_OBJECT (group->dbin,
  4.1444 +        "Got EOS on group input pads, exposing group if it wasn't before");
  4.1445 +    DECODE_BIN_LOCK (group->dbin);
  4.1446 +    gst_decode_group_expose (group);
  4.1447 +    DECODE_BIN_UNLOCK (group->dbin);
  4.1448 +  }
  4.1449 +  return TRUE;
  4.1450 +}
  4.1451 +
  4.1452 +/* gst_decode_group_control_demuxer_pad
  4.1453 + *
  4.1454 + * Adds a new demuxer srcpad to the given group.
  4.1455 + *
  4.1456 + * Returns the srcpad of the multiqueue corresponding the given pad.
  4.1457 + * Returns NULL if there was an error.
  4.1458 + */
  4.1459 +static GstPad *
  4.1460 +gst_decode_group_control_demuxer_pad (GstDecodeGroup * group, GstPad * pad)
  4.1461 +{
  4.1462 +  GstPad *srcpad, *sinkpad;
  4.1463 +  gchar *nb, *sinkname, *srcname;
  4.1464 +
  4.1465 +  GST_LOG ("group:%p pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
  4.1466 +
  4.1467 +  srcpad = NULL;
  4.1468 +
  4.1469 +  if (!(sinkpad = gst_element_get_pad (group->multiqueue, "sink%d"))) {
  4.1470 +    GST_ERROR ("Couldn't get sinkpad from multiqueue");
  4.1471 +    return NULL;
  4.1472 +  }
  4.1473 +
  4.1474 +  if ((gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
  4.1475 +    GST_ERROR ("Couldn't link demuxer and multiqueue");
  4.1476 +    goto beach;
  4.1477 +  }
  4.1478 +
  4.1479 +  sinkname = gst_pad_get_name (sinkpad);
  4.1480 +  nb = sinkname + 4;
  4.1481 +  srcname = g_strdup_printf ("src%s", nb);
  4.1482 +  g_free (sinkname);
  4.1483 +
  4.1484 +  GROUP_MUTEX_LOCK (group);
  4.1485 +
  4.1486 +  if (!(srcpad = gst_element_get_pad (group->multiqueue, srcname))) {
  4.1487 +    GST_ERROR ("Couldn't get srcpad %s from multiqueue", srcname);
  4.1488 +    goto chiringuito;
  4.1489 +  }
  4.1490 +
  4.1491 +  /* connect event handler on pad to intercept EOS events */
  4.1492 +  gst_pad_add_event_probe (pad, G_CALLBACK (group_demuxer_event_probe), group);
  4.1493 +
  4.1494 +chiringuito:
  4.1495 +  g_free (srcname);
  4.1496 +  GROUP_MUTEX_UNLOCK (group);
  4.1497 +
  4.1498 +beach:
  4.1499 +  gst_object_unref (sinkpad);
  4.1500 +  return srcpad;
  4.1501 +}
  4.1502 +
  4.1503 +static gboolean
  4.1504 +gst_decode_group_control_source_pad (GstDecodeGroup * group, GstPad * pad)
  4.1505 +{
  4.1506 +  GstDecodePad *dpad;
  4.1507 +
  4.1508 +  g_return_val_if_fail (group != NULL, FALSE);
  4.1509 +
  4.1510 +  GST_LOG ("group:%p , pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
  4.1511 +
  4.1512 +  /* FIXME : check if pad is already controlled */
  4.1513 +
  4.1514 +  GROUP_MUTEX_LOCK (group);
  4.1515 +
  4.1516 +  /* Create GstDecodePad for the pad */
  4.1517 +  dpad = gst_decode_pad_new (group, pad, TRUE);
  4.1518 +
  4.1519 +  group->endpads = g_list_append (group->endpads, dpad);
  4.1520 +
  4.1521 +  GROUP_MUTEX_UNLOCK (group);
  4.1522 +
  4.1523 +  return TRUE;
  4.1524 +}
  4.1525 +
  4.1526 +/* gst_decode_group_check_if_blocked:
  4.1527 + *
  4.1528 + * Call this when one of the pads blocked status has changed.
  4.1529 + * If the group is complete and blocked, the group will be marked as blocked
  4.1530 + * and will ghost/expose all pads on decodebin if the group is the current one.
  4.1531 + *
  4.1532 + * Call with the group lock taken ! MT safe
  4.1533 + */
  4.1534 +static void
  4.1535 +gst_decode_group_check_if_blocked (GstDecodeGroup * group)
  4.1536 +{
  4.1537 +  GList *tmp;
  4.1538 +  gboolean blocked = TRUE;
  4.1539 +
  4.1540 +  GST_LOG ("group : %p , ->complete:%d , ->nbdynamic:%d",
  4.1541 +      group, group->complete, group->nbdynamic);
  4.1542 +
  4.1543 +  /* 1. don't do anything if group is not complete */
  4.1544 +  if (!group->complete || group->nbdynamic) {
  4.1545 +    GST_DEBUG_OBJECT (group->dbin, "Group isn't complete yet");
  4.1546 +    return;
  4.1547 +  }
  4.1548 +
  4.1549 +  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
  4.1550 +    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
  4.1551 +
  4.1552 +    if (!dpad->blocked) {
  4.1553 +      blocked = FALSE;
  4.1554 +      break;
  4.1555 +    }
  4.1556 +  }
  4.1557 +
  4.1558 +  /* 2. Update status of group */
  4.1559 +  group->blocked = blocked;
  4.1560 +  GST_LOG ("group is blocked:%d", blocked);
  4.1561 +
  4.1562 +  /* 3. don't do anything if not blocked completely */
  4.1563 +  if (!blocked)
  4.1564 +    return;
  4.1565 +
  4.1566 +  /* 4. if we're the current group, expose pads */
  4.1567 +  DECODE_BIN_LOCK (group->dbin);
  4.1568 +  if (!gst_decode_group_expose (group))
  4.1569 +    GST_WARNING_OBJECT (group->dbin, "Couldn't expose group");
  4.1570 +  DECODE_BIN_UNLOCK (group->dbin);
  4.1571 +}
  4.1572 +
  4.1573 +static void
  4.1574 +gst_decode_group_check_if_drained (GstDecodeGroup * group)
  4.1575 +{
  4.1576 +  GList *tmp;
  4.1577 +  GstDecodeBin *dbin = group->dbin;
  4.1578 +  gboolean drained = TRUE;
  4.1579 +
  4.1580 +  GST_LOG ("group : %p", group);
  4.1581 +
  4.1582 +  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
  4.1583 +    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
  4.1584 +
  4.1585 +    GST_LOG ("testing dpad %p", dpad);
  4.1586 +
  4.1587 +    if (!dpad->drained) {
  4.1588 +      drained = FALSE;
  4.1589 +      break;
  4.1590 +    }
  4.1591 +  }
  4.1592 +
  4.1593 +  group->drained = drained;
  4.1594 +  GST_LOG ("group is drained");
  4.1595 +
  4.1596 +  if (!drained)
  4.1597 +    return;
  4.1598 +
  4.1599 +  DECODE_BIN_LOCK (dbin);
  4.1600 +  if ((group == dbin->activegroup) && dbin->groups) {
  4.1601 +    GST_DEBUG_OBJECT (dbin, "Switching to new group");
  4.1602 +
  4.1603 +    gst_decode_group_hide (group);
  4.1604 +
  4.1605 +    gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
  4.1606 +  }
  4.1607 +  DECODE_BIN_UNLOCK (dbin);
  4.1608 +}
  4.1609 +
  4.1610 +/* sort_end_pads:
  4.1611 + * GCompareFunc to use with lists of GstPad.
  4.1612 + * Sorts pads by mime type.
  4.1613 + * First video (raw, then non-raw), then audio (raw, then non-raw),
  4.1614 + * then others.
  4.1615 + *
  4.1616 + * Return: negative if a<b, 0 if a==b, positive if a>b
  4.1617 + */
  4.1618 +
  4.1619 +static gint
  4.1620 +sort_end_pads (GstDecodePad * da, GstDecodePad * db)
  4.1621 +{
  4.1622 +  GstPad *a, *b;
  4.1623 +  gint va, vb;
  4.1624 +  GstCaps *capsa, *capsb;
  4.1625 +  GstStructure *sa, *sb;
  4.1626 +  const gchar *namea, *nameb;
  4.1627 +
  4.1628 +  a = da->pad;
  4.1629 +  b = db->pad;
  4.1630 +
  4.1631 +  capsa = gst_pad_get_caps (a);
  4.1632 +  capsb = gst_pad_get_caps (b);
  4.1633 +
  4.1634 +  sa = gst_caps_get_structure ((const GstCaps *) capsa, 0);
  4.1635 +  sb = gst_caps_get_structure ((const GstCaps *) capsb, 0);
  4.1636 +
  4.1637 +  namea = gst_structure_get_name (sa);
  4.1638 +  nameb = gst_structure_get_name (sb);
  4.1639 +
  4.1640 +  if (g_strrstr (namea, "video/x-raw-"))
  4.1641 +    va = 0;
  4.1642 +  else if (g_strrstr (namea, "video/"))
  4.1643 +    va = 1;
  4.1644 +  else if (g_strrstr (namea, "audio/x-raw"))
  4.1645 +    va = 2;
  4.1646 +  else if (g_strrstr (namea, "audio/"))
  4.1647 +    va = 3;
  4.1648 +  else
  4.1649 +    va = 4;
  4.1650 +
  4.1651 +  if (g_strrstr (nameb, "video/x-raw-"))
  4.1652 +    vb = 0;
  4.1653 +  else if (g_strrstr (nameb, "video/"))
  4.1654 +    vb = 1;
  4.1655 +  else if (g_strrstr (nameb, "audio/x-raw"))
  4.1656 +    vb = 2;
  4.1657 +  else if (g_strrstr (nameb, "audio/"))
  4.1658 +    vb = 3;
  4.1659 +  else
  4.1660 +    vb = 4;
  4.1661 +
  4.1662 +  gst_caps_unref (capsa);
  4.1663 +  gst_caps_unref (capsb);
  4.1664 +
  4.1665 +  return va - vb;
  4.1666 +}
  4.1667 +
  4.1668 +/* gst_decode_group_expose:
  4.1669 + *
  4.1670 + * Expose this group's pads.
  4.1671 + *
  4.1672 + * Not MT safe, please take the group lock
  4.1673 + */
  4.1674 +
  4.1675 +static gboolean
  4.1676 +gst_decode_group_expose (GstDecodeGroup * group)
  4.1677 +{
  4.1678 +  GList *tmp;
  4.1679 +  GList *next = NULL;
  4.1680 +
  4.1681 +  if (group->dbin->activegroup) {
  4.1682 +    GST_DEBUG_OBJECT (group->dbin, "A group is already active and exposed");
  4.1683 +    return TRUE;
  4.1684 +  }
  4.1685 +
  4.1686 +  if (group->dbin->activegroup == group) {
  4.1687 +    GST_WARNING ("Group %p is already exposed", group);
  4.1688 +    return TRUE;
  4.1689 +  }
  4.1690 +
  4.1691 +  if (!group->dbin->groups
  4.1692 +      || (group != (GstDecodeGroup *) group->dbin->groups->data)) {
  4.1693 +    GST_WARNING ("Group %p is not the first group to expose", group);
  4.1694 +    return FALSE;
  4.1695 +  }
  4.1696 +
  4.1697 +  if (group->nbdynamic) {
  4.1698 +    GST_WARNING ("Group %p still has %d dynamic objects, not exposing yet",
  4.1699 +        group, group->nbdynamic);
  4.1700 +    return FALSE;
  4.1701 +  }
  4.1702 +
  4.1703 +  GST_LOG ("Exposing group %p", group);
  4.1704 +
  4.1705 +  /* re-order pads : video, then audio, then others */
  4.1706 +  group->endpads = g_list_sort (group->endpads, (GCompareFunc) sort_end_pads);
  4.1707 +
  4.1708 +  /* Expose pads */
  4.1709 +
  4.1710 +  for (tmp = group->endpads; tmp; tmp = next) {
  4.1711 +    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
  4.1712 +    gchar *padname;
  4.1713 +    GstPad *ghost;
  4.1714 +
  4.1715 +    next = g_list_next (tmp);
  4.1716 +
  4.1717 +    /* 1. ghost pad */
  4.1718 +    padname = g_strdup_printf ("src%d", group->dbin->nbpads);
  4.1719 +    group->dbin->nbpads++;
  4.1720 +
  4.1721 +    GST_LOG_OBJECT (group->dbin, "About to expose pad %s:%s",
  4.1722 +        GST_DEBUG_PAD_NAME (dpad->pad));
  4.1723 +
  4.1724 +    ghost = gst_ghost_pad_new (padname, dpad->pad);
  4.1725 +    gst_pad_set_active (ghost, TRUE);
  4.1726 +    gst_element_add_pad (GST_ELEMENT (group->dbin), ghost);
  4.1727 +    group->ghosts = g_list_append (group->ghosts, ghost);
  4.1728 +
  4.1729 +    g_free (padname);
  4.1730 +
  4.1731 +    /* 2. emit signal */
  4.1732 +    GST_DEBUG_OBJECT (group->dbin, "emitting new-decoded-pad");
  4.1733 +    g_signal_emit (G_OBJECT (group->dbin),
  4.1734 +        gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost,
  4.1735 +        (next == NULL));
  4.1736 +    GST_DEBUG_OBJECT (group->dbin, "emitted new-decoded-pad");
  4.1737 +
  4.1738 +    /* 3. Unblock internal  pad */
  4.1739 +    GST_DEBUG_OBJECT (dpad->pad, "unblocking");
  4.1740 +    gst_pad_set_blocked_async (dpad->pad, FALSE,
  4.1741 +        (GstPadBlockCallback) source_pad_blocked_cb, dpad);
  4.1742 +    GST_DEBUG_OBJECT (dpad->pad, "unblocked");
  4.1743 +
  4.1744 +  }
  4.1745 +
  4.1746 +  group->dbin->activegroup = group;
  4.1747 +
  4.1748 +  /* pop off the first group */
  4.1749 +  group->dbin->groups =
  4.1750 +      g_list_delete_link (group->dbin->groups, group->dbin->groups);
  4.1751 +
  4.1752 +  remove_fakesink (group->dbin);
  4.1753 +
  4.1754 +  group->exposed = TRUE;
  4.1755 +
  4.1756 +  GST_LOG_OBJECT (group->dbin, "signalling no-more-pads");
  4.1757 +  gst_element_no_more_pads (GST_ELEMENT (group->dbin));
  4.1758 +
  4.1759 +  GST_LOG_OBJECT (group->dbin, "Group %p exposed", group);
  4.1760 +  return TRUE;
  4.1761 +}
  4.1762 +
  4.1763 +static void
  4.1764 +gst_decode_group_hide (GstDecodeGroup * group)
  4.1765 +{
  4.1766 +  GList *tmp;
  4.1767 +
  4.1768 +  GST_LOG ("Hiding group %p", group);
  4.1769 +
  4.1770 +  if (group != group->dbin->activegroup) {
  4.1771 +    GST_WARNING ("This group is not the active one, aborting");
  4.1772 +    return;
  4.1773 +  }
  4.1774 +
  4.1775 +  GROUP_MUTEX_LOCK (group);
  4.1776 +
  4.1777 +  /* Remove ghost pads */
  4.1778 +  for (tmp = group->ghosts; tmp; tmp = g_list_next (tmp))
  4.1779 +    gst_element_remove_pad (GST_ELEMENT (group->dbin), (GstPad *) tmp->data);
  4.1780 +
  4.1781 +  g_list_free (group->ghosts);
  4.1782 +  group->ghosts = NULL;
  4.1783 +
  4.1784 +  group->exposed = FALSE;
  4.1785 +
  4.1786 +  GROUP_MUTEX_UNLOCK (group);
  4.1787 +
  4.1788 +  group->dbin->activegroup = NULL;
  4.1789 +  group->dbin->oldgroups = g_list_append (group->dbin->oldgroups, group);
  4.1790 +}
  4.1791 +
  4.1792 +static void
  4.1793 +deactivate_free_recursive (GstDecodeGroup * group, GstElement * element)
  4.1794 +{
  4.1795 +  GstIterator *it;
  4.1796 +  GstIteratorResult res;
  4.1797 +  gpointer point;
  4.1798 +
  4.1799 +  GST_LOG ("element:%s", GST_ELEMENT_NAME (element));
  4.1800 +
  4.1801 +  /* call on downstream elements */
  4.1802 +  it = gst_element_iterate_src_pads (element);
  4.1803 +
  4.1804 +restart:
  4.1805 +
  4.1806 +  while (1) {
  4.1807 +    res = gst_iterator_next (it, &point);
  4.1808 +    switch (res) {
  4.1809 +      case GST_ITERATOR_DONE:
  4.1810 +        goto done;
  4.1811 +      case GST_ITERATOR_RESYNC:
  4.1812 +        gst_iterator_resync (it);
  4.1813 +        goto restart;
  4.1814 +      case GST_ITERATOR_ERROR:
  4.1815 +      {
  4.1816 +        GST_WARNING ("Had an error while iterating source pads of element: %s",
  4.1817 +            GST_ELEMENT_NAME (element));
  4.1818 +        goto beach;
  4.1819 +      }
  4.1820 +      case GST_ITERATOR_OK:
  4.1821 +      {
  4.1822 +        GstPad *pad = GST_PAD (point);
  4.1823 +        GstPad *peerpad = NULL;
  4.1824 +
  4.1825 +        if ((peerpad = gst_pad_get_peer (pad))) {
  4.1826 +          GstObject *parent = gst_pad_get_parent (peerpad);
  4.1827 +
  4.1828 +          if (parent && GST_IS_ELEMENT (parent))
  4.1829 +            deactivate_free_recursive (group, GST_ELEMENT (parent));
  4.1830 +          if (parent)
  4.1831 +            gst_object_unref (parent);
  4.1832 +        }
  4.1833 +      }
  4.1834 +        break;
  4.1835 +      default:
  4.1836 +        break;
  4.1837 +    }
  4.1838 +  }
  4.1839 +
  4.1840 +done:
  4.1841 +  gst_element_set_state (element, GST_STATE_NULL);
  4.1842 +  gst_bin_remove (GST_BIN (group->dbin), element);
  4.1843 +
  4.1844 +beach:
  4.1845 +  gst_iterator_free (it);
  4.1846 +
  4.1847 +  return;
  4.1848 +}
  4.1849 +
  4.1850 +static void
  4.1851 +gst_decode_group_free (GstDecodeGroup * group)
  4.1852 +{
  4.1853 +  GList *tmp;
  4.1854 +
  4.1855 +  GST_LOG ("group %p", group);
  4.1856 +
  4.1857 +  GROUP_MUTEX_LOCK (group);
  4.1858 +  /* Clear all GstDecodePad */
  4.1859 +  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
  4.1860 +    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
  4.1861 +
  4.1862 +    g_free (dpad);
  4.1863 +  }
  4.1864 +  g_list_free (group->endpads);
  4.1865 +  group->endpads = NULL;
  4.1866 +
  4.1867 +  /* disconnect signal handlers on multiqueue */
  4.1868 +  g_signal_handler_disconnect (group->multiqueue, group->underrunsig);
  4.1869 +  g_signal_handler_disconnect (group->multiqueue, group->overrunsig);
  4.1870 +
  4.1871 +  /* remove all elements */
  4.1872 +  deactivate_free_recursive (group, group->multiqueue);
  4.1873 +
  4.1874 +  GROUP_MUTEX_UNLOCK (group);
  4.1875 +
  4.1876 +  g_mutex_free (group->lock);
  4.1877 +  g_free (group);
  4.1878 +}
  4.1879 +
  4.1880 +/* gst_decode_group_set_complete:
  4.1881 + *
  4.1882 + * Mark the group as complete. This means no more streams will be controlled
  4.1883 + * through this group.
  4.1884 + *
  4.1885 + * MT safe
  4.1886 + */
  4.1887 +static void
  4.1888 +gst_decode_group_set_complete (GstDecodeGroup * group)
  4.1889 +{
  4.1890 +  GST_LOG_OBJECT (group->dbin, "Setting group %p to COMPLETE", group);
  4.1891 +
  4.1892 +  GROUP_MUTEX_LOCK (group);
  4.1893 +  group->complete = TRUE;
  4.1894 +  gst_decode_group_check_if_blocked (group);
  4.1895 +  GROUP_MUTEX_UNLOCK (group);
  4.1896 +}
  4.1897 +
  4.1898 +
  4.1899 +
  4.1900 +/*************************
  4.1901 + * GstDecodePad functions
  4.1902 + *************************/
  4.1903 +
  4.1904 +static void
  4.1905 +source_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodePad * dpad)
  4.1906 +{
  4.1907 +  GST_LOG_OBJECT (pad, "blocked:%d , dpad:%p, dpad->group:%p",
  4.1908 +      blocked, dpad, dpad->group);
  4.1909 +
  4.1910 +  /* Update this GstDecodePad status */
  4.1911 +  dpad->blocked = blocked;
  4.1912 +
  4.1913 +  if (blocked) {
  4.1914 +    GROUP_MUTEX_LOCK (dpad->group);
  4.1915 +    gst_decode_group_check_if_blocked (dpad->group);
  4.1916 +    GROUP_MUTEX_UNLOCK (dpad->group);
  4.1917 +  }
  4.1918 +}
  4.1919 +
  4.1920 +static gboolean
  4.1921 +source_pad_event_probe (GstPad * pad, GstEvent * event, GstDecodePad * dpad)
  4.1922 +{
  4.1923 +  GST_LOG_OBJECT (pad, "%s dpad:%p", GST_EVENT_TYPE_NAME (event), dpad);
  4.1924 +
  4.1925 +  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
  4.1926 +    /* Set our pad as drained */
  4.1927 +    dpad->drained = TRUE;
  4.1928 +
  4.1929 +    /* Check if all pads are drained */
  4.1930 +    gst_decode_group_check_if_drained (dpad->group);
  4.1931 +  }
  4.1932 +
  4.1933 +  return TRUE;
  4.1934 +}
  4.1935 +
  4.1936 +/*gst_decode_pad_new:
  4.1937 + *
  4.1938 + * Creates a new GstDecodePad for the given pad.
  4.1939 + * If block is TRUE, Sets the pad blocking asynchronously
  4.1940 + */
  4.1941 +
  4.1942 +static GstDecodePad *
  4.1943 +gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad, gboolean block)
  4.1944 +{
  4.1945 +  GstDecodePad *dpad;
  4.1946 +
  4.1947 +  dpad = g_new0 (GstDecodePad, 1);
  4.1948 +  dpad->pad = pad;
  4.1949 +  dpad->group = group;
  4.1950 +  dpad->blocked = FALSE;
  4.1951 +  dpad->drained = TRUE;
  4.1952 +
  4.1953 +  if (block)
  4.1954 +    gst_pad_set_blocked_async (pad, TRUE,
  4.1955 +        (GstPadBlockCallback) source_pad_blocked_cb, dpad);
  4.1956 +  gst_pad_add_event_probe (pad, G_CALLBACK (source_pad_event_probe), dpad);
  4.1957 +  return dpad;
  4.1958 +}
  4.1959 +
  4.1960 +
  4.1961 +/*****
  4.1962 + * Element add/remove
  4.1963 + *****/
  4.1964 +
  4.1965 +/*
  4.1966 + * add_fakesink / remove_fakesink
  4.1967 + *
  4.1968 + * We use a sink so that the parent ::change_state returns GST_STATE_CHANGE_ASYNC
  4.1969 + * when that sink is present (since it's not connected to anything it will 
  4.1970 + * always return GST_STATE_CHANGE_ASYNC).
  4.1971 + *
  4.1972 + * But this is an ugly way of achieving this goal.
  4.1973 + * Ideally, we shouldn't use a sink and just return GST_STATE_CHANGE_ASYNC in
  4.1974 + * our ::change_state if we have not exposed the active group.
  4.1975 + * We also need to override ::get_state to fake the asynchronous behaviour.
  4.1976 + * Once the active group is exposed, we would then post a
  4.1977 + * GST_MESSAGE_STATE_DIRTY and return GST_STATE_CHANGE_SUCCESS (which will call
  4.1978 + * ::get_state .
  4.1979 + */
  4.1980 +
  4.1981 +static gboolean
  4.1982 +add_fakesink (GstDecodeBin * decode_bin)
  4.1983 +{
  4.1984 +  GST_DEBUG_OBJECT (decode_bin, "Adding the fakesink");
  4.1985 +
  4.1986 +  if (decode_bin->fakesink)
  4.1987 +    return TRUE;
  4.1988 +
  4.1989 +  decode_bin->fakesink =
  4.1990 +      gst_element_factory_make ("fakesink", "async-fakesink");
  4.1991 +  if (!decode_bin->fakesink)
  4.1992 +    goto no_fakesink;
  4.1993 +
  4.1994 +  /* hacky, remove sink flag, we don't want our decodebin to become a sink
  4.1995 +   * just because we add a fakesink element to make us ASYNC */
  4.1996 +  GST_OBJECT_FLAG_UNSET (decode_bin->fakesink, GST_ELEMENT_IS_SINK);
  4.1997 +
  4.1998 +  if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->fakesink))
  4.1999 +    goto could_not_add;
  4.2000 +
  4.2001 +  return TRUE;
  4.2002 +
  4.2003 +  /* ERRORS */
  4.2004 +no_fakesink:
  4.2005 +  {
  4.2006 +    g_warning ("can't find fakesink element, decodebin will not work");
  4.2007 +    return FALSE;
  4.2008 +  }
  4.2009 +could_not_add:
  4.2010 +  {
  4.2011 +    g_warning ("Could not add fakesink to decodebin, decodebin will not work");
  4.2012 +    gst_object_unref (decode_bin->fakesink);
  4.2013 +    decode_bin->fakesink = NULL;
  4.2014 +    return FALSE;
  4.2015 +  }
  4.2016 +}
  4.2017 +
  4.2018 +static void
  4.2019 +remove_fakesink (GstDecodeBin * decode_bin)
  4.2020 +{
  4.2021 +  if (decode_bin->fakesink == NULL)
  4.2022 +    return;
  4.2023 +
  4.2024 +  GST_DEBUG_OBJECT (decode_bin, "Removing the fakesink");
  4.2025 +
  4.2026 +  gst_element_set_state (decode_bin->fakesink, GST_STATE_NULL);
  4.2027 +  gst_bin_remove (GST_BIN (decode_bin), decode_bin->fakesink);
  4.2028 +  decode_bin->fakesink = NULL;
  4.2029 +
  4.2030 +  gst_element_post_message (GST_ELEMENT_CAST (decode_bin),
  4.2031 +      gst_message_new_state_dirty (GST_OBJECT_CAST (decode_bin)));
  4.2032 +}
  4.2033 +
  4.2034 +/*****
  4.2035 + * convenience functions
  4.2036 + *****/
  4.2037 +
  4.2038 +/* find_sink_pad
  4.2039 + *
  4.2040 + * Returns the first sink pad of the given element, or NULL if it doesn't have
  4.2041 + * any.
  4.2042 + */
  4.2043 +
  4.2044 +static GstPad *
  4.2045 +find_sink_pad (GstElement * element)
  4.2046 +{
  4.2047 +  GstIterator *it;
  4.2048 +  GstPad *pad = NULL;
  4.2049 +  gpointer point;
  4.2050 +
  4.2051 +  it = gst_element_iterate_sink_pads (element);
  4.2052 +
  4.2053 +  if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
  4.2054 +    pad = (GstPad *) point;
  4.2055 +
  4.2056 +  gst_iterator_free (it);
  4.2057 +
  4.2058 +  return pad;
  4.2059 +}
  4.2060 +
  4.2061 +static GstStateChangeReturn
  4.2062 +gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
  4.2063 +{
  4.2064 +  GstStateChangeReturn ret;
  4.2065 +  GstDecodeBin *dbin = GST_DECODE_BIN (element);
  4.2066 +
  4.2067 +  switch (transition) {
  4.2068 +    case GST_STATE_CHANGE_NULL_TO_READY:
  4.2069 +      if (dbin->typefind == NULL)
  4.2070 +        goto missing_typefind;
  4.2071 +      break;
  4.2072 +    case GST_STATE_CHANGE_READY_TO_PAUSED:{
  4.2073 +      if (!add_fakesink (dbin))
  4.2074 +        goto missing_fakesink;
  4.2075 +      break;
  4.2076 +    }
  4.2077 +    default:
  4.2078 +      break;
  4.2079 +  }
  4.2080 +
  4.2081 +  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  4.2082 +
  4.2083 +  /* FIXME : put some cleanup functions here.. if needed */
  4.2084 +
  4.2085 +  return ret;
  4.2086 +
  4.2087 +/* ERRORS */
  4.2088 +missing_typefind:
  4.2089 +  {
  4.2090 +    GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no typefind!"));
  4.2091 +    return GST_STATE_CHANGE_FAILURE;
  4.2092 +  }
  4.2093 +missing_fakesink:
  4.2094 +  {
  4.2095 +    GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no fakesink!"));
  4.2096 +    return GST_STATE_CHANGE_FAILURE;
  4.2097 +  }
  4.2098 +}
  4.2099 +
  4.2100 +static gboolean
  4.2101 +plugin_init (GstPlugin * plugin)
  4.2102 +{
  4.2103 +  GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0,
  4.2104 +      "decoder bin");
  4.2105 +
  4.2106 +  return gst_element_register (plugin, "decodebin2", GST_RANK_NONE,
  4.2107 +      GST_TYPE_DECODE_BIN);
  4.2108 +}
  4.2109 +
  4.2110 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
  4.2111 +    GST_VERSION_MINOR,
  4.2112 +    "decodebin2",
  4.2113 +    "decoder bin newer version", plugin_init, VERSION, GST_LICENSE,
  4.2114 +    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/gst-gmyth/decodebin2/gstplay-marshal.c	Sat Jul 14 17:20:54 2007 +0100
     5.3 @@ -0,0 +1,167 @@
     5.4 +#include "gstplay-marshal.h"
     5.5 +
     5.6 +#include	<glib-object.h>
     5.7 +
     5.8 +
     5.9 +#ifdef G_ENABLE_DEBUG
    5.10 +#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
    5.11 +#define g_marshal_value_peek_char(v)     g_value_get_char (v)
    5.12 +#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
    5.13 +#define g_marshal_value_peek_int(v)      g_value_get_int (v)
    5.14 +#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
    5.15 +#define g_marshal_value_peek_long(v)     g_value_get_long (v)
    5.16 +#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
    5.17 +#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
    5.18 +#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
    5.19 +#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
    5.20 +#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
    5.21 +#define g_marshal_value_peek_float(v)    g_value_get_float (v)
    5.22 +#define g_marshal_value_peek_double(v)   g_value_get_double (v)
    5.23 +#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
    5.24 +#define g_marshal_value_peek_param(v)    g_value_get_param (v)
    5.25 +#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
    5.26 +#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
    5.27 +#define g_marshal_value_peek_object(v)   g_value_get_object (v)
    5.28 +#else /* !G_ENABLE_DEBUG */
    5.29 +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
    5.30 + *          Do not access GValues directly in your code. Instead, use the
    5.31 + *          g_value_get_*() functions
    5.32 + */
    5.33 +#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
    5.34 +#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
    5.35 +#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
    5.36 +#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
    5.37 +#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
    5.38 +#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
    5.39 +#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
    5.40 +#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
    5.41 +#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
    5.42 +#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
    5.43 +#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
    5.44 +#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
    5.45 +#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
    5.46 +#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
    5.47 +#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
    5.48 +#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
    5.49 +#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
    5.50 +#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
    5.51 +#endif /* !G_ENABLE_DEBUG */
    5.52 +
    5.53 +
    5.54 +/* BOOLEAN:OBJECT (gstplay-marshal.list:1) */
    5.55 +void
    5.56 +gst_play_marshal_BOOLEAN__OBJECT (GClosure     *closure,
    5.57 +                                  GValue       *return_value,
    5.58 +                                  guint         n_param_values,
    5.59 +                                  const GValue *param_values,
    5.60 +                                  gpointer      invocation_hint,
    5.61 +                                  gpointer      marshal_data)
    5.62 +{
    5.63 +  typedef gboolean (*GMarshalFunc_BOOLEAN__OBJECT) (gpointer     data1,
    5.64 +                                                    gpointer     arg_1,
    5.65 +                                                    gpointer     data2);
    5.66 +  register GMarshalFunc_BOOLEAN__OBJECT callback;
    5.67 +  register GCClosure *cc = (GCClosure*) closure;
    5.68 +  register gpointer data1, data2;
    5.69 +  gboolean v_return;
    5.70 +
    5.71 +  g_return_if_fail (return_value != NULL);
    5.72 +  g_return_if_fail (n_param_values == 2);
    5.73 +
    5.74 +  if (G_CCLOSURE_SWAP_DATA (closure))
    5.75 +    {
    5.76 +      data1 = closure->data;
    5.77 +      data2 = g_value_peek_pointer (param_values + 0);
    5.78 +    }
    5.79 +  else
    5.80 +    {
    5.81 +      data1 = g_value_peek_pointer (param_values + 0);
    5.82 +      data2 = closure->data;
    5.83 +    }
    5.84 +  callback = (GMarshalFunc_BOOLEAN__OBJECT) (marshal_data ? marshal_data : cc->callback);
    5.85 +
    5.86 +  v_return = callback (data1,
    5.87 +                       g_marshal_value_peek_object (param_values + 1),
    5.88 +                       data2);
    5.89 +
    5.90 +  g_value_set_boolean (return_value, v_return);
    5.91 +}
    5.92 +
    5.93 +/* VOID:OBJECT,BOOLEAN (gstplay-marshal.list:2) */
    5.94 +void
    5.95 +gst_play_marshal_VOID__OBJECT_BOOLEAN (GClosure     *closure,
    5.96 +                                       GValue       *return_value,
    5.97 +                                       guint         n_param_values,
    5.98 +                                       const GValue *param_values,
    5.99 +                                       gpointer      invocation_hint,
   5.100 +                                       gpointer      marshal_data)
   5.101 +{
   5.102 +  typedef void (*GMarshalFunc_VOID__OBJECT_BOOLEAN) (gpointer     data1,
   5.103 +                                                     gpointer     arg_1,
   5.104 +                                                     gboolean     arg_2,
   5.105 +                                                     gpointer     data2);
   5.106 +  register GMarshalFunc_VOID__OBJECT_BOOLEAN callback;
   5.107 +  register GCClosure *cc = (GCClosure*) closure;
   5.108 +  register gpointer data1, data2;
   5.109 +
   5.110 +  g_return_if_fail (n_param_values == 3);
   5.111 +
   5.112 +  if (G_CCLOSURE_SWAP_DATA (closure))
   5.113 +    {
   5.114 +      data1 = closure->data;
   5.115 +      data2 = g_value_peek_pointer (param_values + 0);
   5.116 +    }
   5.117 +  else
   5.118 +    {
   5.119 +      data1 = g_value_peek_pointer (param_values + 0);
   5.120 +      data2 = closure->data;
   5.121 +    }
   5.122 +  callback = (GMarshalFunc_VOID__OBJECT_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
   5.123 +
   5.124 +  callback (data1,
   5.125 +            g_marshal_value_peek_object (param_values + 1),
   5.126 +            g_marshal_value_peek_boolean (param_values + 2),
   5.127 +            data2);
   5.128 +}
   5.129 +
   5.130 +/* BOOLEAN:OBJECT,POINTER (gstplay-marshal.list:3) */
   5.131 +void
   5.132 +gst_play_marshal_BOOLEAN__OBJECT_POINTER (GClosure     *closure,
   5.133 +                                          GValue       *return_value,
   5.134 +                                          guint         n_param_values,
   5.135 +                                          const GValue *param_values,
   5.136 +                                          gpointer      invocation_hint,
   5.137 +                                          gpointer      marshal_data)
   5.138 +{
   5.139 +  typedef gboolean (*GMarshalFunc_BOOLEAN__OBJECT_POINTER) (gpointer     data1,
   5.140 +                                                            gpointer     arg_1,
   5.141 +                                                            gpointer     arg_2,
   5.142 +                                                            gpointer     data2);
   5.143 +  register GMarshalFunc_BOOLEAN__OBJECT_POINTER callback;
   5.144 +  register GCClosure *cc = (GCClosure*) closure;
   5.145 +  register gpointer data1, data2;
   5.146 +  gboolean v_return;
   5.147 +
   5.148 +  g_return_if_fail (return_value != NULL);
   5.149 +  g_return_if_fail (n_param_values == 3);
   5.150 +
   5.151 +  if (G_CCLOSURE_SWAP_DATA (closure))
   5.152 +    {
   5.153 +      data1 = closure->data;
   5.154 +      data2 = g_value_peek_pointer (param_values + 0);
   5.155 +    }
   5.156 +  else
   5.157 +    {
   5.158 +      data1 = g_value_peek_pointer (param_values + 0);
   5.159 +      data2 = closure->data;
   5.160 +    }
   5.161 +  callback = (GMarshalFunc_BOOLEAN__OBJECT_POINTER) (marshal_data ? marshal_data : cc->callback);
   5.162 +
   5.163 +  v_return = callback (data1,
   5.164 +                       g_marshal_value_peek_object (param_values + 1),
   5.165 +                       g_marshal_value_peek_pointer (param_values + 2),
   5.166 +                       data2);
   5.167 +
   5.168 +  g_value_set_boolean (return_value, v_return);
   5.169 +}
   5.170 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/gst-gmyth/decodebin2/gstplay-marshal.h	Sat Jul 14 17:20:54 2007 +0100
     6.3 @@ -0,0 +1,36 @@
     6.4 +
     6.5 +#ifndef __gst_play_marshal_MARSHAL_H__
     6.6 +#define __gst_play_marshal_MARSHAL_H__
     6.7 +
     6.8 +#include	<glib-object.h>
     6.9 +
    6.10 +G_BEGIN_DECLS
    6.11 +
    6.12 +/* BOOLEAN:OBJECT (gstplay-marshal.list:1) */
    6.13 +extern void gst_play_marshal_BOOLEAN__OBJECT (GClosure     *closure,
    6.14 +                                              GValue       *return_value,
    6.15 +                                              guint         n_param_values,
    6.16 +                                              const GValue *param_values,
    6.17 +                                              gpointer      invocation_hint,
    6.18 +                                              gpointer      marshal_data);
    6.19 +
    6.20 +/* VOID:OBJECT,BOOLEAN (gstplay-marshal.list:2) */
    6.21 +extern void gst_play_marshal_VOID__OBJECT_BOOLEAN (GClosure     *closure,
    6.22 +                                                   GValue       *return_value,
    6.23 +                                                   guint         n_param_values,
    6.24 +                                                   const GValue *param_values,
    6.25 +                                                   gpointer      invocation_hint,
    6.26 +                                                   gpointer      marshal_data);
    6.27 +
    6.28 +/* BOOLEAN:OBJECT,POINTER (gstplay-marshal.list:3) */
    6.29 +extern void gst_play_marshal_BOOLEAN__OBJECT_POINTER (GClosure     *closure,
    6.30 +                                                      GValue       *return_value,
    6.31 +                                                      guint         n_param_values,
    6.32 +                                                      const GValue *param_values,
    6.33 +                                                      gpointer      invocation_hint,
    6.34 +                                                      gpointer      marshal_data);
    6.35 +
    6.36 +G_END_DECLS
    6.37 +
    6.38 +#endif /* __gst_play_marshal_MARSHAL_H__ */
    6.39 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/gst-gmyth/multiqueue/Makefile.am	Sat Jul 14 17:20:54 2007 +0100
     7.3 @@ -0,0 +1,24 @@
     7.4 +plugin_LTLIBRARIES = libgstmultiqueue.la
     7.5 +
     7.6 +libgstmultiqueue_la_SOURCES =	\
     7.7 +	gstmultiqueue.c \
     7.8 +	gstdataqueue.c
     7.9 +
    7.10 +libgstmultiqueue_la_CFLAGS = \
    7.11 +	$(GST_CFLAGS) \
    7.12 +	$(GST_BASE_CFLAGS) \
    7.13 +	$(GST_PLUGINS_BASE_CFLAGS)
    7.14 +
    7.15 +libgstmultiqueue_la_LIBADD = \
    7.16 +	$(GST_LIBS_LIBS)
    7.17 +
    7.18 +libgstmultiqueue_la_LDFLAGS = \
    7.19 +	$(GST_LIBS) \
    7.20 +	$(GST_PLUGIN_LDFLAGS) \
    7.21 +	$(GST_BASE_LIBS) \
    7.22 +	$(GST_PLUGINS_BASE_LIBS)
    7.23 +
    7.24 +noinst_HEADERS = \
    7.25 +	gstmultiqueue.h \
    7.26 +	gstdataqueue.h
    7.27 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/gst-gmyth/multiqueue/gstdataqueue.c	Sat Jul 14 17:20:54 2007 +0100
     8.3 @@ -0,0 +1,628 @@
     8.4 +/* GStreamer
     8.5 + * Copyright (C) 2006 Edward Hervey <edward@fluendo.com>
     8.6 + *
     8.7 + * gstdataqueue.c:
     8.8 + *
     8.9 + * This library is free software; you can redistribute it and/or
    8.10 + * modify it under the terms of the GNU Library General Public
    8.11 + * License as published by the Free Software Foundation; either
    8.12 + * version 2 of the License, or (at your option) any later version.
    8.13 + *
    8.14 + * This library is distributed in the hope that it will be useful,
    8.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    8.17 + * Library General Public License for more details.
    8.18 + *
    8.19 + * You should have received a copy of the GNU Library General Public
    8.20 + * License along with this library; if not, write to the
    8.21 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    8.22 + * Boston, MA 02111-1307, USA.
    8.23 + */
    8.24 +
    8.25 +/**
    8.26 + * SECTION:gstdataqueue
    8.27 + * @short_description: Threadsafe queueing object
    8.28 + *
    8.29 + * #GstDataQueue is an object that handles threadsafe queueing of objects. It
    8.30 + * also provides size-related functionality. This object should be used for
    8.31 + * any #GstElement that wishes to provide some sort of queueing functionality.
    8.32 + */
    8.33 +
    8.34 +#include <gst/gst.h>
    8.35 +#include "gstdataqueue.h"
    8.36 +
    8.37 +GST_DEBUG_CATEGORY_STATIC (data_queue_debug);
    8.38 +#define GST_CAT_DEFAULT (data_queue_debug)
    8.39 +GST_DEBUG_CATEGORY_STATIC (data_queue_dataflow);
    8.40 +
    8.41 +
    8.42 +/* Queue signals and args */
    8.43 +enum
    8.44 +{
    8.45 +  SIGNAL_EMPTY,
    8.46 +  SIGNAL_FULL,
    8.47 +  LAST_SIGNAL
    8.48 +};
    8.49 +
    8.50 +enum
    8.51 +{
    8.52 +  ARG_0,
    8.53 +  ARG_CUR_LEVEL_VISIBLE,
    8.54 +  ARG_CUR_LEVEL_BYTES,
    8.55 +  ARG_CUR_LEVEL_TIME
    8.56 +      /* FILL ME */
    8.57 +};
    8.58 +
    8.59 +#define GST_DATA_QUEUE_MUTEX_LOCK(q) G_STMT_START {                     \
    8.60 +    GST_CAT_LOG (data_queue_dataflow,                                   \
    8.61 +      "locking qlock from thread %p",                                   \
    8.62 +      g_thread_self ());                                                \
    8.63 +  g_mutex_lock (q->qlock);                                              \
    8.64 +  GST_CAT_LOG (data_queue_dataflow,                                     \
    8.65 +      "locked qlock from thread %p",                                    \
    8.66 +      g_thread_self ());                                                \
    8.67 +} G_STMT_END
    8.68 +
    8.69 +#define GST_DATA_QUEUE_MUTEX_LOCK_CHECK(q, label) G_STMT_START {        \
    8.70 +    GST_DATA_QUEUE_MUTEX_LOCK (q);                                      \
    8.71 +    if (q->flushing)                                                    \
    8.72 +      goto label;                                                       \
    8.73 +  } G_STMT_END
    8.74 +
    8.75 +#define GST_DATA_QUEUE_MUTEX_UNLOCK(q) G_STMT_START {                   \
    8.76 +    GST_CAT_LOG (data_queue_dataflow,                                   \
    8.77 +      "unlocking qlock from thread %p",                                 \
    8.78 +      g_thread_self ());                                                \
    8.79 +  g_mutex_unlock (q->qlock);                                            \
    8.80 +} G_STMT_END
    8.81 +
    8.82 +#define STATUS(q, msg)                                                  \
    8.83 +  GST_CAT_LOG (data_queue_dataflow,                                     \
    8.84 +               "queue:%p " msg ": %u visible items, %u "                \
    8.85 +               "bytes, %"G_GUINT64_FORMAT                               \
    8.86 +               " ns, %u elements",                                      \
    8.87 +               queue,                                                   \
    8.88 +               q->cur_level.visible,                                    \
    8.89 +               q->cur_level.bytes,                                      \
    8.90 +               q->cur_level.time,                                       \
    8.91 +               q->queue->length)
    8.92 +
    8.93 +static void gst_data_queue_base_init (GstDataQueueClass * klass);
    8.94 +static void gst_data_queue_class_init (GstDataQueueClass * klass);
    8.95 +static void gst_data_queue_init (GstDataQueue * queue);
    8.96 +static void gst_data_queue_finalize (GObject * object);
    8.97 +
    8.98 +static void gst_data_queue_set_property (GObject * object,
    8.99 +    guint prop_id, const GValue * value, GParamSpec * pspec);
   8.100 +static void gst_data_queue_get_property (GObject * object,
   8.101 +    guint prop_id, GValue * value, GParamSpec * pspec);
   8.102 +
   8.103 +static GObjectClass *parent_class = NULL;
   8.104 +static guint gst_data_queue_signals[LAST_SIGNAL] = { 0 };
   8.105 +
   8.106 +GType
   8.107 +gst_data_queue_get_type (void)
   8.108 +{
   8.109 +  static GType queue_type = 0;
   8.110 +
   8.111 +  if (!queue_type) {
   8.112 +    static const GTypeInfo queue_info = {
   8.113 +      sizeof (GstDataQueueClass),
   8.114 +      (GBaseInitFunc) gst_data_queue_base_init,
   8.115 +      NULL,
   8.116 +      (GClassInitFunc) gst_data_queue_class_init,
   8.117 +      NULL,
   8.118 +      NULL,
   8.119 +      sizeof (GstDataQueue),
   8.120 +      0,
   8.121 +      (GInstanceInitFunc) gst_data_queue_init,
   8.122 +      NULL
   8.123 +    };
   8.124 +
   8.125 +    queue_type = g_type_register_static (G_TYPE_OBJECT,
   8.126 +        "GstDataQueue", &queue_info, 0);
   8.127 +    GST_DEBUG_CATEGORY_INIT (data_queue_debug, "dataqueue", 0,
   8.128 +        "data queue object");
   8.129 +    GST_DEBUG_CATEGORY_INIT (data_queue_dataflow, "data_queue_dataflow", 0,
   8.130 +        "dataflow inside the data queue object");
   8.131 +  }
   8.132 +
   8.133 +  return queue_type;
   8.134 +}
   8.135 +
   8.136 +static void
   8.137 +gst_data_queue_base_init (GstDataQueueClass * klass)
   8.138 +{
   8.139 +  /* Do we need anything here ?? */
   8.140 +  return;
   8.141 +}
   8.142 +
   8.143 +static void
   8.144 +gst_data_queue_class_init (GstDataQueueClass * klass)
   8.145 +{
   8.146 +  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   8.147 +
   8.148 +  parent_class = g_type_class_peek_parent (klass);
   8.149 +
   8.150 +  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_data_queue_set_property);
   8.151 +  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_data_queue_get_property);
   8.152 +
   8.153 +  /* signals */
   8.154 +  /**
   8.155 +   * GstDataQueue::empty:
   8.156 +   * @queue: the queue instance
   8.157 +   *
   8.158 +   * Reports that the queue became empty (empty).
   8.159 +   * A queue is empty if the total amount of visible items inside it (num-visible, time,
   8.160 +   * size) is lower than the boundary values which can be set through the GObject
   8.161 +   * properties.
   8.162 +   */
   8.163 +  gst_data_queue_signals[SIGNAL_EMPTY] =
   8.164 +      g_signal_new ("empty", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
   8.165 +      G_STRUCT_OFFSET (GstDataQueueClass, empty), NULL, NULL,
   8.166 +      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
   8.167 +
   8.168 +  /**
   8.169 +   * GstDataQueue::full:
   8.170 +   * @queue: the queue instance
   8.171 +   *
   8.172 +   * Reports that the queue became full (full).
   8.173 +   * A queue is full if the total amount of data inside it (num-visible, time,
   8.174 +   * size) is higher than the boundary values which can be set through the GObject
   8.175 +   * properties.
   8.176 +   */
   8.177 +  gst_data_queue_signals[SIGNAL_FULL] =
   8.178 +      g_signal_new ("full", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
   8.179 +      G_STRUCT_OFFSET (GstDataQueueClass, full), NULL, NULL,
   8.180 +      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
   8.181 +
   8.182 +  /* properties */
   8.183 +  g_object_class_install_property (gobject_class, ARG_CUR_LEVEL_BYTES,
   8.184 +      g_param_spec_uint ("current-level-bytes", "Current level (kB)",
   8.185 +          "Current amount of data in the queue (bytes)",
   8.186 +          0, G_MAXUINT, 0, G_PARAM_READABLE));
   8.187 +  g_object_class_install_property (gobject_class, ARG_CUR_LEVEL_VISIBLE,
   8.188 +      g_param_spec_uint ("current-level-visible",
   8.189 +          "Current level (visible items)",
   8.190 +          "Current number of visible items in the queue", 0, G_MAXUINT, 0,
   8.191 +          G_PARAM_READABLE));
   8.192 +  g_object_class_install_property (gobject_class, ARG_CUR_LEVEL_TIME,
   8.193 +      g_param_spec_uint64 ("current-level-time", "Current level (ns)",
   8.194 +          "Current amount of data in the queue (in ns)", 0, G_MAXUINT64, 0,
   8.195 +          G_PARAM_READABLE));
   8.196 +
   8.197 +  /* set several parent class virtual functions */
   8.198 +  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_data_queue_finalize);
   8.199 +
   8.200 +}
   8.201 +
   8.202 +static void
   8.203 +gst_data_queue_init (GstDataQueue * queue)
   8.204 +{
   8.205 +  queue->cur_level.visible = 0; /* no content */
   8.206 +  queue->cur_level.bytes = 0;   /* no content */
   8.207 +  queue->cur_level.time = 0;    /* no content */
   8.208 +
   8.209 +  queue->checkfull = NULL;
   8.210 +
   8.211 +  queue->qlock = g_mutex_new ();
   8.212 +  queue->item_add = g_cond_new ();
   8.213 +  queue->item_del = g_cond_new ();
   8.214 +  queue->queue = g_queue_new ();
   8.215 +
   8.216 +  GST_DEBUG ("initialized queue's not_empty & not_full conditions");
   8.217 +}
   8.218 +
   8.219 +/**
   8.220 + * gst_data_queue_new:
   8.221 + * @checkfull: the callback used to tell if the element considers the queue full
   8.222 + * or not.
   8.223 + * @checkdata: a #gpointer that will be given in the @checkfull callback.
   8.224 + *
   8.225 + * Returns: a new #GstDataQueue.
   8.226 + */
   8.227 +
   8.228 +GstDataQueue *
   8.229 +gst_data_queue_new (GstDataQueueCheckFullFunction checkfull, gpointer checkdata)
   8.230 +{
   8.231 +  GstDataQueue *ret;
   8.232 +
   8.233 +  g_return_val_if_fail (checkfull != NULL, NULL);
   8.234 +
   8.235 +  ret = g_object_new (GST_TYPE_DATA_QUEUE, NULL);
   8.236 +  ret->checkfull = checkfull;
   8.237 +  ret->checkdata = checkdata;
   8.238 +
   8.239 +  return ret;
   8.240 +}
   8.241 +
   8.242 +static void
   8.243 +gst_data_queue_cleanup (GstDataQueue * queue)
   8.244 +{
   8.245 +  while (!g_queue_is_empty (queue->queue)) {
   8.246 +    GstDataQueueItem *item = g_queue_pop_head (queue->queue);
   8.247 +
   8.248 +    /* Just call the destroy notify on the item */
   8.249 +    item->destroy (item);
   8.250 +  }
   8.251 +  queue->cur_level.visible = 0;
   8.252 +  queue->cur_level.bytes = 0;
   8.253 +  queue->cur_level.time = 0;
   8.254 +}
   8.255 +
   8.256 +/* called only once, as opposed to dispose */
   8.257 +static void
   8.258 +gst_data_queue_finalize (GObject * object)
   8.259 +{
   8.260 +  GstDataQueue *queue = GST_DATA_QUEUE (object);
   8.261 +
   8.262 +  GST_DEBUG ("finalizing queue");
   8.263 +
   8.264 +  gst_data_queue_cleanup (queue);
   8.265 +  g_queue_free (queue->queue);
   8.266 +
   8.267 +  GST_DEBUG ("free mutex");
   8.268 +  g_mutex_free (queue->qlock);
   8.269 +  GST_DEBUG ("done free mutex");
   8.270 +
   8.271 +  g_cond_free (queue->item_add);
   8.272 +  g_cond_free (queue->item_del);
   8.273 +
   8.274 +  G_OBJECT_CLASS (parent_class)->finalize (object);
   8.275 +}
   8.276 +
   8.277 +static void
   8.278 +gst_data_queue_locked_flush (GstDataQueue * queue)
   8.279 +{
   8.280 +  STATUS (queue, "before flushing");
   8.281 +  gst_data_queue_cleanup (queue);
   8.282 +  STATUS (queue, "after flushing");
   8.283 +  /* we deleted something... */
   8.284 +  g_cond_signal (queue->item_del);
   8.285 +}
   8.286 +
   8.287 +static gboolean
   8.288 +gst_data_queue_locked_is_empty (GstDataQueue * queue)
   8.289 +{
   8.290 +  return (queue->queue->length == 0);
   8.291 +}
   8.292 +
   8.293 +static gboolean
   8.294 +gst_data_queue_locked_is_full (GstDataQueue * queue)
   8.295 +{
   8.296 +  return queue->checkfull (queue, queue->cur_level.visible,
   8.297 +      queue->cur_level.bytes, queue->cur_level.time, queue->checkdata);
   8.298 +}
   8.299 +
   8.300 +/**
   8.301 + * gst_data_queue_flush:
   8.302 + * @queue: a #GstDataQueue.
   8.303 + *
   8.304 + * Flushes all the contents of the @queue. Any call to #gst_data_queue_pull and
   8.305 + * #gst_data_queue_pop will be released.
   8.306 + * MT safe.
   8.307 + */
   8.308 +void
   8.309 +gst_data_queue_flush (GstDataQueue * queue)
   8.310 +{
   8.311 +  GST_DEBUG ("queue:%p", queue);
   8.312 +  GST_DATA_QUEUE_MUTEX_LOCK (queue);
   8.313 +  gst_data_queue_locked_flush (queue);
   8.314 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.315 +}
   8.316 +
   8.317 +/**
   8.318 + * gst_data_queue_is_empty:
   8.319 + * @queue: a #GstDataQueue.
   8.320 + *
   8.321 + * Queries if there are any items in the @queue.
   8.322 + * MT safe.
   8.323 + *
   8.324 + * Returns: #TRUE if @queue is empty.
   8.325 + */
   8.326 +gboolean
   8.327 +gst_data_queue_is_empty (GstDataQueue * queue)
   8.328 +{
   8.329 +  gboolean res;
   8.330 +
   8.331 +  GST_DATA_QUEUE_MUTEX_LOCK (queue);
   8.332 +  res = gst_data_queue_locked_is_empty (queue);
   8.333 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.334 +
   8.335 +  return res;
   8.336 +}
   8.337 +
   8.338 +/**
   8.339 + * gst_data_queue_is_full:
   8.340 + * @queue: a #GstDataQueue.
   8.341 + *
   8.342 + * Queries if @queue is full. This check will be done using the
   8.343 + * #GstDataQueueCheckFullCallback registered with @queue.
   8.344 + * MT safe.
   8.345 + *
   8.346 + * Returns: #TRUE if @queue is full.
   8.347 + */
   8.348 +gboolean
   8.349 +gst_data_queue_is_full (GstDataQueue * queue)
   8.350 +{
   8.351 +  gboolean res;
   8.352 +
   8.353 +  GST_DATA_QUEUE_MUTEX_LOCK (queue);
   8.354 +  res = gst_data_queue_locked_is_full (queue);
   8.355 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.356 +
   8.357 +  return res;
   8.358 +}
   8.359 +
   8.360 +/**
   8.361 + * gst_data_queue_set_flushing:
   8.362 + * @queue: a #GstDataQueue.
   8.363 + * @flushing: a #gboolean stating if the queue will be flushing or not.
   8.364 + *
   8.365 + * Sets the queue to flushing state if @flushing is #TRUE. If set to flushing
   8.366 + * state, any incoming data on the @queue will be discarded. Any call currently
   8.367 + * blocking on #gst_data_queue_push or #gst_data_queue_pop will return straight
   8.368 + * away with a return value of #FALSE. While the @queue is in flushing state, 
   8.369 + * all calls to those two functions will return #FALSE.
   8.370 + *
   8.371 + * MT Safe.
   8.372 + */
   8.373 +void
   8.374 +gst_data_queue_set_flushing (GstDataQueue * queue, gboolean flushing)
   8.375 +{
   8.376 +  GST_DEBUG ("queue:%p , flushing:%d", queue, flushing);
   8.377 +
   8.378 +  GST_DATA_QUEUE_MUTEX_LOCK (queue);
   8.379 +  queue->flushing = flushing;
   8.380 +  if (flushing) {
   8.381 +    /* release push/pop functions */
   8.382 +    g_cond_signal (queue->item_add);
   8.383 +    g_cond_signal (queue->item_del);
   8.384 +  }
   8.385 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.386 +}
   8.387 +
   8.388 +/**
   8.389 + * gst_data_queue_push:
   8.390 + * @queue: a #GstDataQueue.
   8.391 + * @item: a #GstDataQueueItem.
   8.392 + *
   8.393 + * Pushes a #GstDataQueueItem (or a structure that begins with the same fields)
   8.394 + * on the @queue. If the @queue is full, the call will block until space is
   8.395 + * available, OR the @queue is set to flushing state.
   8.396 + * MT safe.
   8.397 + *
   8.398 + * Note that this function has slightly different semantics than gst_pad_push()
   8.399 + * and gst_pad_push_event(): this function only takes ownership of @item and
   8.400 + * the #GstMiniObject contained in @item if the push was successful. If FALSE
   8.401 + * is returned, the caller is responsible for freeing @item and its contents.
   8.402 + *
   8.403 + * Returns: #TRUE if the @item was successfully pushed on the @queue.
   8.404 + */
   8.405 +gboolean
   8.406 +gst_data_queue_push (GstDataQueue * queue, GstDataQueueItem * item)
   8.407 +{
   8.408 +  g_return_val_if_fail (GST_IS_DATA_QUEUE (queue), FALSE);
   8.409 +  g_return_val_if_fail (item != NULL, FALSE);
   8.410 +
   8.411 +  GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
   8.412 +
   8.413 +  STATUS (queue, "before pushing");
   8.414 +
   8.415 +  /* We ALWAYS need to check for queue fillness */
   8.416 +  if (gst_data_queue_locked_is_full (queue)) {
   8.417 +    GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.418 +    g_signal_emit (G_OBJECT (queue), gst_data_queue_signals[SIGNAL_FULL], 0);
   8.419 +    GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
   8.420 +
   8.421 +    /* signal might have removed some items */
   8.422 +    while (gst_data_queue_locked_is_full (queue)) {
   8.423 +      g_cond_wait (queue->item_del, queue->qlock);
   8.424 +      if (queue->flushing)
   8.425 +        goto flushing;
   8.426 +    }
   8.427 +  }
   8.428 +
   8.429 +  g_queue_push_tail (queue->queue, item);
   8.430 +
   8.431 +  if (item->visible)
   8.432 +    queue->cur_level.visible++;
   8.433 +  queue->cur_level.bytes += item->size;
   8.434 +  queue->cur_level.time += item->duration;
   8.435 +
   8.436 +  STATUS (queue, "after pushing");
   8.437 +  g_cond_signal (queue->item_add);
   8.438 +
   8.439 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.440 +
   8.441 +  return TRUE;
   8.442 +
   8.443 +  /* ERRORS */
   8.444 +flushing:
   8.445 +  {
   8.446 +    GST_DEBUG ("queue:%p, we are flushing", queue);
   8.447 +    GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.448 +    return FALSE;
   8.449 +  }
   8.450 +}
   8.451 +
   8.452 +/**
   8.453 + * gst_data_queue_pop:
   8.454 + * @queue: a #GstDataQueue.
   8.455 + * @item: pointer to store the returned #GstDataQueueItem.
   8.456 + *
   8.457 + * Retrieves the first @item available on the @queue. If the queue is currently
   8.458 + * empty, the call will block until at least one item is available, OR the
   8.459 + * @queue is set to the flushing state.
   8.460 + * MT safe.
   8.461 + *
   8.462 + * Returns: #TRUE if an @item was successfully retrieved from the @queue.
   8.463 + */
   8.464 +gboolean
   8.465 +gst_data_queue_pop (GstDataQueue * queue, GstDataQueueItem ** item)
   8.466 +{
   8.467 +  g_return_val_if_fail (GST_IS_DATA_QUEUE (queue), FALSE);
   8.468 +  g_return_val_if_fail (item != NULL, FALSE);
   8.469 +
   8.470 +  GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
   8.471 +
   8.472 +  STATUS (queue, "before popping");
   8.473 +
   8.474 +  if (gst_data_queue_locked_is_empty (queue)) {
   8.475 +    GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.476 +    g_signal_emit (G_OBJECT (queue), gst_data_queue_signals[SIGNAL_EMPTY], 0);
   8.477 +    GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
   8.478 +
   8.479 +    while (gst_data_queue_locked_is_empty (queue)) {
   8.480 +      g_cond_wait (queue->item_add, queue->qlock);
   8.481 +      if (queue->flushing)
   8.482 +        goto flushing;
   8.483 +    }
   8.484 +  }
   8.485 +
   8.486 +  /* Get the item from the GQueue */
   8.487 +  *item = g_queue_pop_head (queue->queue);
   8.488 +
   8.489 +  /* update current level counter */
   8.490 +  if ((*item)->visible)
   8.491 +    queue->cur_level.visible--;
   8.492 +  queue->cur_level.bytes -= (*item)->size;
   8.493 +  queue->cur_level.time -= (*item)->duration;
   8.494 +
   8.495 +  STATUS (queue, "after popping");
   8.496 +  g_cond_signal (queue->item_del);
   8.497 +
   8.498 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.499 +
   8.500 +  return TRUE;
   8.501 +
   8.502 +  /* ERRORS */
   8.503 +flushing:
   8.504 +  {
   8.505 +    GST_DEBUG ("queue:%p, we are flushing", queue);
   8.506 +    GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.507 +    return FALSE;
   8.508 +  }
   8.509 +}
   8.510 +
   8.511 +/**
   8.512 + * gst_data_queue_drop_head:
   8.513 + * @queue: The #GstDataQueue to drop an item from.
   8.514 + * @type: The #GType of the item to drop.
   8.515 + *
   8.516 + * Pop and unref the head-most #GstMiniObject with the given #GType.
   8.517 + *
   8.518 + * Returns: TRUE if an element was removed.
   8.519 + */
   8.520 +gboolean
   8.521 +gst_data_queue_drop_head (GstDataQueue * queue, GType type)
   8.522 +{
   8.523 +  gboolean res = FALSE;
   8.524 +  GList *item;
   8.525 +  GstDataQueueItem *leak = NULL;
   8.526 +
   8.527 +  g_return_val_if_fail (GST_IS_DATA_QUEUE (queue), FALSE);
   8.528 +
   8.529 +  GST_DEBUG ("queue:%p", queue);
   8.530 +
   8.531 +  GST_DATA_QUEUE_MUTEX_LOCK (queue);
   8.532 +  for (item = g_queue_peek_head_link (queue->queue); item; item = item->next) {
   8.533 +    GstDataQueueItem *tmp = (GstDataQueueItem *) item->data;
   8.534 +
   8.535 +    if (G_TYPE_CHECK_INSTANCE_TYPE (tmp->object, type)) {
   8.536 +      leak = tmp;
   8.537 +      break;
   8.538 +    }
   8.539 +  }
   8.540 +
   8.541 +  if (!leak)
   8.542 +    goto done;
   8.543 +
   8.544 +  g_queue_delete_link (queue->queue, item);
   8.545 +
   8.546 +  if (leak->visible)
   8.547 +    queue->cur_level.visible--;
   8.548 +  queue->cur_level.bytes -= leak->size;
   8.549 +  queue->cur_level.time -= leak->duration;
   8.550 +
   8.551 +  leak->destroy (leak);
   8.552 +
   8.553 +  res = TRUE;
   8.554 +
   8.555 +done:
   8.556 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.557 +
   8.558 +  GST_DEBUG ("queue:%p , res:%d", queue, res);
   8.559 +
   8.560 +  return res;
   8.561 +}
   8.562 +
   8.563 +/**
   8.564 + * gst_data_queue_limits_changed:
   8.565 + * @queue: The #GstDataQueue 
   8.566 + *
   8.567 + * Inform the queue that the limits for the fullness check have changed and that
   8.568 + * any blocking gst_data_queue_push() should be unblocked to recheck the limts.
   8.569 + */
   8.570 +void
   8.571 +gst_data_queue_limits_changed (GstDataQueue * queue)
   8.572 +{
   8.573 +  g_return_if_fail (GST_IS_DATA_QUEUE (queue));
   8.574 +
   8.575 +  GST_DATA_QUEUE_MUTEX_LOCK (queue);
   8.576 +  GST_DEBUG ("signal del");
   8.577 +  g_cond_signal (queue->item_del);
   8.578 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.579 +}
   8.580 +
   8.581 +/**
   8.582 + * gst_data_queue_get_level:
   8.583 + * @queue: The #GstDataQueue
   8.584 + * @level: the location to store the result
   8.585 + *
   8.586 + * Get the current level of the queue.
   8.587 + */
   8.588 +void
   8.589 +gst_data_queue_get_level (GstDataQueue * queue, GstDataQueueSize * level)
   8.590 +{
   8.591 +  level->visible = queue->cur_level.visible;
   8.592 +  level->bytes = queue->cur_level.bytes;
   8.593 +  level->time = queue->cur_level.time;
   8.594 +}
   8.595 +
   8.596 +static void
   8.597 +gst_data_queue_set_property (GObject * object,
   8.598 +    guint prop_id, const GValue * value, GParamSpec * pspec)
   8.599 +{
   8.600 +  switch (prop_id) {
   8.601 +    default:
   8.602 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   8.603 +      break;
   8.604 +  }
   8.605 +}
   8.606 +
   8.607 +static void
   8.608 +gst_data_queue_get_property (GObject * object,
   8.609 +    guint prop_id, GValue * value, GParamSpec * pspec)
   8.610 +{
   8.611 +  GstDataQueue *queue = GST_DATA_QUEUE (object);
   8.612 +
   8.613 +  GST_DATA_QUEUE_MUTEX_LOCK (queue);
   8.614 +
   8.615 +  switch (prop_id) {
   8.616 +    case ARG_CUR_LEVEL_BYTES:
   8.617 +      g_value_set_uint (value, queue->cur_level.bytes);
   8.618 +      break;
   8.619 +    case ARG_CUR_LEVEL_VISIBLE:
   8.620 +      g_value_set_uint (value, queue->cur_level.visible);
   8.621 +      break;
   8.622 +    case ARG_CUR_LEVEL_TIME:
   8.623 +      g_value_set_uint64 (value, queue->cur_level.time);
   8.624 +      break;
   8.625 +    default:
   8.626 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   8.627 +      break;
   8.628 +  }
   8.629 +
   8.630 +  GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
   8.631 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/gst-gmyth/multiqueue/gstdataqueue.h	Sat Jul 14 17:20:54 2007 +0100
     9.3 @@ -0,0 +1,159 @@
     9.4 +/* GStreamer
     9.5 + * Copyright (C) 2006 Edward Hervey <edward@fluendo.com>
     9.6 + *
     9.7 + * gstdataqueue.h:
     9.8 + *
     9.9 + * This library is free software; you can redistribute it and/or
    9.10 + * modify it under the terms of the GNU Library General Public
    9.11 + * License as published by the Free Software Foundation; either
    9.12 + * version 2 of the License, or (at your option) any later version.
    9.13 + *
    9.14 + * This library is distributed in the hope that it will be useful,
    9.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    9.17 + * Library General Public License for more details.
    9.18 + *
    9.19 + * You should have received a copy of the GNU Library General Public
    9.20 + * License along with this library; if not, write to the
    9.21 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    9.22 + * Boston, MA 02111-1307, USA.
    9.23 + */
    9.24 +
    9.25 +
    9.26 +#ifndef __GST_DATA_QUEUE_H__
    9.27 +#define __GST_DATA_QUEUE_H__
    9.28 +
    9.29 +#include <gst/gst.h>
    9.30 +
    9.31 +G_BEGIN_DECLS
    9.32 +#define GST_TYPE_DATA_QUEUE \
    9.33 +  (gst_data_queue_get_type())
    9.34 +#define GST_DATA_QUEUE(obj) \
    9.35 +  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DATA_QUEUE,GstDataQueue))
    9.36 +#define GST_DATA_QUEUE_CLASS(klass) \
    9.37 +  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DATA_QUEUE,GstDataQueueClass))
    9.38 +#define GST_IS_DATA_QUEUE(obj) \
    9.39 +  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DATA_QUEUE))
    9.40 +#define GST_IS_DATA_QUEUE_CLASS(klass) \
    9.41 +  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DATA_QUEUE))
    9.42 +typedef struct _GstDataQueue GstDataQueue;
    9.43 +typedef struct _GstDataQueueClass GstDataQueueClass;
    9.44 +typedef struct _GstDataQueueSize GstDataQueueSize;
    9.45 +typedef struct _GstDataQueueItem GstDataQueueItem;
    9.46 +
    9.47 +/**
    9.48 + * GstDataQueueItem:
    9.49 + * @object: the #GstMiniObject to queue.
    9.50 + * @size: the size in bytes of the miniobject.
    9.51 + * @duration: the duration in #GstClockTime of the miniobject. Can not be
    9.52 + * #GST_CLOCK_TIME_NONE.
    9.53 + * @visible: #TRUE if @object should be considered as a visible object.
    9.54 + * @destroy: The #GDestroyNotify function to use to free the #GstDataQueueItem.
    9.55 + * This function should also drop the reference to @object the owner of the
    9.56 + * #GstDataQueueItem is assumed to hold.
    9.57 + *
    9.58 + * Structure used by #GstDataQueue. You can supply a different structure, as
    9.59 + * long as the top of the structure is identical to this structure.
    9.60 + */
    9.61 +
    9.62 +struct _GstDataQueueItem
    9.63 +{
    9.64 +  GstMiniObject *object;
    9.65 +  guint size;
    9.66 +  guint64 duration;
    9.67 +  gboolean visible;
    9.68 +
    9.69 +  /* user supplied destroy function */
    9.70 +  GDestroyNotify destroy;
    9.71 +};
    9.72 +
    9.73 +/**
    9.74 + * GstDataQueueSize:
    9.75 + * @visible: number of buffers
    9.76 + * @bytes: number of bytes
    9.77 + * @time: amount of time
    9.78 + *
    9.79 + * Structure describing the size of a queue.
    9.80 + */
    9.81 +struct _GstDataQueueSize
    9.82 +{
    9.83 +  guint visible;
    9.84 +  guint bytes;
    9.85 +  guint64 time;
    9.86 +};
    9.87 +
    9.88 +/**
    9.89 + * GstDataQueueCheckFullFunction:
    9.90 + * @queue: a #GstDataQueue.
    9.91 + * @visible: The number of visible items currently in the queue.
    9.92 + * @bytes: The amount of bytes currently in the queue.
    9.93 + * @time: The accumulated duration of the items currently in the queue.
    9.94 + * @checkdata: The #gpointer registered when the #GstDataQueue was created.
    9.95 + * 
    9.96 + * The prototype of the function used to inform the queue that it should be
    9.97 + * considered as full.
    9.98 + *
    9.99 + * Returns: #TRUE if the queue should be considered full.
   9.100 + */
   9.101 +typedef gboolean (*GstDataQueueCheckFullFunction) (GstDataQueue * queue,
   9.102 +    guint visible, guint bytes, guint64 time, gpointer checkdata);
   9.103 +
   9.104 +/**
   9.105 + * GstDataQueue:
   9.106 + *
   9.107 + * Opaque #GstDataQueue structure.
   9.108 + */
   9.109 +struct _GstDataQueue
   9.110 +{
   9.111 +  GObject object;
   9.112 +
   9.113 +  /*< private > */
   9.114 +  /* the queue of data we're keeping our grubby hands on */
   9.115 +  GQueue *queue;
   9.116 +
   9.117 +  GstDataQueueSize cur_level;   /* size of the queue */
   9.118 +  GstDataQueueCheckFullFunction checkfull;      /* Callback to check if the queue is full */
   9.119 +  gpointer *checkdata;
   9.120 +
   9.121 +  GMutex *qlock;                /* lock for queue (vs object lock) */
   9.122 +  GCond *item_add;              /* signals buffers now available for reading */
   9.123 +  GCond *item_del;              /* signals space now available for writing */
   9.124 +  gboolean flushing;            /* indicates whether conditions where signalled because
   9.125 +                                 * of external flushing */
   9.126 +
   9.127 +  gpointer _gst_reserved[GST_PADDING];
   9.128 +};
   9.129 +
   9.130 +struct _GstDataQueueClass
   9.131 +{
   9.132 +  GObjectClass parent_class;
   9.133 +
   9.134 +  /* signals */
   9.135 +  void (*empty) (GstDataQueue * queue);
   9.136 +  void (*full) (GstDataQueue * queue);
   9.137 +
   9.138 +  gpointer _gst_reserved[GST_PADDING];
   9.139 +};
   9.140 +
   9.141 +GType gst_data_queue_get_type (void);
   9.142 +
   9.143 +GstDataQueue * gst_data_queue_new            (GstDataQueueCheckFullFunction checkfull,
   9.144 +                                              gpointer checkdata);
   9.145 +
   9.146 +gboolean       gst_data_queue_push           (GstDataQueue * queue, GstDataQueueItem * item);
   9.147 +gboolean       gst_data_queue_pop            (GstDataQueue * queue, GstDataQueueItem ** item);
   9.148 +
   9.149 +void           gst_data_queue_flush          (GstDataQueue * queue);
   9.150 +void           gst_data_queue_set_flushing   (GstDataQueue * queue, gboolean flushing);
   9.151 +
   9.152 +gboolean       gst_data_queue_drop_head      (GstDataQueue * queue, GType type);
   9.153 +
   9.154 +gboolean       gst_data_queue_is_full        (GstDataQueue * queue);
   9.155 +gboolean       gst_data_queue_is_empty       (GstDataQueue * queue);
   9.156 +
   9.157 +void           gst_data_queue_get_level      (GstDataQueue * queue, GstDataQueueSize *level);
   9.158 +void           gst_data_queue_limits_changed (GstDataQueue * queue);
   9.159 +
   9.160 +G_END_DECLS
   9.161 +
   9.162 +#endif /* __GST_DATA_QUEUE_H__ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/gst-gmyth/multiqueue/gstmultiqueue.c	Sat Jul 14 17:20:54 2007 +0100
    10.3 @@ -0,0 +1,1397 @@
    10.4 +/* GStreamer
    10.5 + * Copyright (C) 2006 Edward Hervey <edward@fluendo.com>
    10.6 + * Copyright (C) 2007 Jan Schmidt <jan@fluendo.com>
    10.7 + * Copyright (C) 2007 Wim Taymans <wim@fluendo.com>
    10.8 + *
    10.9 + * gstmultiqueue.c:
   10.10 + *
   10.11 + * This library is free software; you can redistribute it and/or
   10.12 + * modify it under the terms of the GNU Library General Public
   10.13 + * License as published by the Free Software Foundation; either
   10.14 + * version 2 of the License, or (at your option) any later version.
   10.15 + *
   10.16 + * This library is distributed in the hope that it will be useful,
   10.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   10.19 + * Library General Public License for more details.
   10.20 + *
   10.21 + * You should have received a copy of the GNU Library General Public
   10.22 + * License along with this library; if not, write to the
   10.23 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   10.24 + * Boston, MA 02111-1307, USA.
   10.25 + */
   10.26 +
   10.27 +#ifdef HAVE_CONFIG_H
   10.28 +#  include "config.h"
   10.29 +#endif
   10.30 +
   10.31 +#include <gst/gst.h>
   10.32 +#include "gstmultiqueue.h"
   10.33 +
   10.34 +/**
   10.35 + * GstSingleQueue:
   10.36 + * @sinkpad: associated sink #GstPad
   10.37 + * @srcpad: associated source #GstPad
   10.38 + *
   10.39 + * Structure containing all information and properties about
   10.40 + * a single queue.
   10.41 + */
   10.42 +typedef struct _GstSingleQueue GstSingleQueue;
   10.43 +
   10.44 +struct _GstSingleQueue
   10.45 +{
   10.46 +  /* unique identifier of the queue */
   10.47 +  guint id;
   10.48 +
   10.49 +  GstMultiQueue *mqueue;
   10.50 +
   10.51 +  GstPad *sinkpad;
   10.52 +  GstPad *srcpad;
   10.53 +
   10.54 +  /* flowreturn of previous srcpad push */
   10.55 +  GstFlowReturn srcresult;
   10.56 +  GstSegment sink_segment;
   10.57 +  GstSegment src_segment;
   10.58 +
   10.59 +  /* queue of data */
   10.60 +  GstDataQueue *queue;
   10.61 +  GstDataQueueSize max_size, extra_size;
   10.62 +  GstClockTime cur_time;
   10.63 +  gboolean is_eos;
   10.64 +  gboolean inextra;             /* TRUE if the queue is currently in extradata mode */
   10.65 +
   10.66 +  /* Protected by global lock */
   10.67 +  guint32 nextid;               /* ID of the next object waiting to be pushed */
   10.68 +  guint32 oldid;                /* ID of the last object pushed (last in a series) */
   10.69 +  GCond *turn;                  /* SingleQueue turn waiting conditional */
   10.70 +};
   10.71 +
   10.72 +
   10.73 +/* Extension of GstDataQueueItem structure for our usage */
   10.74 +typedef struct _GstMultiQueueItem GstMultiQueueItem;
   10.75 +
   10.76 +struct _GstMultiQueueItem
   10.77 +{
   10.78 +  GstMiniObject *object;
   10.79 +  guint size;
   10.80 +  guint64 duration;
   10.81 +  gboolean visible;
   10.82 +
   10.83 +  GDestroyNotify destroy;
   10.84 +  guint32 posid;
   10.85 +};
   10.86 +
   10.87 +static GstSingleQueue *gst_single_queue_new (GstMultiQueue * mqueue);
   10.88 +static void gst_single_queue_free (GstSingleQueue * squeue);
   10.89 +
   10.90 +static void wake_up_next_non_linked (GstMultiQueue * mq);
   10.91 +static void compute_high_id (GstMultiQueue * mq);
   10.92 +
   10.93 +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink%d",
   10.94 +    GST_PAD_SINK,
   10.95 +    GST_PAD_REQUEST,
   10.96 +    GST_STATIC_CAPS_ANY);
   10.97 +
   10.98 +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src%d",
   10.99 +    GST_PAD_SRC,
  10.100 +    GST_PAD_SOMETIMES,
  10.101 +    GST_STATIC_CAPS_ANY);
  10.102 +
  10.103 +GST_DEBUG_CATEGORY_STATIC (multi_queue_debug);
  10.104 +#define GST_CAT_DEFAULT (multi_queue_debug)
  10.105 +
  10.106 +/* default limits, we try to keep up to 2 seconds of data and if there is not
  10.107 + * time, up to 10 MB. The number of buffers is dynamically scaled to make sure
  10.108 + * there is data in the queues. Normally, the byte and time limits are not hit
  10.109 + * in theses conditions. */
  10.110 +#define DEFAULT_MAX_SIZE_BYTES 10 * 1024 * 1024 /* 10 MB */
  10.111 +#define DEFAULT_MAX_SIZE_BUFFERS 5
  10.112 +#define DEFAULT_MAX_SIZE_TIME 2 * GST_SECOND
  10.113 +
  10.114 +/* second limits. When we hit one of the above limits we are probably dealing
  10.115 + * with a badly muxed file and we scale the limits to these emergency values.
  10.116 + * This is currently not yet implemented. */
  10.117 +#define DEFAULT_EXTRA_SIZE_BYTES 10 * 1024 * 1024       /* 10 MB */
  10.118 +#define DEFAULT_EXTRA_SIZE_BUFFERS 5
  10.119 +#define DEFAULT_EXTRA_SIZE_TIME 3 * GST_SECOND
  10.120 +
  10.121 +/* Signals and args */
  10.122 +enum
  10.123 +{
  10.124 +  SIGNAL_UNDERRUN,
  10.125 +  SIGNAL_OVERRUN,
  10.126 +  LAST_SIGNAL
  10.127 +};
  10.128 +
  10.129 +enum
  10.130 +{
  10.131 +  ARG_0,
  10.132 +  ARG_EXTRA_SIZE_BYTES,
  10.133 +  ARG_EXTRA_SIZE_BUFFERS,
  10.134 +  ARG_EXTRA_SIZE_TIME,
  10.135 +  ARG_MAX_SIZE_BYTES,
  10.136 +  ARG_MAX_SIZE_BUFFERS,
  10.137 +  ARG_MAX_SIZE_TIME,
  10.138 +};
  10.139 +
  10.140 +
  10.141 +static const GstElementDetails  gst_multiqueue_details = 
  10.142 +GST_ELEMENT_DETAILS ("MultiQueue",
  10.143 +      "Generic",
  10.144 +      "Multiple data queue",
  10.145 +      "Edward Hervey <edward@fluendo.com>");
  10.146 +
  10.147 +
  10.148 +#define GST_MULTI_QUEUE_MUTEX_LOCK(q) G_STMT_START {                          \
  10.149 +  g_mutex_lock (q->qlock);                                              \
  10.150 +} G_STMT_END
  10.151 +
  10.152 +#define GST_MULTI_QUEUE_MUTEX_UNLOCK(q) G_STMT_START {                        \
  10.153 +  g_mutex_unlock (q->qlock);                                            \
  10.154 +} G_STMT_END
  10.155 +
  10.156 +static void gst_multi_queue_finalize (GObject * object);
  10.157 +static void gst_multi_queue_set_property (GObject * object,
  10.158 +    guint prop_id, const GValue * value, GParamSpec * pspec);
  10.159 +static void gst_multi_queue_get_property (GObject * object,
  10.160 +    guint prop_id, GValue * value, GParamSpec * pspec);
  10.161 +
  10.162 +static GstPad *gst_multi_queue_request_new_pad (GstElement * element,
  10.163 +    GstPadTemplate * temp, const gchar * name);
  10.164 +static void gst_multi_queue_release_pad (GstElement * element, GstPad * pad);
  10.165 +
  10.166 +static void gst_multi_queue_loop (GstPad * pad);
  10.167 +
  10.168 +#define _do_init(bla) \
  10.169 +  GST_DEBUG_CATEGORY_INIT (multi_queue_debug, "multiqueue", 0, "multiqueue element");
  10.170 +
  10.171 +GST_BOILERPLATE_FULL (GstMultiQueue, gst_multi_queue, GstElement,
  10.172 +    GST_TYPE_ELEMENT, _do_init);
  10.173 +
  10.174 +static guint gst_multi_queue_signals[LAST_SIGNAL] = { 0 };
  10.175 +
  10.176 +
  10.177 +
  10.178 +static void
  10.179 +gst_multi_queue_base_init (gpointer g_class)
  10.180 +{
  10.181 +  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
  10.182 +
  10.183 +  gst_element_class_set_details (gstelement_class, &gst_multiqueue_details);
  10.184 +  gst_element_class_add_pad_template (gstelement_class,
  10.185 +      gst_static_pad_template_get (&sinktemplate));
  10.186 +  gst_element_class_add_pad_template (gstelement_class,
  10.187 +      gst_static_pad_template_get (&srctemplate));
  10.188 +}
  10.189 +
  10.190 +static void
  10.191 +gst_multi_queue_class_init (GstMultiQueueClass * klass)
  10.192 +{
  10.193 +  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  10.194 +  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
  10.195 +
  10.196 +  gobject_class->set_property =
  10.197 +      GST_DEBUG_FUNCPTR (gst_multi_queue_set_property);
  10.198 +  gobject_class->get_property =
  10.199 +      GST_DEBUG_FUNCPTR (gst_multi_queue_get_property);
  10.200 +
  10.201 +  /* SIGNALS */
  10.202 +  gst_multi_queue_signals[SIGNAL_UNDERRUN] =
  10.203 +      g_signal_new ("underrun", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
  10.204 +      G_STRUCT_OFFSET (GstMultiQueueClass, underrun), NULL, NULL,
  10.205 +      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
  10.206 +
  10.207 +  gst_multi_queue_signals[SIGNAL_OVERRUN] =
  10.208 +      g_signal_new ("overrun", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
  10.209 +      G_STRUCT_OFFSET (GstMultiQueueClass, overrun), NULL, NULL,
  10.210 +      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
  10.211 +
  10.212 +  /* PROPERTIES */
  10.213 +
  10.214 +  g_object_class_install_property (gobject_class, ARG_MAX_SIZE_BYTES,
  10.215 +      g_param_spec_uint ("max-size-bytes", "Max. size (kB)",
  10.216 +          "Max. amount of data in the queue (bytes, 0=disable)",
  10.217 +          0, G_MAXUINT, DEFAULT_MAX_SIZE_BYTES, G_PARAM_READWRITE));
  10.218 +  g_object_class_install_property (gobject_class, ARG_MAX_SIZE_BUFFERS,
  10.219 +      g_param_spec_uint ("max-size-buffers", "Max. size (buffers)",
  10.220 +          "Max. number of buffers in the queue (0=disable)",
  10.221 +          0, G_MAXUINT, DEFAULT_MAX_SIZE_BUFFERS, G_PARAM_READWRITE));
  10.222 +  g_object_class_install_property (gobject_class, ARG_MAX_SIZE_TIME,
  10.223 +      g_param_spec_uint64 ("max-size-time", "Max. size (ns)",
  10.224 +          "Max. amount of data in the queue (in ns, 0=disable)",
  10.225 +          0, G_MAXUINT64, DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE));
  10.226 +
  10.227 +  g_object_class_install_property (gobject_class, ARG_EXTRA_SIZE_BYTES,
  10.228 +      g_param_spec_uint ("extra-size-bytes", "Extra Size (kB)",
  10.229 +          "Amount of data the queues can grow if one of them is empty (bytes, 0=disable)",
  10.230 +          0, G_MAXUINT, DEFAULT_EXTRA_SIZE_BYTES, G_PARAM_READWRITE));
  10.231 +  g_object_class_install_property (gobject_class, ARG_EXTRA_SIZE_BUFFERS,
  10.232 +      g_param_spec_uint ("extra-size-buffers", "Extra Size (buffers)",
  10.233 +          "Amount of buffers the queues can grow if one of them is empty (0=disable)",
  10.234 +          0, G_MAXUINT, DEFAULT_EXTRA_SIZE_BUFFERS, G_PARAM_READWRITE));
  10.235 +  g_object_class_install_property (gobject_class, ARG_EXTRA_SIZE_TIME,
  10.236 +      g_param_spec_uint64 ("extra-size-time", "Extra Size (ns)",
  10.237 +          "Amount of time the queues can grow if one of them is empty (in ns, 0=disable)",
  10.238 +          0, G_MAXUINT64, DEFAULT_EXTRA_SIZE_TIME, G_PARAM_READWRITE));
  10.239 +
  10.240 +  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_multi_queue_finalize);
  10.241 +
  10.242 +  gstelement_class->request_new_pad =
  10.243 +      GST_DEBUG_FUNCPTR (gst_multi_queue_request_new_pad);
  10.244 +  gstelement_class->release_pad =
  10.245 +      GST_DEBUG_FUNCPTR (gst_multi_queue_release_pad);
  10.246 +}
  10.247 +
  10.248 +static void
  10.249 +gst_multi_queue_init (GstMultiQueue * mqueue, GstMultiQueueClass * klass)
  10.250 +{
  10.251 +  mqueue->nbqueues = 0;
  10.252 +  mqueue->queues = NULL;
  10.253 +
  10.254 +  mqueue->max_size.bytes = DEFAULT_MAX_SIZE_BYTES;
  10.255 +  mqueue->max_size.visible = DEFAULT_MAX_SIZE_BUFFERS;
  10.256 +  mqueue->max_size.time = DEFAULT_MAX_SIZE_TIME;
  10.257 +
  10.258 +  mqueue->extra_size.bytes = DEFAULT_EXTRA_SIZE_BYTES;
  10.259 +  mqueue->extra_size.visible = DEFAULT_EXTRA_SIZE_BUFFERS;
  10.260 +  mqueue->extra_size.time = DEFAULT_EXTRA_SIZE_TIME;
  10.261 +
  10.262 +  mqueue->counter = 1;
  10.263 +  mqueue->highid = -1;
  10.264 +  mqueue->nextnotlinked = -1;
  10.265 +
  10.266 +  mqueue->qlock = g_mutex_new ();
  10.267 +}
  10.268 +
  10.269 +static void
  10.270 +gst_multi_queue_finalize (GObject * object)
  10.271 +{
  10.272 +  GstMultiQueue *mqueue = GST_MULTI_QUEUE (object);
  10.273 +
  10.274 +  g_list_foreach (mqueue->queues, (GFunc) gst_single_queue_free, NULL);
  10.275 +  g_list_free (mqueue->queues);
  10.276 +  mqueue->queues = NULL;
  10.277 +
  10.278 +  /* free/unref instance data */
  10.279 +  g_mutex_free (mqueue->qlock);
  10.280 +
  10.281 +  G_OBJECT_CLASS (parent_class)->finalize (object);
  10.282 +}
  10.283 +
  10.284 +
  10.285 +
  10.286 +#define SET_CHILD_PROPERTY(mq,format) G_STMT_START {	        \
  10.287 +    GList * tmp = mq->queues;					\
  10.288 +    while (tmp) {						\
  10.289 +      GstSingleQueue *q = (GstSingleQueue*)tmp->data;		\
  10.290 +      q->max_size.format = mq->max_size.format;                 \
  10.291 +      tmp = g_list_next(tmp);					\
  10.292 +    };								\
  10.293 +} G_STMT_END
  10.294 +
  10.295 +static void
  10.296 +gst_multi_queue_set_property (GObject * object, guint prop_id,
  10.297 +    const GValue * value, GParamSpec * pspec)
  10.298 +{
  10.299 +  GstMultiQueue *mq = GST_MULTI_QUEUE (object);
  10.300 +
  10.301 +  switch (prop_id) {
  10.302 +    case ARG_MAX_SIZE_BYTES:
  10.303 +      mq->max_size.bytes = g_value_get_uint (value);
  10.304 +      SET_CHILD_PROPERTY (mq, bytes);
  10.305 +      break;
  10.306 +    case ARG_MAX_SIZE_BUFFERS:
  10.307 +      mq->max_size.visible = g_value_get_uint (value);
  10.308 +      SET_CHILD_PROPERTY (mq, visible);
  10.309 +      break;
  10.310 +    case ARG_MAX_SIZE_TIME:
  10.311 +      mq->max_size.time = g_value_get_uint64 (value);
  10.312 +      SET_CHILD_PROPERTY (mq, time);
  10.313 +      break;
  10.314 +    case ARG_EXTRA_SIZE_BYTES:
  10.315 +      mq->extra_size.bytes = g_value_get_uint (value);
  10.316 +      break;
  10.317 +    case ARG_EXTRA_SIZE_BUFFERS:
  10.318 +      mq->extra_size.visible = g_value_get_uint (value);
  10.319 +      break;
  10.320 +    case ARG_EXTRA_SIZE_TIME:
  10.321 +      mq->extra_size.time = g_value_get_uint64 (value);
  10.322 +      break;
  10.323 +    default:
  10.324 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  10.325 +      break;
  10.326 +  }
  10.327 +}
  10.328 +
  10.329 +static void
  10.330 +gst_multi_queue_get_property (GObject * object, guint prop_id,
  10.331 +    GValue * value, GParamSpec * pspec)
  10.332 +{
  10.333 +  GstMultiQueue *mq = GST_MULTI_QUEUE (object);
  10.334 +
  10.335 +  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.336 +
  10.337 +  switch (prop_id) {
  10.338 +    case ARG_EXTRA_SIZE_BYTES:
  10.339 +      g_value_set_uint (value, mq->extra_size.bytes);
  10.340 +      break;
  10.341 +    case ARG_EXTRA_SIZE_BUFFERS:
  10.342 +      g_value_set_uint (value, mq->extra_size.visible);
  10.343 +      break;
  10.344 +    case ARG_EXTRA_SIZE_TIME:
  10.345 +      g_value_set_uint64 (value, mq->extra_size.time);
  10.346 +      break;
  10.347 +    case ARG_MAX_SIZE_BYTES:
  10.348 +      g_value_set_uint (value, mq->max_size.bytes);
  10.349 +      break;
  10.350 +    case ARG_MAX_SIZE_BUFFERS:
  10.351 +      g_value_set_uint (value, mq->max_size.visible);
  10.352 +      break;
  10.353 +    case ARG_MAX_SIZE_TIME:
  10.354 +      g_value_set_uint64 (value, mq->max_size.time);
  10.355 +      break;
  10.356 +    default:
  10.357 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  10.358 +      break;
  10.359 +  }
  10.360 +
  10.361 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.362 +}
  10.363 +
  10.364 +GList *
  10.365 +gst_multi_queue_get_internal_links (GstPad * pad)
  10.366 +{
  10.367 +  GList *res = NULL;
  10.368 +  GstMultiQueue *mqueue;
  10.369 +  GstSingleQueue *sq = NULL;
  10.370 +  GList *tmp;
  10.371 +
  10.372 +  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
  10.373 +
  10.374 +  mqueue = GST_MULTI_QUEUE (GST_PAD_PARENT (pad));
  10.375 +  if (!mqueue)
  10.376 +    goto no_parent;
  10.377 +
  10.378 +  GST_MULTI_QUEUE_MUTEX_LOCK (mqueue);
  10.379 +  /* Find which single queue it belongs to */
  10.380 +  for (tmp = mqueue->queues; tmp && !res; tmp = g_list_next (tmp)) {
  10.381 +    sq = (GstSingleQueue *) tmp->data;
  10.382 +
  10.383 +    if (sq->sinkpad == pad)
  10.384 +      res = g_list_prepend (res, sq->srcpad);
  10.385 +    if (sq->srcpad == pad)
  10.386 +      res = g_list_prepend (res, sq->sinkpad);
  10.387 +  }
  10.388 +
  10.389 +  if (!res)
  10.390 +    GST_WARNING_OBJECT (mqueue, "That pad doesn't belong to this element ???");
  10.391 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mqueue);
  10.392 +
  10.393 +  return res;
  10.394 +
  10.395 +no_parent:
  10.396 +  {
  10.397 +    GST_DEBUG_OBJECT (pad, "no parent");
  10.398 +    return NULL;
  10.399 +  }
  10.400 +}
  10.401 +
  10.402 +
  10.403 +/*
  10.404 + * GstElement methods
  10.405 + */
  10.406 +
  10.407 +static GstPad *
  10.408 +gst_multi_queue_request_new_pad (GstElement * element, GstPadTemplate * temp,
  10.409 +    const gchar * name)
  10.410 +{
  10.411 +  GstMultiQueue *mqueue = GST_MULTI_QUEUE (element);
  10.412 +  GstSingleQueue *squeue;
  10.413 +
  10.414 +  GST_LOG_OBJECT (element, "name : %s", name);
  10.415 +
  10.416 +  /* Create a new single queue, add the sink and source pad and return the sink pad */
  10.417 +  squeue = gst_single_queue_new (mqueue);
  10.418 +
  10.419 +  GST_MULTI_QUEUE_MUTEX_LOCK (mqueue);
  10.420 +  mqueue->queues = g_list_append (mqueue->queues, squeue);
  10.421 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mqueue);
  10.422 +
  10.423 +  /*
  10.424 +  GST_DEBUG_OBJECT (mqueue, "Returning pad %s:%s",
  10.425 +      GST_DEBUG_PAD_NAME (squeue->sinkpad));
  10.426 +    */
  10.427 +  return squeue->sinkpad;
  10.428 +}
  10.429 +
  10.430 +static void
  10.431 +gst_multi_queue_release_pad (GstElement * element, GstPad * pad)
  10.432 +{
  10.433 +  GstMultiQueue *mqueue = GST_MULTI_QUEUE (element);
  10.434 +  GstSingleQueue *sq = NULL;
  10.435 +  GList *tmp;
  10.436 +
  10.437 +//  GST_LOG_OBJECT (element, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
  10.438 +
  10.439 +  GST_MULTI_QUEUE_MUTEX_LOCK (mqueue);
  10.440 +  /* Find which single queue it belongs to, knowing that it should be a sinkpad */
  10.441 +  for (tmp = mqueue->queues; tmp; tmp = g_list_next (tmp)) {
  10.442 +    sq = (GstSingleQueue *) tmp->data;
  10.443 +
  10.444 +    if (sq->sinkpad == pad)
  10.445 +      break;
  10.446 +  }
  10.447 +
  10.448 +  if (!tmp) {
  10.449 +    GST_WARNING_OBJECT (mqueue, "That pad doesn't belong to this element ???");
  10.450 +    GST_MULTI_QUEUE_MUTEX_UNLOCK (mqueue);
  10.451 +    return;
  10.452 +  }
  10.453 +
  10.454 +  /* FIXME: The removal of the singlequeue should probably not happen until it
  10.455 +   * finishes draining */
  10.456 +
  10.457 +  /* remove it from the list */
  10.458 +  mqueue->queues = g_list_delete_link (mqueue->queues, tmp);
  10.459 +
  10.460 +  /* FIXME : recompute next-non-linked */
  10.461 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mqueue);
  10.462 +
  10.463 +  /* delete SingleQueue */
  10.464 +  gst_data_queue_set_flushing (sq->queue, TRUE);
  10.465 +
  10.466 +  gst_pad_set_active (sq->srcpad, FALSE);
  10.467 +  gst_pad_set_active (sq->sinkpad, FALSE);
  10.468 +  gst_element_remove_pad (element, sq->srcpad);
  10.469 +  gst_element_remove_pad (element, sq->sinkpad);
  10.470 +  gst_single_queue_free (sq);
  10.471 +}
  10.472 +
  10.473 +static gboolean
  10.474 +gst_single_queue_flush (GstMultiQueue * mq, GstSingleQueue * sq, gboolean flush)
  10.475 +{
  10.476 +  gboolean result;
  10.477 +
  10.478 +  GST_DEBUG_OBJECT (mq, "flush %s queue %d", (flush ? "start" : "stop"),
  10.479 +      sq->id);
  10.480 +
  10.481 +  if (flush) {
  10.482 +    sq->srcresult = GST_FLOW_WRONG_STATE;
  10.483 +    gst_data_queue_set_flushing (sq->queue, TRUE);
  10.484 +
  10.485 +    /* wake up non-linked task */
  10.486 +    GST_LOG_OBJECT (mq, "SingleQueue %d : waking up eventually waiting task",
  10.487 +        sq->id);
  10.488 +    GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.489 +    g_cond_signal (sq->turn);
  10.490 +    GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.491 +
  10.492 +    GST_LOG_OBJECT (mq, "SingleQueue %d : pausing task", sq->id);
  10.493 +    result = gst_pad_pause_task (sq->srcpad);
  10.494 +  } else {
  10.495 +    gst_data_queue_flush (sq->queue);
  10.496 +    gst_segment_init (&sq->sink_segment, GST_FORMAT_TIME);
  10.497 +    gst_segment_init (&sq->src_segment, GST_FORMAT_TIME);
  10.498 +    /* All pads start off not-linked for a smooth kick-off */
  10.499 +    sq->srcresult = GST_FLOW_NOT_LINKED;
  10.500 +    sq->cur_time = 0;
  10.501 +    sq->max_size.visible = mq->max_size.visible;
  10.502 +    sq->is_eos = FALSE;
  10.503 +    sq->inextra = FALSE;
  10.504 +    sq->nextid = 0;
  10.505 +    sq->oldid = 0;
  10.506 +    gst_data_queue_set_flushing (sq->queue, FALSE);
  10.507 +
  10.508 +    GST_LOG_OBJECT (mq, "SingleQueue %d : starting task", sq->id);
  10.509 +    result =
  10.510 +        gst_pad_start_task (sq->srcpad, (GstTaskFunction) gst_multi_queue_loop,
  10.511 +        sq->srcpad);
  10.512 +  }
  10.513 +  return result;
  10.514 +}
  10.515 +
  10.516 +/* calculate the diff between running time on the sink and src of the queue.
  10.517 + * This is the total amount of time in the queue. 
  10.518 + * WITH LOCK TAKEN */
  10.519 +static void
  10.520 +update_time_level (GstMultiQueue * mq, GstSingleQueue * sq)
  10.521 +{
  10.522 +  gint64 sink_time, src_time;
  10.523 +
  10.524 +  sink_time =
  10.525 +      gst_segment_to_running_time (&sq->sink_segment, GST_FORMAT_TIME,
  10.526 +      sq->sink_segment.last_stop);
  10.527 +
  10.528 +  src_time = gst_segment_to_running_time (&sq->src_segment, GST_FORMAT_TIME,
  10.529 +      sq->src_segment.last_stop);
  10.530 +
  10.531 +  GST_DEBUG_OBJECT (mq,
  10.532 +      "queue %d, sink %" GST_TIME_FORMAT ", src %" GST_TIME_FORMAT, sq->id,
  10.533 +      GST_TIME_ARGS (sink_time), GST_TIME_ARGS (src_time));
  10.534 +
  10.535 +  /* This allows for streams with out of order timestamping - sometimes the 
  10.536 +   * emerging timestamp is later than the arriving one(s) */
  10.537 +  if (sink_time >= src_time)
  10.538 +    sq->cur_time = sink_time - src_time;
  10.539 +  else
  10.540 +    sq->cur_time = 0;
  10.541 +}
  10.542 +
  10.543 +/* take a NEWSEGMENT event and apply the values to segment, updating the time
  10.544 + * level of queue. */
  10.545 +static void
  10.546 +apply_segment (GstMultiQueue * mq, GstSingleQueue * sq, GstEvent * event,
  10.547 +    GstSegment * segment)
  10.548 +{
  10.549 +  gboolean update;
  10.550 +  GstFormat format;
  10.551 +  gdouble rate, arate;
  10.552 +  gint64 start, stop, time;
  10.553 +
  10.554 +  gst_event_parse_new_segment_full (event, &update, &rate, &arate,
  10.555 +      &format, &start, &stop, &time);
  10.556 +
  10.557 +  /* now configure the values, we use these to track timestamps on the
  10.558 +   * sinkpad. */
  10.559 +  if (format != GST_FORMAT_TIME) {
  10.560 +    /* non-time format, pretent the current time segment is closed with a
  10.561 +     * 0 start and unknown stop time. */
  10.562 +    update = FALSE;
  10.563 +    format = GST_FORMAT_TIME;
  10.564 +    start = 0;
  10.565 +    stop = -1;
  10.566 +    time = 0;
  10.567 +  }
  10.568 +
  10.569 +  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.570 +
  10.571 +  gst_segment_set_newsegment_full (segment, update,
  10.572 +      rate, arate, format, start, stop, time);
  10.573 +
  10.574 +  GST_DEBUG_OBJECT (mq,
  10.575 +      "queue %d, configured NEWSEGMENT %" GST_SEGMENT_FORMAT, sq->id, segment);
  10.576 +
  10.577 +  /* segment can update the time level of the queue */
  10.578 +  update_time_level (mq, sq);
  10.579 +
  10.580 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.581 +}
  10.582 +
  10.583 +/* take a buffer and update segment, updating the time level of the queue. */
  10.584 +static void
  10.585 +apply_buffer (GstMultiQueue * mq, GstSingleQueue * sq, GstClockTime timestamp,
  10.586 +    GstClockTime duration, GstSegment * segment)
  10.587 +{
  10.588 +  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.589 +
  10.590 +  /* if no timestamp is set, assume it's continuous with the previous 
  10.591 +   * time */
  10.592 +  if (timestamp == GST_CLOCK_TIME_NONE)
  10.593 +    timestamp = segment->last_stop;
  10.594 +
  10.595 +  /* add duration */
  10.596 +  if (duration != GST_CLOCK_TIME_NONE)
  10.597 +    timestamp += duration;
  10.598 +
  10.599 +  GST_DEBUG_OBJECT (mq, "queue %d, last_stop updated to %" GST_TIME_FORMAT,
  10.600 +      sq->id, GST_TIME_ARGS (timestamp));
  10.601 +
  10.602 +  gst_segment_set_last_stop (segment, GST_FORMAT_TIME, timestamp);
  10.603 +
  10.604 +  /* calc diff with other end */
  10.605 +  update_time_level (mq, sq);
  10.606 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.607 +}
  10.608 +
  10.609 +static GstFlowReturn
  10.610 +gst_single_queue_push_one (GstMultiQueue * mq, GstSingleQueue * sq,
  10.611 +    GstMiniObject * object)
  10.612 +{
  10.613 +  GstFlowReturn result = GST_FLOW_OK;
  10.614 +
  10.615 +  if (GST_IS_BUFFER (object)) {
  10.616 +    GstBuffer *buffer;
  10.617 +    GstClockTime timestamp, duration;
  10.618 +
  10.619 +    buffer = GST_BUFFER_CAST (object);
  10.620 +    timestamp = GST_BUFFER_TIMESTAMP (buffer);
  10.621 +    duration = GST_BUFFER_DURATION (buffer);
  10.622 +
  10.623 +    apply_buffer (mq, sq, timestamp, duration, &sq->src_segment);
  10.624 +
  10.625 +    /* Applying the buffer may have made the queue non-full again, unblock it if needed */
  10.626 +    gst_data_queue_limits_changed (sq->queue);
  10.627 +
  10.628 +    GST_DEBUG_OBJECT (mq,
  10.629 +        "SingleQueue %d : Pushing buffer %p with ts %" GST_TIME_FORMAT,
  10.630 +        sq->id, buffer, GST_TIME_ARGS (timestamp));
  10.631 +
  10.632 +    result = gst_pad_push (sq->srcpad, buffer);
  10.633 +  } else if (GST_IS_EVENT (object)) {
  10.634 +    GstEvent *event;
  10.635 +
  10.636 +    event = GST_EVENT_CAST (object);
  10.637 +
  10.638 +    switch (GST_EVENT_TYPE (event)) {
  10.639 +      case GST_EVENT_EOS:
  10.640 +        result = GST_FLOW_UNEXPECTED;
  10.641 +        break;
  10.642 +      case GST_EVENT_NEWSEGMENT:
  10.643 +        apply_segment (mq, sq, event, &sq->src_segment);
  10.644 +        /* Applying the segment may have made the queue non-full again, unblock it if needed */
  10.645 +        gst_data_queue_limits_changed (sq->queue);
  10.646 +        break;
  10.647 +      default:
  10.648 +        break;
  10.649 +    }
  10.650 +
  10.651 +    GST_DEBUG_OBJECT (mq,
  10.652 +        "SingleQueue %d : Pushing event %p of type %s",
  10.653 +        sq->id, event, GST_EVENT_TYPE_NAME (event));
  10.654 +
  10.655 +    gst_pad_push_event (sq->srcpad, event);
  10.656 +  } else {
  10.657 +    g_warning ("Unexpected object in singlequeue %d (refcounting problem?)",
  10.658 +        sq->id);
  10.659 +  }
  10.660 +  return result;
  10.661 +
  10.662 +  /* ERRORS */
  10.663 +}
  10.664 +
  10.665 +static GstMiniObject *
  10.666 +gst_multi_queue_item_steal_object (GstMultiQueueItem * item)
  10.667 +{
  10.668 +  GstMiniObject *res;
  10.669 +
  10.670 +  res = item->object;
  10.671 +  item->object = NULL;
  10.672 +
  10.673 +  return res;
  10.674 +}
  10.675 +
  10.676 +static void
  10.677 +gst_multi_queue_item_destroy (GstMultiQueueItem * item)
  10.678 +{
  10.679 +  if (item->object)
  10.680 +    gst_mini_object_unref (item->object);
  10.681 +  g_free (item);
  10.682 +}
  10.683 +
  10.684 +/* takes ownership of passed mini object! */
  10.685 +static GstMultiQueueItem *
  10.686 +gst_multi_queue_item_new (GstMiniObject * object, guint32 curid)
  10.687 +{
  10.688 +  GstMultiQueueItem *item;
  10.689 +
  10.690 +  item = g_new (GstMultiQueueItem, 1);
  10.691 +  item->object = object;
  10.692 +  item->destroy = (GDestroyNotify) gst_multi_queue_item_destroy;
  10.693 +  item->posid = curid;
  10.694 +
  10.695 +  if (GST_IS_BUFFER (object)) {
  10.696 +    item->size = GST_BUFFER_SIZE (object);
  10.697 +    item->duration = GST_BUFFER_DURATION (object);
  10.698 +    if (item->duration == GST_CLOCK_TIME_NONE)
  10.699 +      item->duration = 0;
  10.700 +    item->visible = TRUE;
  10.701 +  } else {
  10.702 +    item->size = 0;
  10.703 +    item->duration = 0;
  10.704 +    item->visible = FALSE;
  10.705 +  }
  10.706 +  return item;
  10.707 +}
  10.708 +
  10.709 +/* Each main loop attempts to push buffers until the return value
  10.710 + * is not-linked. not-linked pads are not allowed to push data beyond
  10.711 + * any linked pads, so they don't 'rush ahead of the pack'.
  10.712 + */
  10.713 +static void
  10.714 +gst_multi_queue_loop (GstPad * pad)
  10.715 +{
  10.716 +  GstSingleQueue *sq;
  10.717 +  GstMultiQueueItem *item;
  10.718 +  GstDataQueueItem *sitem;
  10.719 +  GstMultiQueue *mq;
  10.720 +  GstMiniObject *object;
  10.721 +  guint32 newid;
  10.722 +  guint32 oldid = -1;
  10.723 +  GstFlowReturn result;
  10.724 +
  10.725 +  sq = (GstSingleQueue *) gst_pad_get_element_private (pad);
  10.726 +  mq = sq->mqueue;
  10.727 +
  10.728 +  do {
  10.729 +    GST_DEBUG_OBJECT (mq, "SingleQueue %d : trying to pop an object", sq->id);
  10.730 +
  10.731 +    /* Get something from the queue, blocking until that happens, or we get
  10.732 +     * flushed */
  10.733 +    if (!(gst_data_queue_pop (sq->queue, &sitem)))
  10.734 +      goto out_flushing;
  10.735 +
  10.736 +    item = (GstMultiQueueItem *) sitem;
  10.737 +    newid = item->posid;
  10.738 +
  10.739 +    /* steal the object and destroy the item */
  10.740 +    object = gst_multi_queue_item_steal_object (item);
  10.741 +    gst_multi_queue_item_destroy (item);
  10.742 +
  10.743 +    GST_LOG_OBJECT (mq, "SingleQueue %d : newid:%d , oldid:%d",
  10.744 +        sq->id, newid, oldid);
  10.745 +
  10.746 +    /* If we're not-linked, we do some extra work because we might need to
  10.747 +     * wait before pushing. If we're linked but there's a gap in the IDs,
  10.748 +     * or it's the first loop, or we just passed the previous highid, 
  10.749 +     * we might need to wake some sleeping pad up, so there's extra work 
  10.750 +     * there too */
  10.751 +    if (sq->srcresult == GST_FLOW_NOT_LINKED ||
  10.752 +        (oldid == -1) || (newid != (oldid + 1)) || oldid > mq->highid) {
  10.753 +      GST_LOG_OBJECT (mq, "CHECKING sq->srcresult: %s",
  10.754 +          gst_flow_get_name (sq->srcresult));
  10.755 +
  10.756 +      GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.757 +
  10.758 +      /* Update the nextid so other threads know when to wake us up */
  10.759 +      sq->nextid = newid;
  10.760 +
  10.761 +      /* Update the oldid (the last ID we output) for highid tracking */
  10.762 +      if (oldid != -1)
  10.763 +        sq->oldid = oldid;
  10.764 +
  10.765 +      if (sq->srcresult == GST_FLOW_NOT_LINKED) {
  10.766 +        /* Go to sleep until it's time to push this buffer */
  10.767 +
  10.768 +        /* Recompute the highid */
  10.769 +        compute_high_id (mq);
  10.770 +        while (newid > mq->highid && sq->srcresult == GST_FLOW_NOT_LINKED) {
  10.771 +          GST_DEBUG_OBJECT (mq, "queue %d sleeping for not-linked wakeup with "
  10.772 +              "newid %u and highid %u", sq->id, newid, mq->highid);
  10.773 +
  10.774 +
  10.775 +          /* Wake up all non-linked pads before we sleep */
  10.776 +          wake_up_next_non_linked (mq);
  10.777 +
  10.778 +          mq->numwaiting++;
  10.779 +          g_cond_wait (sq->turn, mq->qlock);
  10.780 +          mq->numwaiting--;
  10.781 +
  10.782 +          GST_DEBUG_OBJECT (mq, "queue %d woken from sleeping for not-linked "
  10.783 +              "wakeup with newid %u and highid %u", sq->id, newid, mq->highid);
  10.784 +        }
  10.785 +
  10.786 +        /* Re-compute the high_id in case someone else pushed */
  10.787 +        compute_high_id (mq);
  10.788 +      } else {
  10.789 +        compute_high_id (mq);
  10.790 +        /* Wake up all non-linked pads */
  10.791 +        wake_up_next_non_linked (mq);
  10.792 +      }
  10.793 +      /* We're done waiting, we can clear the nextid */
  10.794 +      sq->nextid = 0;
  10.795 +
  10.796 +      GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.797 +    }
  10.798 +
  10.799 +    GST_LOG_OBJECT (mq, "BEFORE PUSHING sq->srcresult: %s",
  10.800 +        gst_flow_get_name (sq->srcresult));
  10.801 +
  10.802 +    /* Try to push out the new object */
  10.803 +    result = gst_single_queue_push_one (mq, sq, object);
  10.804 +    sq->srcresult = result;
  10.805 +
  10.806 +    if (result != GST_FLOW_OK && result != GST_FLOW_NOT_LINKED)
  10.807 +      goto out_flushing;
  10.808 +
  10.809 +    GST_LOG_OBJECT (mq, "AFTER PUSHING sq->srcresult: %s",
  10.810 +        gst_flow_get_name (sq->srcresult));
  10.811 +
  10.812 +    oldid = newid;
  10.813 +  }
  10.814 +  while (TRUE);
  10.815 +
  10.816 +out_flushing:
  10.817 +  {
  10.818 +    /* Need to make sure wake up any sleeping pads when we exit */
  10.819 +    GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.820 +    compute_high_id (mq);
  10.821 +    wake_up_next_non_linked (mq);
  10.822 +    GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.823 +
  10.824 +    gst_data_queue_set_flushing (sq->queue, TRUE);
  10.825 +    gst_pad_pause_task (sq->srcpad);
  10.826 +    GST_CAT_LOG_OBJECT (multi_queue_debug, mq,
  10.827 +        "SingleQueue[%d] task paused, reason:%s",
  10.828 +        sq->id, gst_flow_get_name (sq->srcresult));
  10.829 +    return;
  10.830 +  }
  10.831 +}
  10.832 +
  10.833 +/**
  10.834 + * gst_multi_queue_chain:
  10.835 + *
  10.836 + * This is similar to GstQueue's chain function, except:
  10.837 + * _ we don't have leak behavioures,
  10.838 + * _ we push with a unique id (curid)
  10.839 + */
  10.840 +static GstFlowReturn
  10.841 +gst_multi_queue_chain (GstPad * pad, GstBuffer * buffer)
  10.842 +{
  10.843 +  GstSingleQueue *sq;
  10.844 +  GstMultiQueue *mq;
  10.845 +  GstMultiQueueItem *item;
  10.846 +  GstFlowReturn ret = GST_FLOW_OK;
  10.847 +  guint32 curid;
  10.848 +  GstClockTime timestamp, duration;
  10.849 +
  10.850 +  sq = gst_pad_get_element_private (pad);
  10.851 +  mq = (GstMultiQueue *) gst_pad_get_parent (pad);
  10.852 +
  10.853 +  /* Get a unique incrementing id */
  10.854 +  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.855 +  curid = mq->counter++;
  10.856 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.857 +
  10.858 +  GST_LOG_OBJECT (mq, "SingleQueue %d : about to enqueue buffer %p with id %d",
  10.859 +      sq->id, buffer, curid);
  10.860 +
  10.861 +  item = gst_multi_queue_item_new (GST_MINI_OBJECT_CAST (buffer), curid);
  10.862 +
  10.863 +  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  10.864 +  duration = GST_BUFFER_DURATION (buffer);
  10.865 +
  10.866 +  if (!(gst_data_queue_push (sq->queue, (GstDataQueueItem *) item)))
  10.867 +    goto flushing;
  10.868 +
  10.869 +  /* update time level, we must do this after pushing the data in the queue so
  10.870 +   * that we never end up filling the queue first. */
  10.871 +  apply_buffer (mq, sq, timestamp, duration, &sq->sink_segment);
  10.872 +
  10.873 +done:
  10.874 +  gst_object_unref (mq);
  10.875 +
  10.876 +  return ret;
  10.877 +
  10.878 +  /* ERRORS */
  10.879 +flushing:
  10.880 +  {
  10.881 +    ret = sq->srcresult;
  10.882 +    GST_LOG_OBJECT (mq, "SingleQueue %d : exit because task paused, reason: %s",
  10.883 +        sq->id, gst_flow_get_name (ret));
  10.884 +    gst_multi_queue_item_destroy (item);
  10.885 +    goto done;
  10.886 +  }
  10.887 +}
  10.888 +
  10.889 +static gboolean
  10.890 +gst_multi_queue_sink_activate_push (GstPad * pad, gboolean active)
  10.891 +{
  10.892 +  GstSingleQueue *sq;
  10.893 +
  10.894 +  sq = (GstSingleQueue *) gst_pad_get_element_private (pad);
  10.895 +
  10.896 +  if (active) {
  10.897 +    /* All pads start off not-linked for a smooth kick-off */
  10.898 +    sq->srcresult = GST_FLOW_NOT_LINKED;
  10.899 +  } else {
  10.900 +    sq->srcresult = GST_FLOW_WRONG_STATE;
  10.901 +    gst_data_queue_flush (sq->queue);
  10.902 +  }
  10.903 +  return TRUE;
  10.904 +}
  10.905 +
  10.906 +static gboolean
  10.907 +gst_multi_queue_sink_event (GstPad * pad, GstEvent * event)
  10.908 +{
  10.909 +  GstSingleQueue *sq;
  10.910 +  GstMultiQueue *mq;
  10.911 +  guint32 curid;
  10.912 +  GstMultiQueueItem *item;
  10.913 +  gboolean res;
  10.914 +  GstEventType type;
  10.915 +  GstEvent *sref = NULL;
  10.916 +
  10.917 +  sq = (GstSingleQueue *) gst_pad_get_element_private (pad);
  10.918 +  mq = (GstMultiQueue *) gst_pad_get_parent (pad);
  10.919 +
  10.920 +  type = GST_EVENT_TYPE (event);
  10.921 +
  10.922 +  switch (type) {
  10.923 +    case GST_EVENT_FLUSH_START:
  10.924 +      GST_DEBUG_OBJECT (mq, "SingleQueue %d : received flush start event",
  10.925 +          sq->id);
  10.926 +
  10.927 +      res = gst_pad_push_event (sq->srcpad, event);
  10.928 +
  10.929 +      gst_single_queue_flush (mq, sq, TRUE);
  10.930 +      goto done;
  10.931 +
  10.932 +    case GST_EVENT_FLUSH_STOP:
  10.933 +      GST_DEBUG_OBJECT (mq, "SingleQueue %d : received flush stop event",
  10.934 +          sq->id);
  10.935 +
  10.936 +      res = gst_pad_push_event (sq->srcpad, event);
  10.937 +
  10.938 +      gst_single_queue_flush (mq, sq, FALSE);
  10.939 +      goto done;
  10.940 +    case GST_EVENT_NEWSEGMENT:
  10.941 +      /* take ref because the queue will take ownership and we need the event
  10.942 +       * afterwards to update the segment */
  10.943 +      sref = gst_event_ref (event);
  10.944 +      break;
  10.945 +
  10.946 +    default:
  10.947 +      if (!(GST_EVENT_IS_SERIALIZED (event))) {
  10.948 +        res = gst_pad_push_event (sq->srcpad, event);
  10.949 +        goto done;
  10.950 +      }
  10.951 +      break;
  10.952 +  }
  10.953 +
  10.954 +  /* Get an unique incrementing id */
  10.955 +  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
  10.956 +  curid = mq->counter++;
  10.957 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
  10.958 +
  10.959 +  item = gst_multi_queue_item_new ((GstMiniObject *) event, curid);
  10.960 +
  10.961 +  GST_DEBUG_OBJECT (mq,
  10.962 +      "SingleQueue %d : Enqueuing event %p of type %s with id %d",
  10.963 +      sq->id, event, GST_EVENT_TYPE_NAME (event), curid);
  10.964 +
  10.965 +  if (!(res = gst_data_queue_push (sq->queue, (GstDataQueueItem *) item)))
  10.966 +    goto flushing;
  10.967 +
  10.968 +  /* mark EOS when we received one, we must do that after putting the
  10.969 +   * buffer in the queue because EOS marks the buffer as filled. No need to take
  10.970 +   * a lock, the _check_full happens from this thread only, right before pushing
  10.971 +   * into dataqueue. */
  10.972 +  switch (type) {
  10.973 +    case GST_EVENT_EOS:
  10.974 +      sq->is_eos = TRUE;
  10.975 +      break;
  10.976 +    case GST_EVENT_NEWSEGMENT:
  10.977 +      apply_segment (mq, sq, sref, &sq->sink_segment);
  10.978 +      gst_event_unref (sref);
  10.979 +      break;
  10.980 +    default:
  10.981 +      break;
  10.982 +  }
  10.983 +done:
  10.984 +  gst_object_unref (mq);
  10.985 +  return res;
  10.986 +
  10.987 +flushing:
  10.988 +  {
  10.989 +    GST_LOG_OBJECT (mq, "SingleQueue %d : exit because task paused, reason: %s",
  10.990 +        sq->id, gst_flow_get_name (sq->srcresult));
  10.991 +    if (sref)
  10.992 +      gst_event_unref (sref);
  10.993 +    gst_multi_queue_item_destroy (item);
  10.994 +    goto done;
  10.995 +  }
  10.996 +}
  10.997 +
  10.998 +static GstCaps *
  10.999 +gst_multi_queue_getcaps (GstPad * pad)
 10.1000 +{
 10.1001 +  GstSingleQueue *sq = gst_pad_get_element_private (pad);
 10.1002 +  GstPad *otherpad;
 10.1003 +  GstCaps *result;
 10.1004 +
 10.1005 +  otherpad = (pad == sq->srcpad) ? sq->sinkpad : sq->srcpad;
 10.1006 +
 10.1007 +  GST_LOG_OBJECT (otherpad, "Getting caps from the peer of this pad");
 10.1008 +
 10.1009 +  result = gst_pad_peer_get_caps (otherpad);
 10.1010 +  if (result == NULL)
 10.1011 +    result = gst_caps_new_any ();
 10.1012 +
 10.1013 +  return result;
 10.1014 +}
 10.1015 +
 10.1016 +static GstFlowReturn
 10.1017 +gst_multi_queue_bufferalloc (GstPad * pad, guint64 offset, guint size,
 10.1018 +    GstCaps * caps, GstBuffer ** buf)
 10.1019 +{
 10.1020 +  GstSingleQueue *sq = gst_pad_get_element_private (pad);
 10.1021 +
 10.1022 +  return gst_pad_alloc_buffer (sq->srcpad, offset, size, caps, buf);
 10.1023 +}
 10.1024 +
 10.1025 +static gboolean
 10.1026 +gst_multi_queue_src_activate_push (GstPad * pad, gboolean active)
 10.1027 +{
 10.1028 +  GstMultiQueue *mq;
 10.1029 +  GstSingleQueue *sq;
 10.1030 +  gboolean result = FALSE;
 10.1031 +
 10.1032 +  sq = (GstSingleQueue *) gst_pad_get_element_private (pad);
 10.1033 +  mq = sq->mqueue;
 10.1034 +
 10.1035 +  GST_DEBUG_OBJECT (mq, "SingleQueue %d", sq->id);
 10.1036 +
 10.1037 +  if (active) {
 10.1038 +    result = gst_single_queue_flush (mq, sq, FALSE);
 10.1039 +  } else {
 10.1040 +    result = gst_single_queue_flush (mq, sq, TRUE);
 10.1041 +    /* make sure streaming finishes */
 10.1042 +    result |= gst_pad_stop_task (pad);
 10.1043 +  }
 10.1044 +  return result;
 10.1045 +}
 10.1046 +
 10.1047 +static gboolean
 10.1048 +gst_multi_queue_acceptcaps (GstPad * pad, GstCaps * caps)
 10.1049 +{
 10.1050 +  return TRUE;
 10.1051 +}
 10.1052 +
 10.1053 +static gboolean
 10.1054 +gst_multi_queue_src_event (GstPad * pad, GstEvent * event)
 10.1055 +{
 10.1056 +  GstSingleQueue *sq = gst_pad_get_element_private (pad);
 10.1057 +
 10.1058 +  return gst_pad_push_event (sq->sinkpad, event);
 10.1059 +}
 10.1060 +
 10.1061 +static gboolean
 10.1062 +gst_multi_queue_src_query (GstPad * pad, GstQuery * query)
 10.1063 +{
 10.1064 +  GstSingleQueue *sq = gst_pad_get_element_private (pad);
 10.1065 +  GstPad *peerpad;
 10.1066 +  gboolean res;
 10.1067 +
 10.1068 +  /* FIXME, Handle position offset depending on queue size */
 10.1069 +
 10.1070 +  /* default handling */
 10.1071 +  if (!(peerpad = gst_pad_get_peer (sq->sinkpad)))
 10.1072 +    goto no_peer;
 10.1073 +
 10.1074 +  res = gst_pad_query (peerpad, query);
 10.1075 +
 10.1076 +  gst_object_unref (peerpad);
 10.1077 +
 10.1078 +  return res;
 10.1079 +
 10.1080 +  /* ERRORS */
 10.1081 +no_peer:
 10.1082 +  {
 10.1083 +    GST_LOG_OBJECT (sq->sinkpad, "Couldn't send query because we have no peer");
 10.1084 +    return FALSE;
 10.1085 +  }
 10.1086 +}
 10.1087 +
 10.1088 +/*
 10.1089 + * Next-non-linked functions
 10.1090 + */
 10.1091 +
 10.1092 +/* WITH LOCK TAKEN */
 10.1093 +static void
 10.1094 +wake_up_next_non_linked (GstMultiQueue * mq)
 10.1095 +{
 10.1096 +  GList *tmp;
 10.1097 +
 10.1098 +  /* maybe no-one is waiting */
 10.1099 +  if (mq->numwaiting < 1)
 10.1100 +    return;
 10.1101 +
 10.1102 +  /* Else figure out which singlequeue(s) need waking up */
 10.1103 +  for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) {
 10.1104 +    GstSingleQueue *sq = (GstSingleQueue *) tmp->data;
 10.1105 +
 10.1106 +    if (sq->srcresult == GST_FLOW_NOT_LINKED) {
 10.1107 +      if (sq->nextid != 0 && sq->nextid <= mq->highid) {
 10.1108 +        GST_LOG_OBJECT (mq, "Waking up singlequeue %d", sq->id);
 10.1109 +        g_cond_signal (sq->turn);
 10.1110 +      }
 10.1111 +    }
 10.1112 +  }
 10.1113 +}
 10.1114 +
 10.1115 +/* WITH LOCK TAKEN */
 10.1116 +static void
 10.1117 +compute_high_id (GstMultiQueue * mq)
 10.1118 +{
 10.1119 +  /* The high-id is either the highest id among the linked pads, or if all
 10.1120 +   * pads are not-linked, it's the lowest not-linked pad */
 10.1121 +  GList *tmp;
 10.1122 +  guint32 lowest = G_MAXUINT32;
 10.1123 +  guint32 highid = G_MAXUINT32;
 10.1124 +
 10.1125 +  for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) {
 10.1126 +    GstSingleQueue *sq = (GstSingleQueue *) tmp->data;
 10.1127 +
 10.1128 +    GST_LOG_OBJECT (mq, "inspecting sq:%d , nextid:%d, oldid:%d, srcresult:%s",
 10.1129 +        sq->id, sq->nextid, sq->oldid, gst_flow_get_name (sq->srcresult));
 10.1130 +
 10.1131 +    if (sq->srcresult == GST_FLOW_NOT_LINKED) {
 10.1132 +      /* No need to consider queues which are not waiting */
 10.1133 +      if (sq->nextid == 0) {
 10.1134 +        GST_LOG_OBJECT (mq, "sq:%d is not waiting - ignoring", sq->id);
 10.1135 +        continue;
 10.1136 +      }
 10.1137 +
 10.1138 +      if (sq->nextid < lowest)
 10.1139 +        lowest = sq->nextid;
 10.1140 +    } else if (sq->srcresult != GST_FLOW_UNEXPECTED) {
 10.1141 +      /* If we don't have a global highid, or the global highid is lower than
 10.1142 +       * this single queue's last outputted id, store the queue's one, 
 10.1143 +       * unless the singlequeue is at EOS (srcresult = UNEXPECTED) */
 10.1144 +      if ((highid == G_MAXUINT32) || (sq->oldid > highid))
 10.1145 +        highid = sq->oldid;
 10.1146 +    }
 10.1147 +  }
 10.1148 +
 10.1149 +  if (highid == G_MAXUINT32 || lowest < highid)
 10.1150 +    mq->highid = lowest;
 10.1151 +  else
 10.1152 +    mq->highid = highid;
 10.1153 +
 10.1154 +  GST_LOG_OBJECT (mq, "Highid is now : %u, lowest non-linked %u", mq->highid,
 10.1155 +      lowest);
 10.1156 +}
 10.1157 +
 10.1158 +#define IS_FILLED(format, value) ((sq->max_size.format) != 0 && \
 10.1159 +     (sq->max_size.format) <= (value))
 10.1160 +
 10.1161 +/*
 10.1162 + * GstSingleQueue functions
 10.1163 + */
 10.1164 +static void
 10.1165 +single_queue_overrun_cb (GstDataQueue * dq, GstSingleQueue * sq)
 10.1166 +{
 10.1167 +  GstMultiQueue *mq = sq->mqueue;
 10.1168 +  GList *tmp;
 10.1169 +  GstDataQueueSize size;
 10.1170 +  gboolean filled = FALSE;
 10.1171 +
 10.1172 +  gst_data_queue_get_level (sq->queue, &size);
 10.1173 +
 10.1174 +  GST_LOG_OBJECT (mq, "Single Queue %d is full", sq->id);
 10.1175 +
 10.1176 +  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
 10.1177 +  for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) {
 10.1178 +    GstSingleQueue *ssq = (GstSingleQueue *) tmp->data;
 10.1179 +    GstDataQueueSize ssize;
 10.1180 +
 10.1181 +    GST_LOG_OBJECT (mq, "Checking Queue %d", ssq->id);
 10.1182 +
 10.1183 +    if (gst_data_queue_is_empty (ssq->queue)) {
 10.1184 +      GST_LOG_OBJECT (mq, "Queue %d is empty", ssq->id);
 10.1185 +      if (IS_FILLED (visible, size.visible)) {
 10.1186 +        sq->max_size.visible++;
 10.1187 +        GST_DEBUG_OBJECT (mq,
 10.1188 +            "Another queue is empty, bumping single queue %d max visible to %d",
 10.1189 +            sq->id, sq->max_size.visible);
 10.1190 +      }
 10.1191 +      GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
 10.1192 +      goto beach;
 10.1193 +    }
 10.1194 +    /* check if we reached the hard time/bytes limits */
 10.1195 +    gst_data_queue_get_level (ssq->queue, &ssize);
 10.1196 +
 10.1197 +    GST_DEBUG_OBJECT (mq,
 10.1198 +        "queue %d: visible %u/%u, bytes %u/%u, time %" G_GUINT64_FORMAT "/%"
 10.1199 +        G_GUINT64_FORMAT, ssq->id, ssize.visible, sq->max_size.visible,
 10.1200 +        ssize.bytes, sq->max_size.bytes, sq->cur_time, sq->max_size.time);
 10.1201 +
 10.1202 +    /* if this queue is filled completely we must signal overrun */
 10.1203 +    if (IS_FILLED (bytes, ssize.bytes) || IS_FILLED (time, sq->cur_time)) {
 10.1204 +      GST_LOG_OBJECT (mq, "Queue %d is filled", ssq->id);
 10.1205 +      filled = TRUE;
 10.1206 +    }
 10.1207 +  }
 10.1208 +  /* no queues were empty */
 10.1209 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
 10.1210 +
 10.1211 +  /* Overrun is always forwarded, since this is blocking the upstream element */
 10.1212 +  if (filled) {
 10.1213 +    GST_DEBUG_OBJECT (mq, "A queue is filled, signalling overrun");
 10.1214 +    g_signal_emit (G_OBJECT (mq), gst_multi_queue_signals[SIGNAL_OVERRUN], 0);
 10.1215 +  }
 10.1216 +
 10.1217 +beach:
 10.1218 +  return;
 10.1219 +}
 10.1220 +
 10.1221 +static void
 10.1222 +single_queue_underrun_cb (GstDataQueue * dq, GstSingleQueue * sq)
 10.1223 +{
 10.1224 +  gboolean empty = TRUE;
 10.1225 +  GstMultiQueue *mq = sq->mqueue;
 10.1226 +  GList *tmp;
 10.1227 +
 10.1228 +  GST_LOG_OBJECT (mq,
 10.1229 +      "Single Queue %d is empty, Checking other single queues", sq->id);
 10.1230 +
 10.1231 +  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
 10.1232 +  for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) {
 10.1233 +    GstSingleQueue *sq = (GstSingleQueue *) tmp->data;
 10.1234 +
 10.1235 +    if (gst_data_queue_is_full (sq->queue)) {
 10.1236 +      GstDataQueueSize size;
 10.1237 +
 10.1238 +      gst_data_queue_get_level (sq->queue, &size);
 10.1239 +      if (IS_FILLED (visible, size.visible)) {
 10.1240 +        sq->max_size.visible++;
 10.1241 +        GST_DEBUG_OBJECT (mq,
 10.1242 +            "queue %d is filled, bumping its max visible to %d", sq->id,
 10.1243 +            sq->max_size.visible);
 10.1244 +        gst_data_queue_limits_changed (sq->queue);
 10.1245 +      }
 10.1246 +    }
 10.1247 +    if (!gst_data_queue_is_empty (sq->queue))
 10.1248 +      empty = FALSE;
 10.1249 +  }
 10.1250 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
 10.1251 +
 10.1252 +  if (empty) {
 10.1253 +    GST_DEBUG_OBJECT (mq, "All queues are empty, signalling it");
 10.1254 +    g_signal_emit (G_OBJECT (mq), gst_multi_queue_signals[SIGNAL_UNDERRUN], 0);
 10.1255 +  }
 10.1256 +}
 10.1257 +
 10.1258 +static gboolean
 10.1259 +single_queue_check_full (GstDataQueue * dataq, guint visible, guint bytes,
 10.1260 +    guint64 time, GstSingleQueue * sq)
 10.1261 +{
 10.1262 +  gboolean res;
 10.1263 +
 10.1264 +  GST_DEBUG ("queue %d: visible %u/%u, bytes %u/%u, time %" G_GUINT64_FORMAT
 10.1265 +      "/%" G_GUINT64_FORMAT, sq->id, visible, sq->max_size.visible, bytes,
 10.1266 +      sq->max_size.bytes, sq->cur_time, sq->max_size.time);
 10.1267 +
 10.1268 +  /* we are always filled on EOS */
 10.1269 +  if (sq->is_eos)
 10.1270 +    return TRUE;
 10.1271 +
 10.1272 +  /* we never go past the max visible items */
 10.1273 +  if (IS_FILLED (visible, visible))
 10.1274 +    return TRUE;
 10.1275 +
 10.1276 +  if (sq->cur_time != 0) {
 10.1277 +    /* if we have valid time in the queue, check */
 10.1278 +    res = IS_FILLED (time, sq->cur_time);
 10.1279 +  } else {
 10.1280 +    /* no valid time, check bytes */
 10.1281 +    res = IS_FILLED (bytes, bytes);
 10.1282 +  }
 10.1283 +  return res;
 10.1284 +}
 10.1285 +
 10.1286 +static void
 10.1287 +gst_single_queue_free (GstSingleQueue * sq)
 10.1288 +{
 10.1289 +  /* DRAIN QUEUE */
 10.1290 +  gst_data_queue_flush (sq->queue);
 10.1291 +  g_object_unref (sq->queue);
 10.1292 +  g_cond_free (sq->turn);
 10.1293 +  g_free (sq);
 10.1294 +}
 10.1295 +
 10.1296 +static GstSingleQueue *
 10.1297 +gst_single_queue_new (GstMultiQueue * mqueue)
 10.1298 +{
 10.1299 +  GstSingleQueue *sq;
 10.1300 +  gchar *tmp;
 10.1301 +
 10.1302 +  sq = g_new0 (GstSingleQueue, 1);
 10.1303 +
 10.1304 +  GST_MULTI_QUEUE_MUTEX_LOCK (mqueue);
 10.1305 +  sq->id = mqueue->nbqueues++;
 10.1306 +
 10.1307 +  /* copy over max_size and extra_size so we don't need to take the lock
 10.1308 +   * any longer when checking if the queue is full. */
 10.1309 +  sq->max_size.visible = mqueue->max_size.visible;
 10.1310 +  sq->max_size.bytes = mqueue->max_size.bytes;
 10.1311 +  sq->max_size.time = mqueue->max_size.time;
 10.1312 +
 10.1313 +  sq->extra_size.visible = mqueue->extra_size.visible;
 10.1314 +  sq->extra_size.bytes = mqueue->extra_size.bytes;
 10.1315 +  sq->extra_size.time = mqueue->extra_size.time;
 10.1316 +
 10.1317 +  GST_MULTI_QUEUE_MUTEX_UNLOCK (mqueue);
 10.1318 +
 10.1319 +  GST_DEBUG_OBJECT (mqueue, "Creating GstSingleQueue id:%d", sq->id);
 10.1320 +
 10.1321 +  sq->mqueue = mqueue;
 10.1322 +  sq->srcresult = GST_FLOW_WRONG_STATE;
 10.1323 +  sq->queue = gst_data_queue_new ((GstDataQueueCheckFullFunction)
 10.1324 +      single_queue_check_full, sq);
 10.1325 +  sq->is_eos = FALSE;
 10.1326 +  gst_segment_init (&sq->sink_segment, GST_FORMAT_TIME);
 10.1327 +  gst_segment_init (&sq->src_segment, GST_FORMAT_TIME);
 10.1328 +
 10.1329 +  sq->nextid = 0;
 10.1330 +  sq->oldid = 0;
 10.1331 +  sq->turn = g_cond_new ();
 10.1332 +
 10.1333 +  /* attach to underrun/overrun signals to handle non-starvation  */
 10.1334 +  g_signal_connect (G_OBJECT (sq->queue), "full",
 10.1335 +      G_CALLBACK (single_queue_overrun_cb), sq);
 10.1336 +  g_signal_connect (G_OBJECT (sq->queue), "empty",
 10.1337 +      G_CALLBACK (single_queue_underrun_cb), sq);
 10.1338 +
 10.1339 +  tmp = g_strdup_printf ("sink%d", sq->id);
 10.1340 +  sq->sinkpad = gst_pad_new_from_static_template (&sinktemplate, tmp);
 10.1341 +  g_free (tmp);
 10.1342 +
 10.1343 +  gst_pad_set_chain_function (sq->sinkpad,
 10.1344 +      GST_DEBUG_FUNCPTR (gst_multi_queue_chain));
 10.1345 +  gst_pad_set_activatepush_function (sq->sinkpad,
 10.1346 +      GST_DEBUG_FUNCPTR (gst_multi_queue_sink_activate_push));
 10.1347 +  gst_pad_set_event_function (sq->sinkpad,
 10.1348 +      GST_DEBUG_FUNCPTR (gst_multi_queue_sink_event));
 10.1349 +  gst_pad_set_getcaps_function (sq->sinkpad,
 10.1350 +      GST_DEBUG_FUNCPTR (gst_multi_queue_getcaps));
 10.1351 +  gst_pad_set_bufferalloc_function (sq->sinkpad,
 10.1352 +      GST_DEBUG_FUNCPTR (gst_multi_queue_bufferalloc));
 10.1353 +  gst_pad_set_internal_link_function (sq->sinkpad,
 10.1354 +      GST_DEBUG_FUNCPTR (gst_multi_queue_get_internal_links));
 10.1355 +
 10.1356 +  tmp = g_strdup_printf ("src%d", sq->id);
 10.1357 +  sq->srcpad = gst_pad_new_from_static_template (&srctemplate, tmp);
 10.1358 +  g_free (tmp);
 10.1359 +
 10.1360 +  gst_pad_set_activatepush_function (sq->srcpad,
 10.1361 +      GST_DEBUG_FUNCPTR (gst_multi_queue_src_activate_push));
 10.1362 +  gst_pad_set_acceptcaps_function (sq->srcpad,
 10.1363 +      GST_DEBUG_FUNCPTR (gst_multi_queue_acceptcaps));
 10.1364 +  gst_pad_set_getcaps_function (sq->srcpad,
 10.1365 +      GST_DEBUG_FUNCPTR (gst_multi_queue_getcaps));
 10.1366 +  gst_pad_set_event_function (sq->srcpad,
 10.1367 +      GST_DEBUG_FUNCPTR (gst_multi_queue_src_event));
 10.1368 +  gst_pad_set_query_function (sq->srcpad,
 10.1369 +      GST_DEBUG_FUNCPTR (gst_multi_queue_src_query));
 10.1370 +  gst_pad_set_internal_link_function (sq->srcpad,
 10.1371 +      GST_DEBUG_FUNCPTR (gst_multi_queue_get_internal_links));
 10.1372 +
 10.1373 +  gst_pad_set_element_private (sq->sinkpad, (gpointer) sq);
 10.1374 +  gst_pad_set_element_private (sq->srcpad, (gpointer) sq);
 10.1375 +
 10.1376 +  gst_pad_set_active (sq->srcpad, TRUE);
 10.1377 +  gst_element_add_pad (GST_ELEMENT (mqueue), sq->srcpad);
 10.1378 +
 10.1379 +  gst_pad_set_active (sq->sinkpad, TRUE);
 10.1380 +  gst_element_add_pad (GST_ELEMENT (mqueue), sq->sinkpad);
 10.1381 +
 10.1382 +  GST_DEBUG_OBJECT (mqueue, "GstSingleQueue [%d] created and pads added",
 10.1383 +      sq->id);
 10.1384 +
 10.1385 +  return sq;
 10.1386 +}
 10.1387 +
 10.1388 +static gboolean
 10.1389 +plugin_init (GstPlugin * plugin)
 10.1390 +{
 10.1391 +  return gst_element_register (plugin, "multiqueue", GST_RANK_NONE,
 10.1392 +      GST_TYPE_MULTI_QUEUE);
 10.1393 +}
 10.1394 +
 10.1395 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
 10.1396 +    GST_VERSION_MINOR,
 10.1397 +    "multiqueue",
 10.1398 +    "multiqueue", plugin_init, VERSION, GST_LICENSE,
 10.1399 +    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
 10.1400 +
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/gst-gmyth/multiqueue/gstmultiqueue.h	Sat Jul 14 17:20:54 2007 +0100
    11.3 @@ -0,0 +1,86 @@
    11.4 +/* GStreamer
    11.5 + * Copyright (C) 2006 Edward Hervey <edward@fluendo.com>
    11.6 + *
    11.7 + * gstmultiqueue.h:
    11.8 + *
    11.9 + * This library is free software; you can redistribute it and/or
   11.10 + * modify it under the terms of the GNU Library General Public
   11.11 + * License as published by the Free Software Foundation; either
   11.12 + * version 2 of the License, or (at your option) any later version.
   11.13 + *
   11.14 + * This library is distributed in the hope that it will be useful,
   11.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11.17 + * Library General Public License for more details.
   11.18 + *
   11.19 + * You should have received a copy of the GNU Library General Public
   11.20 + * License along with this library; if not, write to the
   11.21 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   11.22 + * Boston, MA 02111-1307, USA.
   11.23 + */
   11.24 +
   11.25 +
   11.26 +#ifndef __GST_MULTI_QUEUE_H__
   11.27 +#define __GST_MULTI_QUEUE_H__
   11.28 +
   11.29 +#include <gst/gst.h>
   11.30 +#include "gstdataqueue.h"
   11.31 +
   11.32 +G_BEGIN_DECLS
   11.33 +
   11.34 +#define GST_TYPE_MULTI_QUEUE \
   11.35 +  (gst_multi_queue_get_type())
   11.36 +#define GST_MULTI_QUEUE(obj) \
   11.37 +  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTI_QUEUE,GstMultiQueue))
   11.38 +#define GST_MULTI_QUEUE_CLASS(klass) \
   11.39 +  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTI_QUEUE,GstMultiQueueClass))
   11.40 +#define GST_IS_MULTI_QUEUE(obj) \
   11.41 +  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTI_QUEUE))
   11.42 +#define GST_IS_MULTI_QUEUE_CLASS(obj) \
   11.43 +  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTI_QUEUE))
   11.44 +
   11.45 +typedef struct _GstMultiQueue GstMultiQueue;
   11.46 +typedef struct _GstMultiQueueClass GstMultiQueueClass;
   11.47 +
   11.48 +/**
   11.49 + * GstMultiQueue:
   11.50 + *
   11.51 + * Opaque #GstMultiQueue structure.
   11.52 + */
   11.53 +struct _GstMultiQueue {
   11.54 +  GstElement element;
   11.55 +
   11.56 +  /* number of queues */
   11.57 +  guint	nbqueues;
   11.58 +
   11.59 +  /* The list of individual queues */
   11.60 +  GList *queues;
   11.61 +
   11.62 +  GstDataQueueSize  max_size, extra_size;
   11.63 +
   11.64 +  guint32  counter;	/* incoming object counter */
   11.65 +  guint32  highid;	/* contains highest id of last outputted object */
   11.66 +
   11.67 +  GMutex * qlock;	/* Global queue lock (vs object lock or individual */
   11.68 +			/* queues lock). Protects nbqueues, queues, global */
   11.69 +			/* GstMultiQueueSize, counter and highid */
   11.70 +
   11.71 +  gint nextnotlinked;	/* ID of the next queue not linked (-1 : none) */
   11.72 +
   11.73 +  gint numwaiting;	/* number of not-linked pads waiting */
   11.74 +};
   11.75 +
   11.76 +struct _GstMultiQueueClass {
   11.77 +  GstElementClass parent_class;
   11.78 +
   11.79 +  /* signals emitted when ALL queues are either full or empty */
   11.80 +  void (*underrun)	(GstMultiQueue *queue);
   11.81 +  void (*overrun)	(GstMultiQueue *queue);
   11.82 +};
   11.83 +
   11.84 +GType gst_multi_queue_get_type (void);
   11.85 +
   11.86 +G_END_DECLS
   11.87 +
   11.88 +
   11.89 +#endif /* __GST_MULTI_QUEUE_H__ */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/gst-gmyth/playbinmaemo/Makefile.am	Sat Jul 14 17:20:54 2007 +0100
    12.3 @@ -0,0 +1,27 @@
    12.4 +plugin_LTLIBRARIES = libgstplaybinmaemo.la
    12.5 +
    12.6 +libgstplaybinmaemo_la_SOURCES =	\
    12.7 +	gstplaybinmaemo.c
    12.8 +
    12.9 +libgstplaybinmaemo_la_CFLAGS = \
   12.10 +	$(GST_CFLAGS) \
   12.11 +	$(GST_BASE_CFLAGS) \
   12.12 +	$(GST_PLUGINS_BASE_CFLAGS) \
   12.13 +	$(X11_CFLAGS)
   12.14 +
   12.15 +libgstplaybinmaemo_la_LIBADD = \
   12.16 +	$(GST_LIBS_LIBS) \
   12.17 +	$(X11_LIBS)
   12.18 +	-lgstinterfaces-0.10
   12.19 +
   12.20 +libgstplaybinmaemo_la_LDFLAGS = \
   12.21 +	$(GST_LIBS) \
   12.22 +	$(GST_PLUGIN_LDFLAGS) \
   12.23 +	$(GST_BASE_LIBS) \
   12.24 +	$(GST_PLUGINS_BASE_LIBS) \
   12.25 +	-lgstinterfaces-0.10 \
   12.26 +	$(X11_LIBS)
   12.27 +
   12.28 +noinst_HEADERS = \
   12.29 +	gstplaybinmaemo.h
   12.30 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/gst-gmyth/playbinmaemo/gstplaybinmaemo.c	Sat Jul 14 17:20:54 2007 +0100
    13.3 @@ -0,0 +1,841 @@
    13.4 +/* GStreamer
    13.5 + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
    13.6 + *
    13.7 + * This library is free software; you can redistribute it and/or
    13.8 + * modify it under the terms of the GNU Library General Public
    13.9 + * License as published by the Free Software Foundation; either
   13.10 + * version 2 of the License, or (at your option) any later version.
   13.11 + *
   13.12 + * This library is distributed in the hope that it will be useful,
   13.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13.15 + * Library General Public License for more details.
   13.16 + *
   13.17 + * You should have received a copy of the GNU Library General Public
   13.18 + * License along with this library; if not, write to the
   13.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   13.20 + * Boston, MA 02111-1307, USA.
   13.21 + */
   13.22 +
   13.23 +#ifdef HAVE_CONFIG_H
   13.24 +#include "config.h"
   13.25 +#endif
   13.26 +
   13.27 +#include <glib/gi18n.h>
   13.28 +#include <string.h>
   13.29 +#include <gst/gst.h>
   13.30 +#include <gst/gsterror.h>
   13.31 +#include <gst/gstplugin.h>
   13.32 +#include <gst/interfaces/xoverlay.h>
   13.33 +#include <X11/Xlib.h>
   13.34 +//#include <gst/pbutils/pbutils.h>
   13.35 +#include "gstplaybinmaemo.h"
   13.36 +
   13.37 +
   13.38 +GST_DEBUG_CATEGORY_STATIC (gst_play_bin_maemo_debug);
   13.39 +#define GST_CAT_DEFAULT gst_play_bin_maemo_debug
   13.40 +
   13.41 +#define DEFAULT_VOLUME               10
   13.42 +#define DEFAULT_XID                 -1
   13.43 +
   13.44 +/* props */
   13.45 +enum
   13.46 +{
   13.47 +  ARG_0,
   13.48 +  ARG_URI,
   13.49 +  ARG_QUEUE_SIZE,
   13.50 +  ARG_QUEUE_MIN_THRESHOLD,
   13.51 +  ARG_SOURCE,
   13.52 +  ARG_VOLUME,
   13.53 +  ARG_XID
   13.54 +};
   13.55 +
   13.56 +static const GstElementDetails gst_play_bin_maemo_details =
   13.57 +        GST_ELEMENT_DETAILS("Nuv demuxer",
   13.58 +                            "Generic/Bin/Player",
   13.59 +                            "Autoplug and play media from an uri used on maemo plataform",
   13.60 +                            "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>");
   13.61 +
   13.62 +static void     gst_play_bin_maemo_dispose          (GObject * object);
   13.63 +static void     gst_play_bin_maemo_finalize         (GObject * object);
   13.64 +static void     gst_play_bin_maemo_set_property     (GObject * object, guint prop_id,
   13.65 +                                                    const GValue * value, GParamSpec * spec);
   13.66 +static void     gst_play_bin_maemo_get_property     (GObject * object, guint prop_id,
   13.67 +                                                    GValue * value, GParamSpec * spec);
   13.68 +static GstStateChangeReturn
   13.69 +                gst_play_bin_maemo_change_state     (GstElement *element,
   13.70 +                                                    GstStateChange transition);
   13.71 +static gboolean factory_filter_sinks                (GstPluginFeature *feature,
   13.72 +                                                    GstPlayBinMaemo *pbm);
   13.73 +static gint     compare_ranks                       (GstPluginFeature * f1,
   13.74 +                                                    GstPluginFeature * f2);
   13.75 +static GList    *find_compatibles                   (GstPlayBinMaemo *pbm,
   13.76 +                                                     const GstCaps *caps);
   13.77 +static GstPad   *find_sink_pad                      (GstElement * element);
   13.78 +static void     update_volume                       (GstPlayBinMaemo *pbm);
   13.79 +static void     update_xid                          (GstPlayBinMaemo *pbm);
   13.80 +static void     new_decoded_pad_cb                  (GstElement *object,
   13.81 +                                                     GstPad* pad,
   13.82 +                                                     gboolean arg,
   13.83 +                                                     gpointer user_data);
   13.84 +static void     unknown_type_cb                     (GstElement *object,
   13.85 +                                                     GstPad *pad,
   13.86 +                                                     GstCaps *casp,
   13.87 +                                                     gpointer user_data);
   13.88 +static gboolean autoplug_continue_cb                (GstElement* object,
   13.89 +                                                     GstCaps* caps,
   13.90 +                                                     gpointer user_data);
   13.91 +static void     decode_new_pad_cb                   (GstElement *element,
   13.92 +                                                     GObject    *new_pad,
   13.93 +                                                     gpointer   user_data);
   13.94 +static void     queue_underrun_cb                   (GstElement* queue,
   13.95 +                                                     gpointer user_data);
   13.96 +static void     queue_sink_underrun_cb              (GstElement* queue,
   13.97 +                                                     gpointer user_data);
   13.98 +static void     queue_sink_overrun_cb               (GstElement* queue,
   13.99 +                                                     gpointer user_data);
  13.100 +
  13.101 +
  13.102 +
  13.103 +
  13.104 +
  13.105 +GST_BOILERPLATE(GstPlayBinMaemo, gst_play_bin_maemo, GstPipeline, GST_TYPE_PIPELINE)
  13.106 +
  13.107 +
  13.108 +static void
  13.109 +gst_play_bin_maemo_base_init (gpointer klass)
  13.110 +{
  13.111 +    GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
  13.112 +
  13.113 +    gst_element_class_set_details (element_class, &gst_play_bin_maemo_details);
  13.114 +}
  13.115 +
  13.116 +static void
  13.117 +gst_play_bin_maemo_class_init (GstPlayBinMaemoClass * klass)
  13.118 +{
  13.119 +  GObjectClass *gobject_klass;
  13.120 +  GstElementClass *gstelement_klass;
  13.121 +  GstBinClass *gstbin_klass;
  13.122 +
  13.123 +  gobject_klass = (GObjectClass *) klass;
  13.124 +  gstelement_klass = (GstElementClass *) klass;
  13.125 +  gstbin_klass = (GstBinClass *) klass;
  13.126 +
  13.127 +  parent_class = g_type_class_peek_parent (klass);
  13.128 +
  13.129 +  gobject_klass->set_property = gst_play_bin_maemo_set_property;
  13.130 +  gobject_klass->get_property = gst_play_bin_maemo_get_property;
  13.131 +
  13.132 +  g_object_class_install_property (gobject_klass, ARG_URI,
  13.133 +      g_param_spec_string ("uri", "URI", "URI of the media to play",
  13.134 +          NULL, G_PARAM_READWRITE));
  13.135 +
  13.136 +  g_object_class_install_property (gobject_klass, ARG_VOLUME,
  13.137 +      g_param_spec_uint ("volume", "Audio volume", "volume",
  13.138 +                         0, 10, (guint) DEFAULT_VOLUME, G_PARAM_READWRITE));
  13.139 +
  13.140 +  g_object_class_install_property (gobject_klass, ARG_XID,
  13.141 +      g_param_spec_long ("xid", "xid", "X windown ID",
  13.142 +                         -1, G_MAXLONG, DEFAULT_XID, G_PARAM_READWRITE));
  13.143 +
  13.144 +  g_object_class_install_property (gobject_klass, ARG_SOURCE,
  13.145 +      g_param_spec_object ("source", "Source", "Source element",
  13.146 +          GST_TYPE_ELEMENT, G_PARAM_READABLE));
  13.147 +
  13.148 +  GST_DEBUG_CATEGORY_INIT (gst_play_bin_maemo_debug, "playbinmaemo", 0,
  13.149 +      "playbinmaemo");
  13.150 +
  13.151 +  gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_maemo_dispose);
  13.152 +  gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_maemo_finalize);
  13.153 +
  13.154 +  gstelement_klass->change_state =
  13.155 +      GST_DEBUG_FUNCPTR (gst_play_bin_maemo_change_state);
  13.156 +}
  13.157 +
  13.158 +static void
  13.159 +gst_play_bin_maemo_init (GstPlayBinMaemo * play_bin_maemo, GstPlayBinMaemoClass *class)
  13.160 +{
  13.161 +  GList *factories;
  13.162 +
  13.163 +  play_bin_maemo->uri = NULL;
  13.164 +  play_bin_maemo->source = NULL;
  13.165 +
  13.166 +  play_bin_maemo->volume = DEFAULT_VOLUME * 65535 / 10;
  13.167 +  play_bin_maemo->xid = DEFAULT_XID;
  13.168 +
  13.169 +  factories = gst_default_registry_feature_filter ((GstPluginFeatureFilter) factory_filter_sinks,
  13.170 +                                                   FALSE, play_bin_maemo);
  13.171 +
  13.172 +  play_bin_maemo->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
  13.173 +}
  13.174 +
  13.175 +static void
  13.176 +gst_play_bin_maemo_dispose (GObject * object)
  13.177 +{
  13.178 +  GstPlayBinMaemo *play_bin_maemo;
  13.179 +
  13.180 +  play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
  13.181 +  g_free (play_bin_maemo->uri);
  13.182 +  play_bin_maemo->uri = NULL;
  13.183 +
  13.184 +  G_OBJECT_CLASS (parent_class)->dispose (object);
  13.185 +}
  13.186 +
  13.187 +static void
  13.188 +gst_play_bin_maemo_finalize (GObject * object)
  13.189 +{
  13.190 +  G_OBJECT_CLASS (parent_class)->finalize (object);
  13.191 +}
  13.192 +
  13.193 +static gboolean
  13.194 +array_has_value (const gchar * values[], const gchar * value)
  13.195 +{
  13.196 +  gint i;
  13.197 +
  13.198 +  for (i = 0; values[i]; i++) {
  13.199 +    if (g_str_has_prefix (value, values[i]))
  13.200 +      return TRUE;
  13.201 +  }
  13.202 +  return FALSE;
  13.203 +}
  13.204 +
  13.205 +/* list of URIs that we consider to be streams and that need buffering.
  13.206 + * We have no mechanism yet to figure this out with a query. */
  13.207 +static const gchar *stream_uris[] = { "http://", "mms://", "mmsh://",
  13.208 +  "mmsu://", "mmst://", NULL
  13.209 +};
  13.210 +
  13.211 +/* blacklisted URIs, we know they will always fail. */
  13.212 +static const gchar *blacklisted_uris[] = { NULL };
  13.213 +
  13.214 +/* mime types that we don't consider to be media types */
  13.215 +static const gchar *no_media_mimes[] = {
  13.216 +  "application/x-executable", "application/x-bzip", "application/x-gzip",
  13.217 +  "application/zip", "application/x-compress", NULL
  13.218 +};
  13.219 +
  13.220 +/* mime types we consider raw media */
  13.221 +static const gchar *raw_mimes[] = {
  13.222 +  "audio/x-raw", "video/x-raw", NULL
  13.223 +};
  13.224 +
  13.225 +#define IS_STREAM_URI(uri)          (array_has_value (stream_uris, uri))
  13.226 +#define IS_BLACKLISTED_URI(uri)     (array_has_value (blacklisted_uris, uri))
  13.227 +#define IS_NO_MEDIA_MIME(mime)      (array_has_value (no_media_mimes, mime))
  13.228 +#define IS_RAW_MIME(mime)           (array_has_value (raw_mimes, mime))
  13.229 +
  13.230 +/*
  13.231 + * Generate and configure a source element.
  13.232 + */
  13.233 +static GstElement *
  13.234 +gen_source_element (GstPlayBinMaemo * play_bin_maemo)
  13.235 +{
  13.236 +  GstElement *source;
  13.237 +
  13.238 +  if (!play_bin_maemo->uri)
  13.239 +    goto no_uri;
  13.240 +
  13.241 +  if (!gst_uri_is_valid (play_bin_maemo->uri))
  13.242 +    goto invalid_uri;
  13.243 +
  13.244 +  if (IS_BLACKLISTED_URI (play_bin_maemo->uri))
  13.245 +    goto uri_blacklisted;
  13.246 +
  13.247 +  source = gst_element_make_from_uri (GST_URI_SRC, play_bin_maemo->uri,
  13.248 +      "source");
  13.249 +  if (!source)
  13.250 +    goto no_source;
  13.251 +
  13.252 +  play_bin_maemo->is_stream = IS_STREAM_URI (play_bin_maemo->uri);
  13.253 +
  13.254 +  /* make HTTP sources send extra headers so we get icecast
  13.255 +   * metadata in case the stream is an icecast stream */
  13.256 +  if (!strncmp (play_bin_maemo->uri, "http://", 7) &&
  13.257 +      g_object_class_find_property (G_OBJECT_GET_CLASS (source),
  13.258 +          "iradio-mode")) {
  13.259 +    g_object_set (source, "iradio-mode", TRUE, NULL);
  13.260 +  }
  13.261 +  return source;
  13.262 +
  13.263 +  /* ERRORS */
  13.264 +no_uri:
  13.265 +  {
  13.266 +    GST_ELEMENT_ERROR (play_bin_maemo, RESOURCE, NOT_FOUND,
  13.267 +        (_("No URI specified to play from.")), (NULL));
  13.268 +    return NULL;
  13.269 +  }
  13.270 +invalid_uri:
  13.271 +  {
  13.272 +    GST_ELEMENT_ERROR (play_bin_maemo, RESOURCE, NOT_FOUND,
  13.273 +        (_("Invalid URI \"%s\"."), play_bin_maemo->uri), (NULL));
  13.274 +    return NULL;
  13.275 +  }
  13.276 +uri_blacklisted:
  13.277 +  {
  13.278 +    GST_ELEMENT_ERROR (play_bin_maemo, RESOURCE, FAILED,
  13.279 +        (_("RTSP streams cannot be played yet.")), (NULL));
  13.280 +    return NULL;
  13.281 +  }
  13.282 +no_source:
  13.283 +  {
  13.284 +    gchar *prot = gst_uri_get_protocol (play_bin_maemo->uri);
  13.285 +
  13.286 +    /* whoops, could not create the source element, dig a little deeper to
  13.287 +     * figure out what might be wrong. */
  13.288 +    if (prot) {
  13.289 +      gchar *desc;
  13.290 +
  13.291 +      /*
  13.292 +      gst_element_post_message (GST_ELEMENT (play_bin_maemo),
  13.293 +          gst_missing_uri_source_message_new (GST_ELEMENT (play_bin_maemo),
  13.294 +              prot));
  13.295 +
  13.296 +      desc = gst_pb_utils_get_source_description (prot);
  13.297 +      GST_ELEMENT_ERROR (play_bin_maemo, CORE, MISSING_PLUGIN,
  13.298 +          (_("A %s plugin is required to play this stream, but not installed."),
  13.299 +              desc), ("No URI handler for %s", prot));
  13.300 +              */
  13.301 +      g_free (desc);
  13.302 +      g_free (prot);
  13.303 +    } else
  13.304 +      goto invalid_uri;
  13.305 +
  13.306 +    return NULL;
  13.307 +  }
  13.308 +}
  13.309 +
  13.310 +static void
  13.311 +remove_source (GstPlayBinMaemo *pbm)
  13.312 +{
  13.313 +  GstElement *source = pbm->source;
  13.314 +
  13.315 +  if (source) {
  13.316 +    GST_DEBUG_OBJECT (pbm, "removing old src element");
  13.317 +    gst_element_set_state (source, GST_STATE_NULL);
  13.318 +    gst_bin_remove (GST_BIN_CAST (pbm), source);
  13.319 +    pbm->source = NULL;
  13.320 +  }
  13.321 +}
  13.322 +
  13.323 +static void
  13.324 +remove_decoders (GstPlayBinMaemo *pbm)
  13.325 +{
  13.326 +    if (pbm->queue != NULL) {
  13.327 +        gst_element_set_state (pbm->queue, GST_STATE_NULL);
  13.328 +        gst_bin_remove (GST_BIN_CAST (pbm), pbm->queue);
  13.329 +        pbm->queue = NULL;
  13.330 +    }
  13.331 +
  13.332 +    if (pbm->decoder != NULL) {
  13.333 +        gst_element_set_state (pbm->decoder, GST_STATE_NULL);
  13.334 +        gst_bin_remove (GST_BIN_CAST (pbm), pbm->decoder);
  13.335 +        pbm->decoder = NULL;
  13.336 +    }
  13.337 +}
  13.338 +
  13.339 +static void
  13.340 +remove_sinks (GstPlayBinMaemo *pbm)
  13.341 +{
  13.342 +    GSList *walk;
  13.343 +
  13.344 +    for(walk=pbm->sinks; walk != NULL; walk = walk->next) {
  13.345 +        GstElement *element = (GstElement *) walk->data;
  13.346 +
  13.347 +        gst_element_set_state (element, GST_STATE_NULL);
  13.348 +        gst_bin_remove (GST_BIN_CAST (pbm), element);
  13.349 +    }
  13.350 +
  13.351 +    g_slist_free (pbm->sinks);
  13.352 +    pbm->sinks = NULL;
  13.353 +}
  13.354 +
  13.355 +static void
  13.356 +prepare_elements (GstPlayBinMaemo *pbm)
  13.357 +{
  13.358 +    if (pbm->decoder == NULL) {
  13.359 +        pbm->decoder = gst_element_factory_make ("decodebin2", "decode");
  13.360 +        gst_bin_add (GST_BIN (pbm), pbm->decoder);
  13.361 +        g_signal_connect (G_OBJECT (pbm->decoder),
  13.362 +                          "autoplug-continue",
  13.363 +                          G_CALLBACK (autoplug_continue_cb),
  13.364 +                          pbm);
  13.365 +        g_signal_connect (G_OBJECT (pbm->decoder),
  13.366 +                          "unknown-type",
  13.367 +                          G_CALLBACK (unknown_type_cb),
  13.368 +                          pbm);
  13.369 +        g_signal_connect (G_OBJECT (pbm->decoder),
  13.370 +                          "new-decoded-pad",
  13.371 +                          G_CALLBACK (new_decoded_pad_cb),
  13.372 +                          pbm);
  13.373 +    }
  13.374 +
  13.375 +    if (pbm->queue == NULL) {
  13.376 +        pbm->queue = gst_element_factory_make ("queue", NULL);
  13.377 +        gst_bin_add (GST_BIN (pbm), pbm->queue);
  13.378 +    }
  13.379 +
  13.380 +    if (gst_element_link_many (pbm->source, pbm->queue, pbm->decoder, NULL) == FALSE) {
  13.381 +        g_warning ("FAIL TO LINK SRC WITH DECODEBIN2");
  13.382 +    }
  13.383 +}
  13.384 +
  13.385 +static gboolean
  13.386 +setup_source (GstPlayBinMaemo *pbm)
  13.387 +{
  13.388 +    if (!pbm->need_rebuild)
  13.389 +        return TRUE;
  13.390 +
  13.391 +    GST_DEBUG_OBJECT (pbm, "setup source");
  13.392 +
  13.393 +    /* delete old src */
  13.394 +    remove_source (pbm);
  13.395 +
  13.396 +    /* create and configure an element that can handle the uri */
  13.397 +    if (!(pbm->source = gen_source_element (pbm)))
  13.398 +        goto no_source;
  13.399 +
  13.400 +
  13.401 +    gst_bin_add (GST_BIN_CAST (pbm), pbm->source);
  13.402 +
  13.403 +    remove_decoders (pbm);
  13.404 +
  13.405 +    remove_sinks (pbm);
  13.406 +
  13.407 +#if 0
  13.408 +    if (verify_src_have_sink (pbm)) {
  13.409 +        /* source can be linked with sinks directly */
  13.410 +        return TRUE;
  13.411 +    }
  13.412 +#endif
  13.413 +
  13.414 +    prepare_elements (pbm);
  13.415 +
  13.416 +    return TRUE;
  13.417 +
  13.418 +no_source:
  13.419 +    return FALSE;
  13.420 +}
  13.421 +
  13.422 +static void
  13.423 +gst_play_bin_maemo_set_property (GObject *object,
  13.424 +                                 guint prop_id,
  13.425 +                                 const GValue *value,
  13.426 +                                 GParamSpec *pspec)
  13.427 +{
  13.428 +  GstPlayBinMaemo *play_bin_maemo;
  13.429 +
  13.430 +  g_return_if_fail (GST_IS_PLAY_BIN_MAEMO (object));
  13.431 +
  13.432 +  play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
  13.433 +
  13.434 +  switch (prop_id) {
  13.435 +    case ARG_URI:
  13.436 +    {
  13.437 +      const gchar *uri = g_value_get_string (value);
  13.438 +
  13.439 +      if (uri == NULL) {
  13.440 +        g_warning ("cannot set NULL uri");
  13.441 +        return;
  13.442 +      }
  13.443 +      /* if we have no previous uri, or the new uri is different from the
  13.444 +       * old one, replug */
  13.445 +      if (play_bin_maemo->uri == NULL || strcmp (play_bin_maemo->uri, uri) != 0) {
  13.446 +        g_free (play_bin_maemo->uri);
  13.447 +        play_bin_maemo->uri = g_strdup (uri);
  13.448 +
  13.449 +        GST_DEBUG ("setting new uri to %s", uri);
  13.450 +
  13.451 +        play_bin_maemo->need_rebuild = TRUE;
  13.452 +      }
  13.453 +      break;
  13.454 +    }
  13.455 +    case ARG_VOLUME:
  13.456 +    {
  13.457 +      guint volume;
  13.458 +      volume = g_value_get_uint (value);
  13.459 +      if (volume != 0) {
  13.460 +        volume = (guint) (65535 * volume / 10);
  13.461 +      }
  13.462 +
  13.463 +      if (play_bin_maemo->volume != volume) {
  13.464 +          play_bin_maemo->volume = volume;
  13.465 +          update_volume (play_bin_maemo);
  13.466 +      }
  13.467 +      break;
  13.468 +    }
  13.469 +    case ARG_XID:
  13.470 +    {
  13.471 +      long xid;
  13.472 +      xid = g_value_get_long (value);
  13.473 +      if (play_bin_maemo->xid != xid) {
  13.474 +          play_bin_maemo->xid = xid;
  13.475 +          update_xid (play_bin_maemo);
  13.476 +      }
  13.477 +      break;
  13.478 +    }
  13.479 +    default:
  13.480 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  13.481 +      break;
  13.482 +  }
  13.483 +}
  13.484 +
  13.485 +static void
  13.486 +gst_play_bin_maemo_get_property (GObject * object, guint prop_id, GValue * value,
  13.487 +    GParamSpec * pspec)
  13.488 +{
  13.489 +  GstPlayBinMaemo *play_bin_maemo;
  13.490 +
  13.491 +  g_return_if_fail (GST_IS_PLAY_BIN_MAEMO (object));
  13.492 +
  13.493 +  play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
  13.494 +
  13.495 +  switch (prop_id) {
  13.496 +    case ARG_URI:
  13.497 +      g_value_set_string (value, play_bin_maemo->uri);
  13.498 +      break;
  13.499 +    case ARG_SOURCE:
  13.500 +      g_value_set_object (value, play_bin_maemo->source);
  13.501 +      break;
  13.502 +    case ARG_VOLUME:
  13.503 +      g_value_set_uint (value, play_bin_maemo->volume);
  13.504 +      break;
  13.505 +    case ARG_XID:
  13.506 +      g_value_set_long (value, play_bin_maemo->xid);
  13.507 +      break;
  13.508 +    default:
  13.509 +      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  13.510 +      break;
  13.511 +  }
  13.512 +}
  13.513 +
  13.514 +static GstStateChangeReturn
  13.515 +gst_play_bin_maemo_change_state (GstElement * element, GstStateChange transition)
  13.516 +{
  13.517 +  GstStateChangeReturn ret;
  13.518 +  GstPlayBinMaemo *play_bin_maemo;
  13.519 +
  13.520 +  play_bin_maemo = GST_PLAY_BIN_MAEMO (element);
  13.521 +
  13.522 +  switch (transition) {
  13.523 +    case GST_STATE_CHANGE_READY_TO_PAUSED:
  13.524 +      if (!setup_source (play_bin_maemo))
  13.525 +        goto source_failed;
  13.526 +      break;
  13.527 +    default:
  13.528 +      break;
  13.529 +  }
  13.530 +
  13.531 +  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  13.532 +
  13.533 +  switch (transition) {
  13.534 +    case GST_STATE_CHANGE_READY_TO_PAUSED:
  13.535 +      if (ret == GST_STATE_CHANGE_FAILURE) {
  13.536 +        play_bin_maemo->need_rebuild = TRUE;
  13.537 +        return GST_STATE_CHANGE_FAILURE;
  13.538 +      }
  13.539 +      break;
  13.540 +      /* clean-up in both cases, READY=>NULL clean-up is if there was an error */
  13.541 +    case GST_STATE_CHANGE_PAUSED_TO_READY:
  13.542 +    case GST_STATE_CHANGE_READY_TO_NULL:
  13.543 +      play_bin_maemo->need_rebuild = TRUE;
  13.544 +      remove_decoders (play_bin_maemo);
  13.545 +      remove_source (play_bin_maemo);
  13.546 +      break;
  13.547 +    default:
  13.548 +      break;
  13.549 +  }
  13.550 +  return ret;
  13.551 +
  13.552 +  /* ERRORS */
  13.553 +source_failed:
  13.554 +  {
  13.555 +    play_bin_maemo->need_rebuild = TRUE;
  13.556 +
  13.557 +    return GST_STATE_CHANGE_FAILURE;
  13.558 +  }
  13.559 +}
  13.560 +
  13.561 +static gboolean
  13.562 +factory_filter_sinks (GstPluginFeature *feature,
  13.563 +                      GstPlayBinMaemo *pbm)
  13.564 +{
  13.565 +    guint rank;
  13.566 +    const gchar *klass;
  13.567 +
  13.568 +    if (!GST_IS_ELEMENT_FACTORY (feature))
  13.569 +        return FALSE;
  13.570 +
  13.571 +    klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
  13.572 +
  13.573 +    if ((strstr (klass, "Sink/Video") == NULL) && (strstr (klass, "Sink/Audio") == NULL))
  13.574 +        return FALSE;
  13.575 +
  13.576 +    g_debug ("Fitered: %s", gst_element_factory_get_longname ((GST_ELEMENT_FACTORY (feature))));
  13.577 +    rank = gst_plugin_feature_get_rank (feature);
  13.578 +    if (rank < GST_RANK_MARGINAL)
  13.579 +        return FALSE;
  13.580 +
  13.581 +    return TRUE;
  13.582 +}
  13.583 +
  13.584 +static gint
  13.585 +compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
  13.586 +{
  13.587 +  gint diff;
  13.588 +  const gchar *rname1, *rname2;
  13.589 +
  13.590 +  diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
  13.591 +  if (diff != 0)
  13.592 +    return diff;
  13.593 +
  13.594 +  rname1 = gst_plugin_feature_get_name (f1);
  13.595 +  rname2 = gst_plugin_feature_get_name (f2);
  13.596 +
  13.597 +  diff = strcmp (rname2, rname1);
  13.598 +
  13.599 +  return diff;
  13.600 +}
  13.601 +
  13.602 +
  13.603 +static GList *
  13.604 +find_compatibles (GstPlayBinMaemo *pbm, const GstCaps *caps)
  13.605 +{
  13.606 +  GList *factories;
  13.607 +  GList *to_try = NULL;
  13.608 +
  13.609 +  /* loop over all the factories */
  13.610 +  for (factories = pbm->factories; factories; factories = g_list_next (factories)) {
  13.611 +    GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
  13.612 +    const GList *templates;
  13.613 +    GList *walk;
  13.614 +
  13.615 +    /* get the templates from the element factory */
  13.616 +    templates = gst_element_factory_get_static_pad_templates (factory);
  13.617 +    for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
  13.618 +      GstStaticPadTemplate *templ = walk->data;
  13.619 +
  13.620 +      /* we only care about the sink templates */
  13.621 +      if (templ->direction == GST_PAD_SINK) {
  13.622 +        GstCaps *intersect;
  13.623 +        GstCaps *tmpl_caps;
  13.624 +
  13.625 +        /* try to intersect the caps with the caps of the template */
  13.626 +        tmpl_caps = gst_static_caps_get (&templ->static_caps);
  13.627 +
  13.628 +        intersect = gst_caps_intersect (caps, tmpl_caps);
  13.629 +        gst_caps_unref (tmpl_caps);
  13.630 +
  13.631 +        /* check if the intersection is empty */
  13.632 +        if (!gst_caps_is_empty (intersect)) {
  13.633 +          /* non empty intersection, we can use this element */
  13.634 +          to_try = g_list_prepend (to_try, factory);
  13.635 +          gst_caps_unref (intersect);
  13.636 +          break;
  13.637 +        }
  13.638 +        gst_caps_unref (intersect);
  13.639 +      }
  13.640 +    }
  13.641 +  }
  13.642 +  to_try = g_list_reverse (to_try);
  13.643 +
  13.644 +  return to_try;
  13.645 +}
  13.646 +
  13.647 +
  13.648 +static gboolean
  13.649 +autoplug_continue_cb (GstElement* object,
  13.650 +                      GstCaps* caps,
  13.651 +                      gpointer user_data)
  13.652 +{
  13.653 +    GList *comp = NULL;
  13.654 +    gboolean ret = TRUE;
  13.655 +
  13.656 +    comp = find_compatibles (GST_PLAY_BIN_MAEMO (user_data), caps);
  13.657 +    if (comp != NULL) {
  13.658 +        g_list_free (comp);
  13.659 +        ret = FALSE;
  13.660 +    }
  13.661 +
  13.662 +    return ret;
  13.663 +}
  13.664 +
  13.665 +static void
  13.666 +unknown_type_cb (GstElement *object,
  13.667 +                 GstPad *pad,
  13.668 +                 GstCaps *caps,
  13.669 +                 gpointer user_data)
  13.670 +{
  13.671 +    g_debug ("unknown_type_cb: %s", gst_caps_to_string (caps));
  13.672 +}
  13.673 +
  13.674 +static GstPad *
  13.675 +find_sink_pad (GstElement * element)
  13.676 +{
  13.677 +  GstIterator *it;
  13.678 +  GstPad *pad = NULL;
  13.679 +  gpointer point;
  13.680 +
  13.681 +  it = gst_element_iterate_sink_pads (element);
  13.682 +
  13.683 +  if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
  13.684 +    pad = (GstPad *) point;
  13.685 +
  13.686 +  gst_iterator_free (it);
  13.687 +
  13.688 +  return pad;
  13.689 +}
  13.690 +
  13.691 +static void
  13.692 +new_decoded_pad_cb (GstElement *object,
  13.693 +                    GstPad* pad,
  13.694 +                    gboolean arg,
  13.695 +                    gpointer user_data)
  13.696 +{
  13.697 +    GList *comp = NULL;
  13.698 +    GList *walk;
  13.699 +    GstCaps *caps;
  13.700 +    gboolean linked;
  13.701 +    GstPlayBinMaemo *pbm;
  13.702 +
  13.703 +    pbm = GST_PLAY_BIN_MAEMO (user_data);
  13.704 +    caps = gst_pad_get_caps (pad);
  13.705 +
  13.706 +    g_debug ("new_decoded_pad_cb: %s", gst_caps_to_string (caps));
  13.707 +
  13.708 +    comp = find_compatibles (GST_PLAY_BIN_MAEMO (user_data), caps);
  13.709 +
  13.710 +
  13.711 +    if (comp == NULL) {
  13.712 +        g_warning ("flow error: dont find comaptible");
  13.713 +        return;
  13.714 +    }
  13.715 +
  13.716 +    GST_PAD_STREAM_LOCK (pad);
  13.717 +
  13.718 +    linked = FALSE;
  13.719 +    for (walk=comp; walk != NULL; walk = walk->next) {
  13.720 +        GstElementFactory *factory = (GstElementFactory *) walk->data;
  13.721 +        GstElement *element;
  13.722 +        GstPad *sinkpad;
  13.723 +
  13.724 +        if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
  13.725 +            GST_WARNING_OBJECT (pbm, "Could not create an element from %s",
  13.726 +                gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
  13.727 +            continue;
  13.728 +        }
  13.729 +
  13.730 +        if (strstr (gst_element_factory_get_klass (factory), "Sink/Video") != NULL) {
  13.731 +            pbm->sink_video = element;
  13.732 +            update_xid (pbm);
  13.733 +        } else if (strstr (gst_element_factory_get_klass (factory), "Sink/Audio") != NULL) {
  13.734 +            pbm->volume_element = element;
  13.735 +            update_volume (pbm);
  13.736 +        }
  13.737 +
  13.738 +        if (!(gst_bin_add (GST_BIN (user_data), element))) {
  13.739 +            GST_WARNING_OBJECT (pbm, "Couldn't set %s to READY",
  13.740 +                GST_ELEMENT_NAME (element));
  13.741 +            gst_object_unref (element);
  13.742 +            continue;
  13.743 +        }
  13.744 +
  13.745 +        if ((gst_element_set_state (element, GST_STATE_READY))
  13.746 +                         == GST_STATE_CHANGE_FAILURE) {
  13.747 +            gst_element_set_state (element, GST_STATE_NULL);
  13.748 +            gst_object_unref (sinkpad);
  13.749 +            gst_bin_remove (GST_BIN (user_data), element);
  13.750 +            continue;
  13.751 +        }
  13.752 +
  13.753 +        if (!(sinkpad = find_sink_pad (element))) {
  13.754 +            GST_WARNING_OBJECT (pbm, "Element %s doesn't have a sink pad", GST_ELEMENT_NAME (element));
  13.755 +            gst_object_unref (element);
  13.756 +            continue;
  13.757 +        }
  13.758 +
  13.759 +
  13.760 +        if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
  13.761 +            GST_WARNING_OBJECT (pbm, "Link failed on pad %s:%s",
  13.762 +                GST_DEBUG_PAD_NAME (sinkpad));
  13.763 +            gst_element_set_state (element, GST_STATE_NULL);
  13.764 +            gst_object_unref (sinkpad);
  13.765 +            gst_bin_remove (GST_BIN (user_data), element);
  13.766 +            continue;
  13.767 +        }
  13.768 +
  13.769 +        gst_object_unref (sinkpad);
  13.770 +
  13.771 +        if ((gst_element_set_state (element, GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
  13.772 +            gst_element_set_state (element, GST_STATE_NULL);
  13.773 +            gst_bin_remove (GST_BIN (user_data), element);
  13.774 +            continue;
  13.775 +        }
  13.776 +
  13.777 +
  13.778 +        pbm->sinks = g_slist_append (pbm->sinks, element);
  13.779 +        linked = TRUE;
  13.780 +        break;
  13.781 +    }
  13.782 +
  13.783 +    g_list_free (comp);
  13.784 +    if (linked == FALSE) {
  13.785 +        g_warning ("GstFlow ERROR");
  13.786 +    }
  13.787 +    GST_PAD_STREAM_UNLOCK (pad);
  13.788 +}
  13.789 +
  13.790 +static void
  13.791 +update_volume (GstPlayBinMaemo *pbm)
  13.792 +{
  13.793 +    if (pbm->volume_element != NULL) {
  13.794 +        if (pbm->volume > 0) {
  13.795 +            g_object_set (G_OBJECT (pbm->volume_element),
  13.796 +                          "volume", pbm->volume,
  13.797 +                          NULL);
  13.798 +        } else {
  13.799 +            g_object_set (G_OBJECT (pbm->volume_element),
  13.800 +                          "mute", TRUE,
  13.801 +                          NULL);
  13.802 +        }
  13.803 +    }
  13.804 +}
  13.805 +
  13.806 +static void
  13.807 +update_xid (GstPlayBinMaemo *pbm)
  13.808 +{
  13.809 +    if ((pbm->sink_video != NULL) &&
  13.810 +        (pbm->xid != -1) &&
  13.811 +        (GST_IS_X_OVERLAY (pbm->sink_video))) {
  13.812 +        XGCValues values;
  13.813 +        Display *disp;
  13.814 +        g_object_set (G_OBJECT (pbm->sink_video),
  13.815 +                      "force-aspect-ratio", TRUE, NULL);
  13.816 +        g_debug ("Update XID to %ld", pbm->xid);
  13.817 +
  13.818 +        gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (pbm->sink_video),
  13.819 +                                      pbm->xid);
  13.820 +    }
  13.821 +}
  13.822 +
  13.823 +static gboolean
  13.824 +plugin_init(GstPlugin * plugin)
  13.825 +{
  13.826 +#ifdef ENABLE_NLS
  13.827 +    setlocale(LC_ALL, "");
  13.828 +    bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
  13.829 +#endif                          /* ENABLE_NLS */
  13.830 +
  13.831 +    if (!gst_element_register(plugin, "playbinmaemo", GST_RANK_SECONDARY,
  13.832 +                              GST_TYPE_PLAY_BIN_MAEMO)) {
  13.833 +        return FALSE;
  13.834 +    }
  13.835 +
  13.836 +    return TRUE;
  13.837 +}
  13.838 +
  13.839 +GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
  13.840 +                  GST_VERSION_MINOR,
  13.841 +                  "playbinmaemo",
  13.842 +                  "Demuxes and muxes audio and video",
  13.843 +                  plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
  13.844 +                  GST_PACKAGE_ORIGIN)
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/gst-gmyth/playbinmaemo/gstplaybinmaemo.h	Sat Jul 14 17:20:54 2007 +0100
    14.3 @@ -0,0 +1,73 @@
    14.4 +/* GStreamer
    14.5 + *
    14.6 + * This library is free software; you can redistribute it and/or
    14.7 + * modify it under the terms of the GNU Library General Public
    14.8 + * License as published by the Free Software Foundation; either
    14.9 + * version 2 of the License, or (at your option) any later version.
   14.10 + *
   14.11 + * This library is distributed in the hope that it will be useful,
   14.12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14.13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14.14 + * Library General Public License for more details.
   14.15 + *
   14.16 + * You should have received a copy of the GNU Library General Public
   14.17 + * License along with this library; if not, write to the
   14.18 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   14.19 + * Boston, MA 02111-1307, USA.
   14.20 + */
   14.21 +
   14.22 +#ifndef __GST_PLAYBINMAEMO_H__
   14.23 +#define __GST_PLAYBINMAEMO_H__
   14.24 +
   14.25 +#include <gst/gst.h>
   14.26 +
   14.27 +G_BEGIN_DECLS
   14.28 +
   14.29 +#define GST_TYPE_PLAY_BIN_MAEMO \
   14.30 +    (gst_play_bin_maemo_get_type())
   14.31 +#define GST_PLAY_BIN_MAEMO(obj) \
   14.32 +    (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN_MAEMO,GstPlayBinMaemo))
   14.33 +#define GST_PLAY_BIN_MAEMO_CLASS(klass) \
   14.34 +    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN_MAEMO,GstPlayBinMaemoClass))
   14.35 +#define GST_IS_PLAY_BIN_MAEMO(obj) \
   14.36 +    (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN_MAEMO))
   14.37 +#define GST_IS_PLAY_BIN_MAEMO_CLASS(klass) \
   14.38 +    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN_MAEMO))
   14.39 +#define GST_PLAY_BIN_MAEMO_GET_CLASS(obj) \
   14.40 +  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAY_BIN_MAEMO,GstPlayBinMaemoClass))
   14.41 +
   14.42 +typedef struct _GstPlayBinMaemo GstPlayBinMaemo;
   14.43 +typedef struct _GstPlayBinMaemoClass GstPlayBinMaemoClass;
   14.44 +
   14.45 +struct _GstPlayBinMaemo {
   14.46 +  GstPipeline    pipeline;
   14.47 +
   14.48 +  /* properties */
   14.49 +  guint64        queue_size;
   14.50 +  guint64        queue_min_threshold;
   14.51 +  gboolean       is_stream;
   14.52 +  glong          xid;
   14.53 +  guint          volume;
   14.54 +
   14.55 +  /* currently loaded media */
   14.56 +  gboolean      need_rebuild;
   14.57 +  gchar         *uri;
   14.58 +  GstElement    *source;
   14.59 +  GstElement    *decoder;
   14.60 +  GstElement    *queue;
   14.61 +  GstElement    *volume_element;
   14.62 +  GstElement    *sink_video;
   14.63 +  GSList        *sinks;
   14.64 +  GList         *factories;
   14.65 +};
   14.66 +
   14.67 +struct _GstPlayBinMaemoClass {
   14.68 +  GstPipelineClass parent_class;
   14.69 +};
   14.70 +
   14.71 +GType gst_play_bin_maemo_get_type (void);
   14.72 +
   14.73 +G_END_DECLS
   14.74 +
   14.75 +#endif /* __GST_PLAYBINMAEMO_H__ */
   14.76 +