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 +