1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/gst-gmyth/decodebin2/gstdecodebin2.c Tue Jul 17 23:17:09 2007 +0100
1.3 @@ -0,0 +1,2111 @@
1.4 +/* GStreamer
1.5 + * Copyright (C) <2006> Edward Hervey <edward@fluendo.com>
1.6 + *
1.7 + * This library is free software; you can redistribute it and/or
1.8 + * modify it under the terms of the GNU Library General Public
1.9 + * License as published by the Free Software Foundation; either
1.10 + * version 2 of the License, or (at your option) any later version.
1.11 + *
1.12 + * This library is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.15 + * Library General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU Library General Public
1.18 + * License along with this library; if not, write to the
1.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1.20 + * Boston, MA 02111-1307, USA.
1.21 + */
1.22 +
1.23 +/**
1.24 + * SECTION:element-decodebin2
1.25 + * @short_description: Next-generation automatic decoding bin
1.26 + *
1.27 + * #GstBin that auto-magically constructs a decoding pipeline using available
1.28 + * decoders and demuxers via auto-plugging.
1.29 + *
1.30 + * At this stage, decodebin2 is considered UNSTABLE. The API provided in the
1.31 + * signals is expected to change in the near future.
1.32 + *
1.33 + * To try out decodebin2, you can set the USE_DECODEBIN2 environment
1.34 + * variable (USE_DECODEBIN2=1 for example). This will cause playbin to use
1.35 + * decodebin2 instead of the older decodebin for its internal auto-plugging.
1.36 + */
1.37 +
1.38 +#ifdef HAVE_CONFIG_H
1.39 +#include "config.h"
1.40 +#endif
1.41 +
1.42 +#include <string.h>
1.43 +#include <gst/gst.h>
1.44 +
1.45 +#include "gstplay-marshal.h"
1.46 +
1.47 +/* generic templates */
1.48 +static GstStaticPadTemplate decoder_bin_sink_template =
1.49 +GST_STATIC_PAD_TEMPLATE ("sink",
1.50 + GST_PAD_SINK,
1.51 + GST_PAD_ALWAYS,
1.52 + GST_STATIC_CAPS_ANY);
1.53 +
1.54 +static GstStaticPadTemplate decoder_bin_src_template =
1.55 +GST_STATIC_PAD_TEMPLATE ("src%d",
1.56 + GST_PAD_SRC,
1.57 + GST_PAD_SOMETIMES,
1.58 + GST_STATIC_CAPS_ANY);
1.59 +
1.60 +GST_DEBUG_CATEGORY_STATIC (gst_decode_bin_debug);
1.61 +#define GST_CAT_DEFAULT gst_decode_bin_debug
1.62 +
1.63 +typedef struct _GstDecodeGroup GstDecodeGroup;
1.64 +typedef struct _GstDecodePad GstDecodePad;
1.65 +typedef struct _GstDecodeBin GstDecodeBin;
1.66 +typedef struct _GstDecodeBin GstDecodeBin2;
1.67 +typedef struct _GstDecodeBinClass GstDecodeBinClass;
1.68 +
1.69 +#define GST_TYPE_DECODE_BIN (gst_decode_bin_get_type())
1.70 +#define GST_DECODE_BIN_CAST(obj) ((GstDecodeBin*)(obj))
1.71 +#define GST_DECODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECODE_BIN,GstDecodeBin))
1.72 +#define GST_DECODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DECODE_BIN,GstDecodeBinClass))
1.73 +#define GST_IS_DECODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DECODE_BIN))
1.74 +#define GST_IS_DECODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECODE_BIN))
1.75 +
1.76 +/**
1.77 + * GstDecodeBin2:
1.78 + *
1.79 + * The opaque #DecodeBin2 data structure
1.80 + */
1.81 +struct _GstDecodeBin
1.82 +{
1.83 + GstBin bin; /* we extend GstBin */
1.84 +
1.85 + GstElement *typefind; /* this holds the typefind object */
1.86 + GstElement *fakesink;
1.87 +
1.88 + GMutex *lock; /* Protects activegroup and groups */
1.89 + GstDecodeGroup *activegroup; /* group currently active */
1.90 + GList *groups; /* List of non-active GstDecodeGroups, sorted in
1.91 + * order of creation. */
1.92 + GList *oldgroups; /* List of no-longer-used GstDecodeGroups.
1.93 + * Should be freed in dispose */
1.94 + gint nbpads; /* unique identifier for source pads */
1.95 + GstCaps *caps; /* caps on which to stop decoding */
1.96 +
1.97 + GList *factories; /* factories we can use for selecting elements */
1.98 +};
1.99 +
1.100 +struct _GstDecodeBinClass
1.101 +{
1.102 + GstBinClass parent_class;
1.103 +
1.104 + /* signal we fire when a new pad has been decoded into raw audio/video */
1.105 + void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
1.106 + /* signal we fire when a pad has been removed */
1.107 + void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
1.108 + /* signal fired when we found a pad that we cannot decode */
1.109 + void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
1.110 + /* signal fired to know if we continue trying to decode the given caps */
1.111 + gboolean (*autoplug_continue) (GstElement * element, GstCaps * caps);
1.112 + /* signal fired to reorder the proposed list of factories */
1.113 + gboolean (*autoplug_sort) (GstElement * element, GstCaps * caps,
1.114 + GList ** list);
1.115 +};
1.116 +
1.117 +/* signals */
1.118 +enum
1.119 +{
1.120 + SIGNAL_NEW_DECODED_PAD,
1.121 + SIGNAL_REMOVED_DECODED_PAD,
1.122 + SIGNAL_UNKNOWN_TYPE,
1.123 + SIGNAL_AUTOPLUG_CONTINUE,
1.124 + SIGNAL_AUTOPLUG_SORT,
1.125 + LAST_SIGNAL
1.126 +};
1.127 +
1.128 +/* Properties */
1.129 +enum
1.130 +{
1.131 + PROP_0,
1.132 + PROP_CAPS,
1.133 +};
1.134 +
1.135 +static GstBinClass *parent_class;
1.136 +static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
1.137 +
1.138 +static const GstElementDetails gst_decode_bin_details =
1.139 +GST_ELEMENT_DETAILS ("Decoder Bin",
1.140 + "Generic/Bin/Decoder",
1.141 + "Autoplug and decode to raw media",
1.142 + "Edward Hervey <edward@fluendo.com>");
1.143 +
1.144 +
1.145 +static gboolean add_fakesink (GstDecodeBin * decode_bin);
1.146 +static void remove_fakesink (GstDecodeBin * decode_bin);
1.147 +
1.148 +static void type_found (GstElement * typefind, guint probability,
1.149 + GstCaps * caps, GstDecodeBin * decode_bin);
1.150 +
1.151 +static gboolean gst_decode_bin_autoplug_continue (GstElement * element,
1.152 + GstCaps * caps);
1.153 +static gboolean gst_decode_bin_autoplug_sort (GstElement * element,
1.154 + GstCaps * caps, GList ** list);
1.155 +static void gst_decode_bin_set_property (GObject * object, guint prop_id,
1.156 + const GValue * value, GParamSpec * pspec);
1.157 +static void gst_decode_bin_get_property (GObject * object, guint prop_id,
1.158 + GValue * value, GParamSpec * pspec);
1.159 +static void gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps);
1.160 +static GstCaps *gst_decode_bin_get_caps (GstDecodeBin * dbin);
1.161 +
1.162 +static GstPad *find_sink_pad (GstElement * element);
1.163 +static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element,
1.164 + GstStateChange transition);
1.165 +
1.166 +#define DECODE_BIN_LOCK(dbin) G_STMT_START { \
1.167 + GST_LOG_OBJECT (dbin, \
1.168 + "locking from thread %p", \
1.169 + g_thread_self ()); \
1.170 + g_mutex_lock (GST_DECODE_BIN_CAST(dbin)->lock); \
1.171 + GST_LOG_OBJECT (dbin, \
1.172 + "locked from thread %p", \
1.173 + g_thread_self ()); \
1.174 +} G_STMT_END
1.175 +
1.176 +#define DECODE_BIN_UNLOCK(dbin) G_STMT_START { \
1.177 + GST_LOG_OBJECT (dbin, \
1.178 + "unlocking from thread %p", \
1.179 + g_thread_self ()); \
1.180 + g_mutex_unlock (GST_DECODE_BIN_CAST(dbin)->lock); \
1.181 +} G_STMT_END
1.182 +
1.183 +/* GstDecodeGroup
1.184 + *
1.185 + * Streams belonging to the same group/chain of a media file
1.186 + *
1.187 + */
1.188 +
1.189 +struct _GstDecodeGroup
1.190 +{
1.191 + GstDecodeBin *dbin;
1.192 + GMutex *lock;
1.193 + GstElement *multiqueue;
1.194 + gboolean exposed; /* TRUE if this group is exposed */
1.195 + gboolean drained; /* TRUE if EOS went throug all endpads */
1.196 + gboolean blocked; /* TRUE if all endpads are blocked */
1.197 + gboolean complete; /* TRUE if we are not expecting anymore streams
1.198 + * on this group */
1.199 + gulong overrunsig;
1.200 + gulong underrunsig;
1.201 + guint nbdynamic; /* number of dynamic pads in the group. */
1.202 +
1.203 + GList *endpads; /* List of GstDecodePad of source pads to be exposed */
1.204 + GList *ghosts; /* List of GstGhostPad for the endpads */
1.205 +};
1.206 +
1.207 +#define GROUP_MUTEX_LOCK(group) G_STMT_START { \
1.208 + GST_LOG_OBJECT (group->dbin, \
1.209 + "locking group %p from thread %p", \
1.210 + group, g_thread_self ()); \
1.211 + g_mutex_lock (group->lock); \
1.212 + GST_LOG_OBJECT (group->dbin, \
1.213 + "locked group %p from thread %p", \
1.214 + group, g_thread_self ()); \
1.215 +} G_STMT_END
1.216 +
1.217 +#define GROUP_MUTEX_UNLOCK(group) G_STMT_START { \
1.218 + GST_LOG_OBJECT (group->dbin, \
1.219 + "unlocking group %p from thread %p", \
1.220 + group, g_thread_self ()); \
1.221 + g_mutex_unlock (group->lock); \
1.222 +} G_STMT_END
1.223 +
1.224 +
1.225 +static GstDecodeGroup *gst_decode_group_new (GstDecodeBin * decode_bin);
1.226 +static GstPad *gst_decode_group_control_demuxer_pad (GstDecodeGroup * group,
1.227 + GstPad * pad);
1.228 +static gboolean gst_decode_group_control_source_pad (GstDecodeGroup * group,
1.229 + GstPad * pad);
1.230 +static gboolean gst_decode_group_expose (GstDecodeGroup * group);
1.231 +static void gst_decode_group_check_if_blocked (GstDecodeGroup * group);
1.232 +static void gst_decode_group_set_complete (GstDecodeGroup * group);
1.233 +static void gst_decode_group_hide (GstDecodeGroup * group);
1.234 +static void gst_decode_group_free (GstDecodeGroup * group);
1.235 +
1.236 +/* GstDecodePad
1.237 + *
1.238 + * GstPad private used for source pads of groups
1.239 + */
1.240 +
1.241 +struct _GstDecodePad
1.242 +{
1.243 + GstPad *pad;
1.244 + GstDecodeGroup *group;
1.245 + gboolean blocked;
1.246 + gboolean drained;
1.247 +};
1.248 +
1.249 +static GstDecodePad *gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad,
1.250 + gboolean block);
1.251 +static void source_pad_blocked_cb (GstPad * pad, gboolean blocked,
1.252 + GstDecodePad * dpad);
1.253 +
1.254 +/* TempPadStruct
1.255 + * Internal structure used for pads which have more than one structure.
1.256 + */
1.257 +typedef struct _TempPadStruct
1.258 +{
1.259 + GstDecodeBin *dbin;
1.260 + GstDecodeGroup *group;
1.261 +} TempPadStruct;
1.262 +
1.263 +/********************************
1.264 + * Standard GObject boilerplate *
1.265 + ********************************/
1.266 +
1.267 +static void gst_decode_bin_class_init (GstDecodeBinClass * klass);
1.268 +static void gst_decode_bin_init (GstDecodeBin * decode_bin);
1.269 +static void gst_decode_bin_dispose (GObject * object);
1.270 +static void gst_decode_bin_finalize (GObject * object);
1.271 +
1.272 +static GType
1.273 +gst_decode_bin_get_type (void)
1.274 +{
1.275 + static GType gst_decode_bin_type = 0;
1.276 +
1.277 + if (!gst_decode_bin_type) {
1.278 + static const GTypeInfo gst_decode_bin_info = {
1.279 + sizeof (GstDecodeBinClass),
1.280 + NULL,
1.281 + NULL,
1.282 + (GClassInitFunc) gst_decode_bin_class_init,
1.283 + NULL,
1.284 + NULL,
1.285 + sizeof (GstDecodeBin),
1.286 + 0,
1.287 + (GInstanceInitFunc) gst_decode_bin_init,
1.288 + NULL
1.289 + };
1.290 +
1.291 + gst_decode_bin_type =
1.292 + g_type_register_static (GST_TYPE_BIN, "GstDecodeBin2",
1.293 + &gst_decode_bin_info, 0);
1.294 + }
1.295 +
1.296 + return gst_decode_bin_type;
1.297 +}
1.298 +
1.299 +static gboolean
1.300 +_gst_boolean_accumulator (GSignalInvocationHint * ihint,
1.301 + GValue * return_accu, const GValue * handler_return, gpointer dummy)
1.302 +{
1.303 + gboolean myboolean;
1.304 +
1.305 + myboolean = g_value_get_boolean (handler_return);
1.306 + if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
1.307 + g_value_set_boolean (return_accu, myboolean);
1.308 +
1.309 + /* stop emission if FALSE */
1.310 + return myboolean;
1.311 +}
1.312 +
1.313 +static void
1.314 +gst_decode_bin_class_init (GstDecodeBinClass * klass)
1.315 +{
1.316 + GObjectClass *gobject_klass;
1.317 + GstElementClass *gstelement_klass;
1.318 + GstBinClass *gstbin_klass;
1.319 +
1.320 + gobject_klass = (GObjectClass *) klass;
1.321 + gstelement_klass = (GstElementClass *) klass;
1.322 + gstbin_klass = (GstBinClass *) klass;
1.323 +
1.324 + parent_class = g_type_class_peek_parent (klass);
1.325 +
1.326 + gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
1.327 + gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_decode_bin_finalize);
1.328 + gobject_klass->set_property = GST_DEBUG_FUNCPTR (gst_decode_bin_set_property);
1.329 + gobject_klass->get_property = GST_DEBUG_FUNCPTR (gst_decode_bin_get_property);
1.330 +
1.331 + /**
1.332 + * GstDecodeBin2::new-decoded-pad:
1.333 + * @pad: the newly created pad
1.334 + * @islast: #TRUE if this is the last pad to be added. Deprecated.
1.335 + *
1.336 + * This signal gets emitted as soon as a new pad of the same type as one of
1.337 + * the valid 'raw' types is added.
1.338 + */
1.339 +
1.340 + gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD] =
1.341 + g_signal_new ("new-decoded-pad", G_TYPE_FROM_CLASS (klass),
1.342 + G_SIGNAL_RUN_LAST,
1.343 + G_STRUCT_OFFSET (GstDecodeBinClass, new_decoded_pad), NULL, NULL,
1.344 + gst_play_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, GST_TYPE_PAD,
1.345 + G_TYPE_BOOLEAN);
1.346 +
1.347 + /**
1.348 + * GstDecodeBin2::removed-decoded-pad:
1.349 + * @pad: the pad that was removed
1.350 + *
1.351 + * This signal is emitted when a 'final' caps pad has been removed.
1.352 + */
1.353 +
1.354 + gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD] =
1.355 + g_signal_new ("removed-decoded-pad", G_TYPE_FROM_CLASS (klass),
1.356 + G_SIGNAL_RUN_LAST,
1.357 + G_STRUCT_OFFSET (GstDecodeBinClass, removed_decoded_pad), NULL, NULL,
1.358 + gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
1.359 +
1.360 + /**
1.361 + * GstDecodeBin2::unknown-type:
1.362 + * @pad: the new pad containing caps that cannot be resolved to a 'final' stream type.
1.363 + * @caps: the #GstCaps of the pad that cannot be resolved.
1.364 + *
1.365 + * This signal is emitted when a pad for which there is no further possible
1.366 + * decoding is added to the decodebin.
1.367 + */
1.368 +
1.369 + gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] =
1.370 + g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass),
1.371 + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
1.372 + NULL, NULL, gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2,
1.373 + GST_TYPE_PAD, GST_TYPE_CAPS);
1.374 +
1.375 + /**
1.376 + * GstDecodeBin2::autoplug-continue:
1.377 + * @caps: The #GstCaps found.
1.378 + *
1.379 + * This signal is emitted whenever decodebin2 finds a new stream. It is
1.380 + * emitted before looking for any elements that can handle that stream.
1.381 + *
1.382 + * Returns: #TRUE if you wish decodebin2 to look for elements that can
1.383 + * handle the given @caps. If #FALSE, those caps will be considered as
1.384 + * final and the pad will be exposed as such (see 'new-decoded-pad'
1.385 + * signal).
1.386 + */
1.387 +
1.388 + gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE] =
1.389 + g_signal_new ("autoplug-continue", G_TYPE_FROM_CLASS (klass),
1.390 + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_continue),
1.391 + _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT,
1.392 + G_TYPE_BOOLEAN, 1, GST_TYPE_CAPS);
1.393 +
1.394 + /**
1.395 + * GstDecodeBin2::autoplug-sort:
1.396 + * @caps: The #GstCaps.
1.397 + * @factories: A #GList of possible #GstElementFactory to use.
1.398 + *
1.399 + * This signal is emitted once decodebin2 has found all the possible
1.400 + * #GstElementFactory that can be used to handle the given @caps.
1.401 + *
1.402 + * UNSTABLE API. Will change soon.
1.403 + *
1.404 + * Returns: #TRUE if you wish decodebin2 to start trying to decode
1.405 + * the given @caps with the list of factories. #FALSE if you do not want
1.406 + * these #GstCaps, if so the pad will be exposed as unknown (see
1.407 + * 'unknown-type' signal).
1.408 + */
1.409 +
1.410 + gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT] =
1.411 + g_signal_new ("autoplug-sort", G_TYPE_FROM_CLASS (klass),
1.412 + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_sort),
1.413 + _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT_POINTER,
1.414 + G_TYPE_BOOLEAN, 2, GST_TYPE_CAPS, G_TYPE_POINTER);
1.415 +
1.416 + g_object_class_install_property (gobject_klass, PROP_CAPS,
1.417 + g_param_spec_boxed ("caps", "Caps", "The caps on which to stop decoding.",
1.418 + GST_TYPE_CAPS, G_PARAM_READWRITE));
1.419 +
1.420 + klass->autoplug_continue =
1.421 + GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_continue);
1.422 + klass->autoplug_sort = GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_sort);
1.423 +
1.424 + gst_element_class_add_pad_template (gstelement_klass,
1.425 + gst_static_pad_template_get (&decoder_bin_sink_template));
1.426 + gst_element_class_add_pad_template (gstelement_klass,
1.427 + gst_static_pad_template_get (&decoder_bin_src_template));
1.428 +
1.429 + gst_element_class_set_details (gstelement_klass, &gst_decode_bin_details);
1.430 +
1.431 + gstelement_klass->change_state =
1.432 + GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
1.433 +}
1.434 +
1.435 +/* the filter function for selecting the elements we can use in
1.436 + * autoplugging */
1.437 +static gboolean
1.438 +gst_decode_bin_factory_filter (GstPluginFeature * feature,
1.439 + GstDecodeBin * decode_bin)
1.440 +{
1.441 + guint rank;
1.442 + const gchar *klass;
1.443 +
1.444 + /* we only care about element factories */
1.445 + if (!GST_IS_ELEMENT_FACTORY (feature))
1.446 + return FALSE;
1.447 +
1.448 + klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
1.449 + /* only demuxers, decoders and parsers can play */
1.450 + if (strstr (klass, "Demux") == NULL &&
1.451 + strstr (klass, "Decoder") == NULL && strstr (klass, "Parse") == NULL) {
1.452 + return FALSE;
1.453 + }
1.454 +
1.455 + /* only select elements with autoplugging rank */
1.456 + rank = gst_plugin_feature_get_rank (feature);
1.457 + if (rank < GST_RANK_MARGINAL)
1.458 + return FALSE;
1.459 +
1.460 + return TRUE;
1.461 +}
1.462 +
1.463 +/* function used to sort element features */
1.464 +static gint
1.465 +compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
1.466 +{
1.467 + gint diff;
1.468 + const gchar *rname1, *rname2;
1.469 +
1.470 + diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
1.471 + if (diff != 0)
1.472 + return diff;
1.473 +
1.474 + rname1 = gst_plugin_feature_get_name (f1);
1.475 + rname2 = gst_plugin_feature_get_name (f2);
1.476 +
1.477 + diff = strcmp (rname2, rname1);
1.478 +
1.479 + return diff;
1.480 +}
1.481 +
1.482 +static void
1.483 +print_feature (GstPluginFeature * feature)
1.484 +{
1.485 + const gchar *rname;
1.486 +
1.487 + rname = gst_plugin_feature_get_name (feature);
1.488 +
1.489 + GST_DEBUG ("%s", rname);
1.490 +}
1.491 +
1.492 +static void
1.493 +gst_decode_bin_init (GstDecodeBin * decode_bin)
1.494 +{
1.495 + GList *factories;
1.496 +
1.497 + /* first filter out the interesting element factories */
1.498 + factories = gst_default_registry_feature_filter (
1.499 + (GstPluginFeatureFilter) gst_decode_bin_factory_filter,
1.500 + FALSE, decode_bin);
1.501 +
1.502 + /* sort them according to their ranks */
1.503 + decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
1.504 + /* do some debugging */
1.505 + g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
1.506 +
1.507 +
1.508 + /* we create the typefind element only once */
1.509 + decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
1.510 + if (!decode_bin->typefind) {
1.511 + g_warning ("can't find typefind element, decodebin will not work");
1.512 + } else {
1.513 + GstPad *pad;
1.514 + GstPad *gpad;
1.515 +
1.516 + /* add the typefind element */
1.517 + if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind)) {
1.518 + g_warning ("Could not add typefind element, decodebin will not work");
1.519 + gst_object_unref (decode_bin->typefind);
1.520 + decode_bin->typefind = NULL;
1.521 + }
1.522 +
1.523 + /* get the sinkpad */
1.524 + pad = gst_element_get_pad (decode_bin->typefind, "sink");
1.525 +
1.526 + /* ghost the sink pad to ourself */
1.527 + gpad = gst_ghost_pad_new ("sink", pad);
1.528 + gst_pad_set_active (gpad, TRUE);
1.529 + gst_element_add_pad (GST_ELEMENT (decode_bin), gpad);
1.530 +
1.531 + gst_object_unref (pad);
1.532 +
1.533 + /* connect a signal to find out when the typefind element found
1.534 + * a type */
1.535 + g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
1.536 + G_CALLBACK (type_found), decode_bin);
1.537 + }
1.538 +
1.539 + decode_bin->lock = g_mutex_new ();
1.540 + decode_bin->activegroup = NULL;
1.541 + decode_bin->groups = NULL;
1.542 +
1.543 + decode_bin->caps =
1.544 + gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray;"
1.545 + "audio/x-raw-int;audio/x-raw-float;" "text/plain;text/x-pango-markup");
1.546 +
1.547 + add_fakesink (decode_bin);
1.548 +
1.549 + /* FILLME */
1.550 +}
1.551 +
1.552 +static void
1.553 +gst_decode_bin_dispose (GObject * object)
1.554 +{
1.555 + GstDecodeBin *decode_bin;
1.556 + GList *tmp;
1.557 +
1.558 + decode_bin = GST_DECODE_BIN (object);
1.559 +
1.560 + if (decode_bin->factories)
1.561 + gst_plugin_feature_list_free (decode_bin->factories);
1.562 + decode_bin->factories = NULL;
1.563 +
1.564 + if (decode_bin->activegroup) {
1.565 + gst_decode_group_free (decode_bin->activegroup);
1.566 + decode_bin->activegroup = NULL;
1.567 + }
1.568 +
1.569 + /* remove groups */
1.570 + for (tmp = decode_bin->groups; tmp; tmp = g_list_next (tmp)) {
1.571 + GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
1.572 +
1.573 + gst_decode_group_free (group);
1.574 + }
1.575 + g_list_free (decode_bin->groups);
1.576 + decode_bin->groups = NULL;
1.577 +
1.578 + for (tmp = decode_bin->oldgroups; tmp; tmp = g_list_next (tmp)) {
1.579 + GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
1.580 +
1.581 + gst_decode_group_free (group);
1.582 + }
1.583 + g_list_free (decode_bin->oldgroups);
1.584 + decode_bin->oldgroups = NULL;
1.585 +
1.586 + if (decode_bin->caps)
1.587 + gst_caps_unref (decode_bin->caps);
1.588 + decode_bin->caps = NULL;
1.589 + remove_fakesink (decode_bin);
1.590 +
1.591 + G_OBJECT_CLASS (parent_class)->dispose (object);
1.592 +}
1.593 +
1.594 +static void
1.595 +gst_decode_bin_finalize (GObject * object)
1.596 +{
1.597 + GstDecodeBin *decode_bin;
1.598 +
1.599 + decode_bin = GST_DECODE_BIN (object);
1.600 +
1.601 + if (decode_bin->lock) {
1.602 + g_mutex_free (decode_bin->lock);
1.603 + decode_bin->lock = NULL;
1.604 + }
1.605 +
1.606 + G_OBJECT_CLASS (parent_class)->finalize (object);
1.607 +}
1.608 +
1.609 +static void
1.610 +gst_decode_bin_set_property (GObject * object, guint prop_id,
1.611 + const GValue * value, GParamSpec * pspec)
1.612 +{
1.613 + GstDecodeBin *dbin;
1.614 +
1.615 + dbin = GST_DECODE_BIN (object);
1.616 +
1.617 + switch (prop_id) {
1.618 + case PROP_CAPS:
1.619 + gst_decode_bin_set_caps (dbin, (GstCaps *) g_value_dup_boxed (value));
1.620 + break;
1.621 + default:
1.622 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1.623 + break;
1.624 + }
1.625 +}
1.626 +
1.627 +static void
1.628 +gst_decode_bin_get_property (GObject * object, guint prop_id,
1.629 + GValue * value, GParamSpec * pspec)
1.630 +{
1.631 + GstDecodeBin *dbin;
1.632 +
1.633 + dbin = GST_DECODE_BIN (object);
1.634 + switch (prop_id) {
1.635 + case PROP_CAPS:{
1.636 + g_value_take_boxed (value, gst_decode_bin_get_caps (dbin));
1.637 + break;
1.638 + }
1.639 + default:
1.640 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1.641 + break;
1.642 + }
1.643 +
1.644 +}
1.645 +
1.646 +/* _set_caps
1.647 + * Changes the caps on which decodebin will stop decoding.
1.648 + * Will unref the previously set one. The refcount of the given caps will be
1.649 + * taken.
1.650 + * @caps can be NULL.
1.651 + *
1.652 + * MT-safe
1.653 + */
1.654 +
1.655 +static void
1.656 +gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps)
1.657 +{
1.658 + GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps);
1.659 +
1.660 + DECODE_BIN_LOCK (dbin);
1.661 + if (dbin->caps)
1.662 + gst_caps_unref (dbin->caps);
1.663 + dbin->caps = caps;
1.664 + DECODE_BIN_UNLOCK (dbin);
1.665 +}
1.666 +
1.667 +/* _get_caps
1.668 + * Returns the currently configured caps on which decodebin will stop decoding.
1.669 + * The returned caps (if not NULL), will have its refcount incremented.
1.670 + *
1.671 + * MT-safe
1.672 + */
1.673 +
1.674 +static GstCaps *
1.675 +gst_decode_bin_get_caps (GstDecodeBin * dbin)
1.676 +{
1.677 + GstCaps *caps;
1.678 +
1.679 + GST_DEBUG_OBJECT (dbin, "Getting currently set caps");
1.680 +
1.681 + DECODE_BIN_LOCK (dbin);
1.682 + caps = dbin->caps;
1.683 + if (caps)
1.684 + gst_caps_ref (caps);
1.685 + DECODE_BIN_UNLOCK (dbin);
1.686 +
1.687 + return caps;
1.688 +}
1.689 +
1.690 +/*****
1.691 + * Default autoplug signal handlers
1.692 + *****/
1.693 +
1.694 +static gboolean
1.695 +gst_decode_bin_autoplug_continue (GstElement * element, GstCaps * caps)
1.696 +{
1.697 + return TRUE;
1.698 +}
1.699 +
1.700 +static gboolean
1.701 +gst_decode_bin_autoplug_sort (GstElement * element, GstCaps * caps,
1.702 + GList ** list)
1.703 +{
1.704 + return TRUE;
1.705 +}
1.706 +
1.707 +
1.708 +
1.709 +/********
1.710 + * Discovery methods
1.711 + *****/
1.712 +
1.713 +static gboolean are_raw_caps (GstDecodeBin * dbin, GstCaps * caps);
1.714 +static gboolean is_demuxer_element (GstElement * srcelement);
1.715 +static GList *find_compatibles (GstDecodeBin * decode_bin,
1.716 + const GstCaps * caps);
1.717 +
1.718 +static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src,
1.719 + GstPad * pad, GList * factories, GstDecodeGroup * group);
1.720 +static gboolean connect_element (GstDecodeBin * dbin, GstElement * element,
1.721 + GstDecodeGroup * group);
1.722 +static void expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
1.723 + GstDecodeGroup * group);
1.724 +
1.725 +static void pad_added_group_cb (GstElement * element, GstPad * pad,
1.726 + GstDecodeGroup * group);
1.727 +static void pad_removed_group_cb (GstElement * element, GstPad * pad,
1.728 + GstDecodeGroup * group);
1.729 +static void no_more_pads_group_cb (GstElement * element,
1.730 + GstDecodeGroup * group);
1.731 +static void pad_added_cb (GstElement * element, GstPad * pad,
1.732 + GstDecodeBin * dbin);
1.733 +static void pad_removed_cb (GstElement * element, GstPad * pad,
1.734 + GstDecodeBin * dbin);
1.735 +static void no_more_pads_cb (GstElement * element, GstDecodeBin * dbin);
1.736 +
1.737 +static GstDecodeGroup *get_current_group (GstDecodeBin * dbin);
1.738 +
1.739 +static void
1.740 +analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
1.741 + GstCaps * caps, GstDecodeGroup * group)
1.742 +{
1.743 + gboolean apcontinue = TRUE;
1.744 + GList *factories = NULL;
1.745 + gboolean apsort = TRUE;
1.746 +
1.747 + GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
1.748 + GST_DEBUG_PAD_NAME (pad), caps);
1.749 +
1.750 + if ((caps == NULL) || gst_caps_is_empty (caps))
1.751 + goto unknown_type;
1.752 +
1.753 + if (gst_caps_is_any (caps))
1.754 + goto any_caps;
1.755 +
1.756 + /* 1. Emit 'autoplug-continue' */
1.757 + g_signal_emit (G_OBJECT (dbin),
1.758 + gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, caps, &apcontinue);
1.759 +
1.760 + /* 1.a if autoplug-continue is FALSE or caps is a raw format, goto pad_is_final */
1.761 + if ((!apcontinue) || are_raw_caps (dbin, caps))
1.762 + goto expose_pad;
1.763 +
1.764 + /* 1.b else if there's no compatible factory or 'autoplug-sort' returned FALSE, goto pad_not_used */
1.765 + if ((factories = find_compatibles (dbin, caps))) {
1.766 + /* emit autoplug-sort */
1.767 + g_signal_emit (G_OBJECT (dbin),
1.768 + gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT],
1.769 + 0, caps, &factories, &apsort);
1.770 + if (!apsort) {
1.771 + g_list_free (factories);
1.772 + /* User doesn't want that pad */
1.773 + goto pad_not_wanted;
1.774 + }
1.775 + } else {
1.776 + /* no compatible factories */
1.777 + goto unknown_type;
1.778 + }
1.779 +
1.780 + /* 1.c else goto pad_is_valid */
1.781 + GST_LOG_OBJECT (pad, "Let's continue discovery on this pad");
1.782 +
1.783 + connect_pad (dbin, src, pad, factories, group);
1.784 + g_list_free (factories);
1.785 +
1.786 + return;
1.787 +
1.788 +expose_pad:
1.789 + {
1.790 + GST_LOG_OBJECT (dbin, "Pad is final. autoplug-continue:%d", apcontinue);
1.791 + expose_pad (dbin, src, pad, group);
1.792 + return;
1.793 + }
1.794 +
1.795 +pad_not_wanted:
1.796 + {
1.797 + GST_LOG_OBJECT (pad, "User doesn't want this pad, stopping discovery");
1.798 + return;
1.799 + }
1.800 +
1.801 +unknown_type:
1.802 + {
1.803 + GST_LOG_OBJECT (pad, "Unknown type, firing signal");
1.804 + g_signal_emit (G_OBJECT (dbin),
1.805 + gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
1.806 +
1.807 + /* Check if there are no pending groups, if so, remove fakesink */
1.808 + if (dbin->groups == NULL)
1.809 + remove_fakesink (dbin);
1.810 +
1.811 + return;
1.812 + }
1.813 +
1.814 +any_caps:
1.815 + {
1.816 + GST_WARNING_OBJECT (pad,
1.817 + "pad has ANY caps, not able to autoplug to anything");
1.818 + /* FIXME : connect to caps notification */
1.819 + return;
1.820 + }
1.821 +}
1.822 +
1.823 +
1.824 +/* connect_pad:
1.825 + *
1.826 + * Try to connect the given pad to an element created from one of the factories,
1.827 + * and recursively.
1.828 + *
1.829 + * Returns TRUE if an element was properly created and linked
1.830 + */
1.831 +
1.832 +static gboolean
1.833 +connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
1.834 + GList * factories, GstDecodeGroup * group)
1.835 +{
1.836 + gboolean res = FALSE;
1.837 + GList *tmp;
1.838 +
1.839 + g_return_val_if_fail (factories != NULL, FALSE);
1.840 + GST_DEBUG_OBJECT (dbin, "pad %s:%s , group:%p",
1.841 + GST_DEBUG_PAD_NAME (pad), group);
1.842 +
1.843 + /* 1. is element demuxer or parser */
1.844 + if (is_demuxer_element (src)) {
1.845 + GstPad *mqpad;
1.846 +
1.847 + GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
1.848 +
1.849 + if (!group)
1.850 + if (!(group = get_current_group (dbin))) {
1.851 + group = gst_decode_group_new (dbin);
1.852 + DECODE_BIN_LOCK (dbin);
1.853 + dbin->groups = g_list_append (dbin->groups, group);
1.854 + DECODE_BIN_UNLOCK (dbin);
1.855 + }
1.856 +
1.857 + if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
1.858 + goto beach;
1.859 + pad = mqpad;
1.860 + }
1.861 +
1.862 + /* 2. Try to create an element and link to it */
1.863 + for (tmp = factories; tmp; tmp = g_list_next (tmp)) {
1.864 + GstElementFactory *factory = (GstElementFactory *) tmp->data;
1.865 + GstElement *element;
1.866 + GstPad *sinkpad;
1.867 +
1.868 + /* 2.1. Try to create an element */
1.869 + if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
1.870 + GST_WARNING_OBJECT (dbin, "Could not create an element from %s",
1.871 + gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
1.872 + continue;
1.873 + }
1.874 +
1.875 + /* 2.3. Find its sink pad */
1.876 + if (!(sinkpad = find_sink_pad (element))) {
1.877 + GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
1.878 + GST_ELEMENT_NAME (element));
1.879 + gst_object_unref (element);
1.880 + continue;
1.881 + }
1.882 +
1.883 + /* 2.4 add it ... */
1.884 + if (!(gst_bin_add (GST_BIN (dbin), element))) {
1.885 + GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
1.886 + GST_ELEMENT_NAME (element));
1.887 + gst_object_unref (sinkpad);
1.888 + gst_object_unref (element);
1.889 + continue;
1.890 + }
1.891 +
1.892 + /* ... activate it ... */
1.893 + if ((gst_element_set_state (element,
1.894 + GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
1.895 + GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
1.896 + GST_ELEMENT_NAME (element));
1.897 + gst_object_unref (sinkpad);
1.898 + gst_bin_remove (GST_BIN (dbin), element);
1.899 + continue;
1.900 + }
1.901 +
1.902 + /* 2.5 ...and try to link */
1.903 + if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
1.904 + GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s",
1.905 + GST_DEBUG_PAD_NAME (sinkpad));
1.906 + gst_element_set_state (element, GST_STATE_NULL);
1.907 + gst_object_unref (sinkpad);
1.908 + gst_bin_remove (GST_BIN (dbin), element);
1.909 + continue;
1.910 + }
1.911 +
1.912 + GST_LOG_OBJECT (dbin, "linked on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1.913 +
1.914 + /* link this element further */
1.915 + connect_element (dbin, element, group);
1.916 +
1.917 + /* Bring the element to the state of the parent */
1.918 + if ((gst_element_set_state (element,
1.919 + GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
1.920 + GST_WARNING_OBJECT (dbin, "Couldn't set %s to PAUSED",
1.921 + GST_ELEMENT_NAME (element));
1.922 + gst_element_set_state (element, GST_STATE_NULL);
1.923 + gst_object_unref (sinkpad);
1.924 + gst_bin_remove (GST_BIN (dbin), element);
1.925 + continue;
1.926 + }
1.927 +
1.928 + res = TRUE;
1.929 + break;
1.930 + }
1.931 +
1.932 +beach:
1.933 + return res;
1.934 +}
1.935 +
1.936 +static gboolean
1.937 +connect_element (GstDecodeBin * dbin, GstElement * element,
1.938 + GstDecodeGroup * group)
1.939 +{
1.940 + GList *pads;
1.941 + gboolean res = TRUE;
1.942 + gboolean dynamic = FALSE;
1.943 + GList *to_connect = NULL;
1.944 +
1.945 + GST_DEBUG_OBJECT (dbin, "Attempting to connect element %s [group:%p] further",
1.946 + GST_ELEMENT_NAME (element), group);
1.947 +
1.948 + /* 1. Loop over pad templates, grabbing existing pads along the way */
1.949 + for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
1.950 + pads = g_list_next (pads)) {
1.951 + GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
1.952 + const gchar *templ_name;
1.953 +
1.954 + /* we are only interested in source pads */
1.955 + if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
1.956 + continue;
1.957 +
1.958 + templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
1.959 + GST_DEBUG_OBJECT (dbin, "got a source pad template %s", templ_name);
1.960 +
1.961 + /* figure out what kind of pad this is */
1.962 + switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
1.963 + case GST_PAD_ALWAYS:
1.964 + {
1.965 + /* get the pad that we need to autoplug */
1.966 + GstPad *pad = gst_element_get_pad (element, templ_name);
1.967 +
1.968 + if (pad) {
1.969 + GST_DEBUG_OBJECT (dbin, "got the pad for always template %s",
1.970 + templ_name);
1.971 + /* here is the pad, we need to autoplug it */
1.972 + to_connect = g_list_prepend (to_connect, pad);
1.973 + } else {
1.974 + /* strange, pad is marked as always but it's not
1.975 + * there. Fix the element */
1.976 + GST_WARNING_OBJECT (dbin,
1.977 + "could not get the pad for always template %s", templ_name);
1.978 + }
1.979 + break;
1.980 + }
1.981 + case GST_PAD_SOMETIMES:
1.982 + {
1.983 + /* try to get the pad to see if it is already created or
1.984 + * not */
1.985 + GstPad *pad = gst_element_get_pad (element, templ_name);
1.986 +
1.987 + if (pad) {
1.988 + GST_DEBUG_OBJECT (dbin, "got the pad for sometimes template %s",
1.989 + templ_name);
1.990 + /* the pad is created, we need to autoplug it */
1.991 + to_connect = g_list_prepend (to_connect, pad);
1.992 + } else {
1.993 + GST_DEBUG_OBJECT (dbin,
1.994 + "did not get the sometimes pad of template %s", templ_name);
1.995 + /* we have an element that will create dynamic pads */
1.996 + dynamic = TRUE;
1.997 + }
1.998 + break;
1.999 + }
1.1000 + case GST_PAD_REQUEST:
1.1001 + /* ignore request pads */
1.1002 + GST_DEBUG_OBJECT (dbin, "ignoring request padtemplate %s", templ_name);
1.1003 + break;
1.1004 + }
1.1005 + }
1.1006 +
1.1007 + /* 2. if there are more potential pads, connect to relevent signals */
1.1008 + if (dynamic) {
1.1009 + if (group) {
1.1010 + GST_LOG ("Adding signals to element %s in group %p",
1.1011 + GST_ELEMENT_NAME (element), group);
1.1012 + GROUP_MUTEX_LOCK (group);
1.1013 + group->nbdynamic++;
1.1014 + GST_LOG ("Group %p has now %d dynamic elements", group, group->nbdynamic);
1.1015 + GROUP_MUTEX_UNLOCK (group);
1.1016 + g_signal_connect (G_OBJECT (element), "pad-added",
1.1017 + G_CALLBACK (pad_added_group_cb), group);
1.1018 + g_signal_connect (G_OBJECT (element), "pad-removed",
1.1019 + G_CALLBACK (pad_removed_group_cb), group);
1.1020 + g_signal_connect (G_OBJECT (element), "no-more-pads",
1.1021 + G_CALLBACK (no_more_pads_group_cb), group);
1.1022 + } else {
1.1023 + /* This is a non-grouped element, the handlers are different */
1.1024 + g_signal_connect (G_OBJECT (element), "pad-added",
1.1025 + G_CALLBACK (pad_added_cb), dbin);
1.1026 + g_signal_connect (G_OBJECT (element), "pad-removed",
1.1027 + G_CALLBACK (pad_removed_cb), dbin);
1.1028 + g_signal_connect (G_OBJECT (element), "no-more-pads",
1.1029 + G_CALLBACK (no_more_pads_cb), dbin);
1.1030 + }
1.1031 + }
1.1032 +
1.1033 + /* 3. for every available pad, connect it */
1.1034 + for (pads = to_connect; pads; pads = g_list_next (pads)) {
1.1035 + GstPad *pad = GST_PAD_CAST (pads->data);
1.1036 + GstCaps *caps;
1.1037 +
1.1038 + caps = gst_pad_get_caps (pad);
1.1039 + analyze_new_pad (dbin, element, pad, caps, group);
1.1040 + if (caps)
1.1041 + gst_caps_unref (caps);
1.1042 +
1.1043 + gst_object_unref (pad);
1.1044 + }
1.1045 + g_list_free (to_connect);
1.1046 +
1.1047 + return res;
1.1048 +}
1.1049 +
1.1050 +/* expose_pad:
1.1051 + *
1.1052 + * Expose the given pad on the group as a decoded pad.
1.1053 + * If group is NULL, a GstDecodeGroup will be created and setup properly.
1.1054 + */
1.1055 +static void
1.1056 +expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
1.1057 + GstDecodeGroup * group)
1.1058 +{
1.1059 + gboolean newgroup = FALSE;
1.1060 + gboolean isdemux;
1.1061 +
1.1062 + GST_DEBUG_OBJECT (dbin, "pad %s:%s, group:%p",
1.1063 + GST_DEBUG_PAD_NAME (pad), group);
1.1064 +
1.1065 + if (!group)
1.1066 + if (!(group = get_current_group (dbin))) {
1.1067 + group = gst_decode_group_new (dbin);
1.1068 + DECODE_BIN_LOCK (dbin);
1.1069 + dbin->groups = g_list_append (dbin->groups, group);
1.1070 + DECODE_BIN_UNLOCK (dbin);
1.1071 + newgroup = TRUE;
1.1072 + }
1.1073 +
1.1074 + isdemux = is_demuxer_element (src);
1.1075 +
1.1076 + if (isdemux || newgroup) {
1.1077 + GstPad *mqpad;
1.1078 +
1.1079 + GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
1.1080 +
1.1081 + if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
1.1082 + goto beach;
1.1083 + pad = mqpad;
1.1084 + }
1.1085 +
1.1086 + gst_decode_group_control_source_pad (group, pad);
1.1087 +
1.1088 + if (newgroup && !isdemux) {
1.1089 + /* If we have discovered a raw pad and it doesn't belong to any group,
1.1090 + * that means there wasn't any demuxer. In that case, we consider the
1.1091 + * group as being complete. */
1.1092 + gst_decode_group_set_complete (group);
1.1093 + }
1.1094 +beach:
1.1095 + return;
1.1096 +}
1.1097 +
1.1098 +static void
1.1099 +type_found (GstElement * typefind, guint probability,
1.1100 + GstCaps * caps, GstDecodeBin * decode_bin)
1.1101 +{
1.1102 + GstPad *pad;
1.1103 +
1.1104 + GST_STATE_LOCK (decode_bin);
1.1105 +
1.1106 + GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
1.1107 +
1.1108 + pad = gst_element_get_pad (typefind, "src");
1.1109 +
1.1110 + analyze_new_pad (decode_bin, typefind, pad, caps, NULL);
1.1111 +
1.1112 + gst_object_unref (pad);
1.1113 +
1.1114 + GST_STATE_UNLOCK (decode_bin);
1.1115 + return;
1.1116 +}
1.1117 +
1.1118 +static void
1.1119 +pad_added_group_cb (GstElement * element, GstPad * pad, GstDecodeGroup * group)
1.1120 +{
1.1121 + GstCaps *caps;
1.1122 + gboolean expose = FALSE;
1.1123 +
1.1124 + GST_LOG_OBJECT (pad, "pad added, group:%p", group);
1.1125 +
1.1126 + caps = gst_pad_get_caps (pad);
1.1127 + analyze_new_pad (group->dbin, element, pad, caps, group);
1.1128 + if (caps)
1.1129 + gst_caps_unref (caps);
1.1130 +
1.1131 + GROUP_MUTEX_LOCK (group);
1.1132 + group->nbdynamic--;
1.1133 + GST_LOG ("Group %p has now %d dynamic objects", group, group->nbdynamic);
1.1134 + if (group->nbdynamic == 0)
1.1135 + expose = TRUE;
1.1136 + GROUP_MUTEX_UNLOCK (group);
1.1137 + if (expose) {
1.1138 + GST_LOG
1.1139 + ("That was the last dynamic object, now attempting to expose the group");
1.1140 + DECODE_BIN_LOCK (group->dbin);
1.1141 + gst_decode_group_expose (group);
1.1142 + DECODE_BIN_UNLOCK (group->dbin);
1.1143 + }
1.1144 +}
1.1145 +
1.1146 +static void
1.1147 +pad_removed_group_cb (GstElement * element, GstPad * pad,
1.1148 + GstDecodeGroup * group)
1.1149 +{
1.1150 + GST_LOG_OBJECT (pad, "pad removed, group:%p", group);
1.1151 +
1.1152 + /* In fact, we don't have to do anything here, the active group will be
1.1153 + * removed when the group's multiqueue is drained */
1.1154 +}
1.1155 +
1.1156 +static void
1.1157 +no_more_pads_group_cb (GstElement * element, GstDecodeGroup * group)
1.1158 +{
1.1159 + GST_LOG_OBJECT (element, "no more pads, setting group %p to complete", group);
1.1160 +
1.1161 + /* FIXME : FILLME */
1.1162 + gst_decode_group_set_complete (group);
1.1163 +}
1.1164 +
1.1165 +static void
1.1166 +pad_added_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
1.1167 +{
1.1168 + GstCaps *caps;
1.1169 +
1.1170 + GST_LOG_OBJECT (pad, "Pad added to non-grouped element");
1.1171 +
1.1172 + caps = gst_pad_get_caps (pad);
1.1173 + analyze_new_pad (dbin, element, pad, caps, NULL);
1.1174 + if (caps)
1.1175 + gst_caps_unref (caps);
1.1176 +}
1.1177 +
1.1178 +static void
1.1179 +pad_removed_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
1.1180 +{
1.1181 + GST_LOG_OBJECT (pad, "Pad removed from non-grouped element");
1.1182 +}
1.1183 +
1.1184 +static void
1.1185 +no_more_pads_cb (GstElement * element, GstDecodeBin * dbin)
1.1186 +{
1.1187 + GstDecodeGroup *group;
1.1188 +
1.1189 + GST_LOG_OBJECT (element, "No more pads, setting current group to complete");
1.1190 +
1.1191 + /* Find the non-complete group, there should only be one */
1.1192 + if (!(group = get_current_group (dbin)))
1.1193 + goto no_group;
1.1194 +
1.1195 + gst_decode_group_set_complete (group);
1.1196 + return;
1.1197 +
1.1198 +no_group:
1.1199 + {
1.1200 + GST_WARNING_OBJECT (dbin, "We couldn't find a non-completed group !!");
1.1201 + return;
1.1202 + }
1.1203 +}
1.1204 +
1.1205 +/* this function runs through the element factories and returns a list
1.1206 + * of all elements that are able to sink the given caps
1.1207 + */
1.1208 +static GList *
1.1209 +find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
1.1210 +{
1.1211 + GList *factories;
1.1212 + GList *to_try = NULL;
1.1213 +
1.1214 + /* loop over all the factories */
1.1215 + for (factories = decode_bin->factories; factories;
1.1216 + factories = g_list_next (factories)) {
1.1217 + GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
1.1218 + const GList *templates;
1.1219 + GList *walk;
1.1220 +
1.1221 + /* get the templates from the element factory */
1.1222 + templates = gst_element_factory_get_static_pad_templates (factory);
1.1223 + for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
1.1224 + GstStaticPadTemplate *templ = walk->data;
1.1225 +
1.1226 + /* we only care about the sink templates */
1.1227 + if (templ->direction == GST_PAD_SINK) {
1.1228 + GstCaps *intersect;
1.1229 + GstCaps *tmpl_caps;
1.1230 +
1.1231 + /* try to intersect the caps with the caps of the template */
1.1232 + tmpl_caps = gst_static_caps_get (&templ->static_caps);
1.1233 +
1.1234 + intersect = gst_caps_intersect (caps, tmpl_caps);
1.1235 + gst_caps_unref (tmpl_caps);
1.1236 +
1.1237 + /* check if the intersection is empty */
1.1238 + if (!gst_caps_is_empty (intersect)) {
1.1239 + /* non empty intersection, we can use this element */
1.1240 + to_try = g_list_prepend (to_try, factory);
1.1241 + gst_caps_unref (intersect);
1.1242 + break;
1.1243 + }
1.1244 + gst_caps_unref (intersect);
1.1245 + }
1.1246 + }
1.1247 + }
1.1248 + to_try = g_list_reverse (to_try);
1.1249 +
1.1250 + return to_try;
1.1251 +}
1.1252 +
1.1253 +/* Decide whether an element is a demuxer based on the
1.1254 + * klass and number/type of src pad templates it has */
1.1255 +static gboolean
1.1256 +is_demuxer_element (GstElement * srcelement)
1.1257 +{
1.1258 + GstElementFactory *srcfactory;
1.1259 + GstElementClass *elemclass;
1.1260 + GList *templates, *walk;
1.1261 + const gchar *klass;
1.1262 + gint potential_src_pads = 0;
1.1263 +
1.1264 + srcfactory = gst_element_get_factory (srcelement);
1.1265 + klass = gst_element_factory_get_klass (srcfactory);
1.1266 +
1.1267 + /* Can't be a demuxer unless it has Demux in the klass name */
1.1268 + if (!strstr (klass, "Demux"))
1.1269 + return FALSE;
1.1270 +
1.1271 + /* Walk the src pad templates and count how many the element
1.1272 + * might produce */
1.1273 + elemclass = GST_ELEMENT_GET_CLASS (srcelement);
1.1274 +
1.1275 + walk = templates = gst_element_class_get_pad_template_list (elemclass);
1.1276 + while (walk != NULL) {
1.1277 + GstPadTemplate *templ;
1.1278 +
1.1279 + templ = (GstPadTemplate *) walk->data;
1.1280 + if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) {
1.1281 + switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
1.1282 + case GST_PAD_ALWAYS:
1.1283 + case GST_PAD_SOMETIMES:
1.1284 + if (strstr (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "%"))
1.1285 + potential_src_pads += 2; /* Might make multiple pads */
1.1286 + else
1.1287 + potential_src_pads += 1;
1.1288 + break;
1.1289 + case GST_PAD_REQUEST:
1.1290 + potential_src_pads += 2;
1.1291 + break;
1.1292 + }
1.1293 + }
1.1294 + walk = g_list_next (walk);
1.1295 + }
1.1296 +
1.1297 + if (potential_src_pads < 2)
1.1298 + return FALSE;
1.1299 +
1.1300 + return TRUE;
1.1301 +}
1.1302 +
1.1303 +/* Returns TRUE if the caps are raw, or if they are compatible with the caps
1.1304 + * specified in the 'caps' property
1.1305 + *
1.1306 + * The decodebin_lock should be taken !
1.1307 + */
1.1308 +static gboolean
1.1309 +are_raw_caps (GstDecodeBin * dbin, GstCaps * caps)
1.1310 +{
1.1311 + GstCaps *intersection;
1.1312 + gboolean res;
1.1313 +
1.1314 + GST_LOG_OBJECT (dbin, "Checking with caps %" GST_PTR_FORMAT, caps);
1.1315 +
1.1316 + intersection = gst_caps_intersect (dbin->caps, caps);
1.1317 +
1.1318 + res = (!(gst_caps_is_empty (intersection)));
1.1319 +
1.1320 + gst_caps_unref (intersection);
1.1321 +
1.1322 + GST_LOG_OBJECT (dbin, "Caps are %sfinal caps", res ? "" : "not ");
1.1323 +
1.1324 + return res;
1.1325 +}
1.1326 +
1.1327 +
1.1328 +/****
1.1329 + * GstDecodeGroup functions
1.1330 + ****/
1.1331 +
1.1332 +static void
1.1333 +multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group)
1.1334 +{
1.1335 + GST_LOG_OBJECT (group->dbin, "multiqueue is full");
1.1336 +
1.1337 + /* if we haven't exposed the group, do it */
1.1338 + DECODE_BIN_LOCK (group->dbin);
1.1339 + gst_decode_group_expose (group);
1.1340 + DECODE_BIN_UNLOCK (group->dbin);
1.1341 +}
1.1342 +
1.1343 +static void
1.1344 +multi_queue_underrun_cb (GstElement * queue, GstDecodeGroup * group)
1.1345 +{
1.1346 + GstDecodeBin *dbin = group->dbin;
1.1347 +
1.1348 + GST_LOG_OBJECT (dbin, "multiqueue is empty for group %p", group);
1.1349 +
1.1350 + /* Check if we need to activate another group */
1.1351 + DECODE_BIN_LOCK (dbin);
1.1352 + if ((group == dbin->activegroup) && dbin->groups) {
1.1353 + GST_DEBUG_OBJECT (dbin, "Switching to new group");
1.1354 + /* unexpose current active */
1.1355 + gst_decode_group_hide (group);
1.1356 +
1.1357 + /* expose first group of groups */
1.1358 + gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
1.1359 + }
1.1360 + DECODE_BIN_UNLOCK (dbin);
1.1361 +}
1.1362 +
1.1363 +/* gst_decode_group_new
1.1364 + *
1.1365 + * Creates a new GstDecodeGroup. It is up to the caller to add it to the list
1.1366 + * of groups.
1.1367 + */
1.1368 +static GstDecodeGroup *
1.1369 +gst_decode_group_new (GstDecodeBin * dbin)
1.1370 +{
1.1371 + GstDecodeGroup *group;
1.1372 + GstElement *mq;
1.1373 +
1.1374 + GST_LOG_OBJECT (dbin, "Creating new group");
1.1375 +
1.1376 + if (!(mq = gst_element_factory_make ("multiqueue", NULL))) {
1.1377 + GST_WARNING ("Couldn't create multiqueue element");
1.1378 + return NULL;
1.1379 + }
1.1380 +
1.1381 + g_object_set (G_OBJECT (mq),
1.1382 + "max-size-bytes", 2 * 1024 * 1024,
1.1383 + "max-size-time", 5 * GST_SECOND, "max-size-buffers", 0, NULL);
1.1384 +
1.1385 + group = g_new0 (GstDecodeGroup, 1);
1.1386 + group->lock = g_mutex_new ();
1.1387 + group->dbin = dbin;
1.1388 + group->multiqueue = mq;
1.1389 + group->exposed = FALSE;
1.1390 + group->drained = FALSE;
1.1391 + group->blocked = FALSE;
1.1392 + group->complete = FALSE;
1.1393 + group->endpads = NULL;
1.1394 +
1.1395 + group->overrunsig = g_signal_connect (G_OBJECT (mq), "overrun",
1.1396 + G_CALLBACK (multi_queue_overrun_cb), group);
1.1397 + group->underrunsig = g_signal_connect (G_OBJECT (mq), "underrun",
1.1398 + G_CALLBACK (multi_queue_underrun_cb), group);
1.1399 +
1.1400 + gst_bin_add (GST_BIN (dbin), group->multiqueue);
1.1401 + gst_element_set_state (group->multiqueue, GST_STATE_PAUSED);
1.1402 +
1.1403 + GST_LOG_OBJECT (dbin, "Returning new group %p", group);
1.1404 +
1.1405 + return group;
1.1406 +}
1.1407 +
1.1408 +/** get_current_group:
1.1409 + *
1.1410 + * Returns the current non-completed group.
1.1411 + *
1.1412 + * Returns NULL if no groups are available, or all groups are completed.
1.1413 + */
1.1414 +static GstDecodeGroup *
1.1415 +get_current_group (GstDecodeBin * dbin)
1.1416 +{
1.1417 + GList *tmp;
1.1418 + GstDecodeGroup *group = NULL;
1.1419 +
1.1420 + DECODE_BIN_LOCK (dbin);
1.1421 + for (tmp = dbin->groups; tmp; tmp = g_list_next (tmp)) {
1.1422 + GstDecodeGroup *this = (GstDecodeGroup *) tmp->data;
1.1423 +
1.1424 + GST_LOG_OBJECT (dbin, "group %p, complete:%d", this, this->complete);
1.1425 +
1.1426 + if (!this->complete) {
1.1427 + group = this;
1.1428 + break;
1.1429 + }
1.1430 + }
1.1431 + DECODE_BIN_UNLOCK (dbin);
1.1432 +
1.1433 + GST_LOG_OBJECT (dbin, "Returning group %p", group);
1.1434 +
1.1435 + return group;
1.1436 +}
1.1437 +
1.1438 +static gboolean
1.1439 +group_demuxer_event_probe (GstPad * pad, GstEvent * event,
1.1440 + GstDecodeGroup * group)
1.1441 +{
1.1442 + if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
1.1443 + GST_DEBUG_OBJECT (group->dbin,
1.1444 + "Got EOS on group input pads, exposing group if it wasn't before");
1.1445 + DECODE_BIN_LOCK (group->dbin);
1.1446 + gst_decode_group_expose (group);
1.1447 + DECODE_BIN_UNLOCK (group->dbin);
1.1448 + }
1.1449 + return TRUE;
1.1450 +}
1.1451 +
1.1452 +/* gst_decode_group_control_demuxer_pad
1.1453 + *
1.1454 + * Adds a new demuxer srcpad to the given group.
1.1455 + *
1.1456 + * Returns the srcpad of the multiqueue corresponding the given pad.
1.1457 + * Returns NULL if there was an error.
1.1458 + */
1.1459 +static GstPad *
1.1460 +gst_decode_group_control_demuxer_pad (GstDecodeGroup * group, GstPad * pad)
1.1461 +{
1.1462 + GstPad *srcpad, *sinkpad;
1.1463 + gchar *nb, *sinkname, *srcname;
1.1464 +
1.1465 + GST_LOG ("group:%p pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
1.1466 +
1.1467 + srcpad = NULL;
1.1468 +
1.1469 + if (!(sinkpad = gst_element_get_pad (group->multiqueue, "sink%d"))) {
1.1470 + GST_ERROR ("Couldn't get sinkpad from multiqueue");
1.1471 + return NULL;
1.1472 + }
1.1473 +
1.1474 + if ((gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
1.1475 + GST_ERROR ("Couldn't link demuxer and multiqueue");
1.1476 + goto beach;
1.1477 + }
1.1478 +
1.1479 + sinkname = gst_pad_get_name (sinkpad);
1.1480 + nb = sinkname + 4;
1.1481 + srcname = g_strdup_printf ("src%s", nb);
1.1482 + g_free (sinkname);
1.1483 +
1.1484 + GROUP_MUTEX_LOCK (group);
1.1485 +
1.1486 + if (!(srcpad = gst_element_get_pad (group->multiqueue, srcname))) {
1.1487 + GST_ERROR ("Couldn't get srcpad %s from multiqueue", srcname);
1.1488 + goto chiringuito;
1.1489 + }
1.1490 +
1.1491 + /* connect event handler on pad to intercept EOS events */
1.1492 + gst_pad_add_event_probe (pad, G_CALLBACK (group_demuxer_event_probe), group);
1.1493 +
1.1494 +chiringuito:
1.1495 + g_free (srcname);
1.1496 + GROUP_MUTEX_UNLOCK (group);
1.1497 +
1.1498 +beach:
1.1499 + gst_object_unref (sinkpad);
1.1500 + return srcpad;
1.1501 +}
1.1502 +
1.1503 +static gboolean
1.1504 +gst_decode_group_control_source_pad (GstDecodeGroup * group, GstPad * pad)
1.1505 +{
1.1506 + GstDecodePad *dpad;
1.1507 +
1.1508 + g_return_val_if_fail (group != NULL, FALSE);
1.1509 +
1.1510 + GST_LOG ("group:%p , pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
1.1511 +
1.1512 + /* FIXME : check if pad is already controlled */
1.1513 +
1.1514 + GROUP_MUTEX_LOCK (group);
1.1515 +
1.1516 + /* Create GstDecodePad for the pad */
1.1517 + dpad = gst_decode_pad_new (group, pad, TRUE);
1.1518 +
1.1519 + group->endpads = g_list_append (group->endpads, dpad);
1.1520 +
1.1521 + GROUP_MUTEX_UNLOCK (group);
1.1522 +
1.1523 + return TRUE;
1.1524 +}
1.1525 +
1.1526 +/* gst_decode_group_check_if_blocked:
1.1527 + *
1.1528 + * Call this when one of the pads blocked status has changed.
1.1529 + * If the group is complete and blocked, the group will be marked as blocked
1.1530 + * and will ghost/expose all pads on decodebin if the group is the current one.
1.1531 + *
1.1532 + * Call with the group lock taken ! MT safe
1.1533 + */
1.1534 +static void
1.1535 +gst_decode_group_check_if_blocked (GstDecodeGroup * group)
1.1536 +{
1.1537 + GList *tmp;
1.1538 + gboolean blocked = TRUE;
1.1539 +
1.1540 + GST_LOG ("group : %p , ->complete:%d , ->nbdynamic:%d",
1.1541 + group, group->complete, group->nbdynamic);
1.1542 +
1.1543 + /* 1. don't do anything if group is not complete */
1.1544 + if (!group->complete || group->nbdynamic) {
1.1545 + GST_DEBUG_OBJECT (group->dbin, "Group isn't complete yet");
1.1546 + return;
1.1547 + }
1.1548 +
1.1549 + for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
1.1550 + GstDecodePad *dpad = (GstDecodePad *) tmp->data;
1.1551 +
1.1552 + if (!dpad->blocked) {
1.1553 + blocked = FALSE;
1.1554 + break;
1.1555 + }
1.1556 + }
1.1557 +
1.1558 + /* 2. Update status of group */
1.1559 + group->blocked = blocked;
1.1560 + GST_LOG ("group is blocked:%d", blocked);
1.1561 +
1.1562 + /* 3. don't do anything if not blocked completely */
1.1563 + if (!blocked)
1.1564 + return;
1.1565 +
1.1566 + /* 4. if we're the current group, expose pads */
1.1567 + DECODE_BIN_LOCK (group->dbin);
1.1568 + if (!gst_decode_group_expose (group))
1.1569 + GST_WARNING_OBJECT (group->dbin, "Couldn't expose group");
1.1570 + DECODE_BIN_UNLOCK (group->dbin);
1.1571 +}
1.1572 +
1.1573 +static void
1.1574 +gst_decode_group_check_if_drained (GstDecodeGroup * group)
1.1575 +{
1.1576 + GList *tmp;
1.1577 + GstDecodeBin *dbin = group->dbin;
1.1578 + gboolean drained = TRUE;
1.1579 +
1.1580 + GST_LOG ("group : %p", group);
1.1581 +
1.1582 + for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
1.1583 + GstDecodePad *dpad = (GstDecodePad *) tmp->data;
1.1584 +
1.1585 + GST_LOG ("testing dpad %p", dpad);
1.1586 +
1.1587 + if (!dpad->drained) {
1.1588 + drained = FALSE;
1.1589 + break;
1.1590 + }
1.1591 + }
1.1592 +
1.1593 + group->drained = drained;
1.1594 + GST_LOG ("group is drained");
1.1595 +
1.1596 + if (!drained)
1.1597 + return;
1.1598 +
1.1599 + DECODE_BIN_LOCK (dbin);
1.1600 + if ((group == dbin->activegroup) && dbin->groups) {
1.1601 + GST_DEBUG_OBJECT (dbin, "Switching to new group");
1.1602 +
1.1603 + gst_decode_group_hide (group);
1.1604 +
1.1605 + gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
1.1606 + }
1.1607 + DECODE_BIN_UNLOCK (dbin);
1.1608 +}
1.1609 +
1.1610 +/* sort_end_pads:
1.1611 + * GCompareFunc to use with lists of GstPad.
1.1612 + * Sorts pads by mime type.
1.1613 + * First video (raw, then non-raw), then audio (raw, then non-raw),
1.1614 + * then others.
1.1615 + *
1.1616 + * Return: negative if a<b, 0 if a==b, positive if a>b
1.1617 + */
1.1618 +
1.1619 +static gint
1.1620 +sort_end_pads (GstDecodePad * da, GstDecodePad * db)
1.1621 +{
1.1622 + GstPad *a, *b;
1.1623 + gint va, vb;
1.1624 + GstCaps *capsa, *capsb;
1.1625 + GstStructure *sa, *sb;
1.1626 + const gchar *namea, *nameb;
1.1627 +
1.1628 + a = da->pad;
1.1629 + b = db->pad;
1.1630 +
1.1631 + capsa = gst_pad_get_caps (a);
1.1632 + capsb = gst_pad_get_caps (b);
1.1633 +
1.1634 + sa = gst_caps_get_structure ((const GstCaps *) capsa, 0);
1.1635 + sb = gst_caps_get_structure ((const GstCaps *) capsb, 0);
1.1636 +
1.1637 + namea = gst_structure_get_name (sa);
1.1638 + nameb = gst_structure_get_name (sb);
1.1639 +
1.1640 + if (g_strrstr (namea, "video/x-raw-"))
1.1641 + va = 0;
1.1642 + else if (g_strrstr (namea, "video/"))
1.1643 + va = 1;
1.1644 + else if (g_strrstr (namea, "audio/x-raw"))
1.1645 + va = 2;
1.1646 + else if (g_strrstr (namea, "audio/"))
1.1647 + va = 3;
1.1648 + else
1.1649 + va = 4;
1.1650 +
1.1651 + if (g_strrstr (nameb, "video/x-raw-"))
1.1652 + vb = 0;
1.1653 + else if (g_strrstr (nameb, "video/"))
1.1654 + vb = 1;
1.1655 + else if (g_strrstr (nameb, "audio/x-raw"))
1.1656 + vb = 2;
1.1657 + else if (g_strrstr (nameb, "audio/"))
1.1658 + vb = 3;
1.1659 + else
1.1660 + vb = 4;
1.1661 +
1.1662 + gst_caps_unref (capsa);
1.1663 + gst_caps_unref (capsb);
1.1664 +
1.1665 + return va - vb;
1.1666 +}
1.1667 +
1.1668 +/* gst_decode_group_expose:
1.1669 + *
1.1670 + * Expose this group's pads.
1.1671 + *
1.1672 + * Not MT safe, please take the group lock
1.1673 + */
1.1674 +
1.1675 +static gboolean
1.1676 +gst_decode_group_expose (GstDecodeGroup * group)
1.1677 +{
1.1678 + GList *tmp;
1.1679 + GList *next = NULL;
1.1680 +
1.1681 + if (group->dbin->activegroup) {
1.1682 + GST_DEBUG_OBJECT (group->dbin, "A group is already active and exposed");
1.1683 + return TRUE;
1.1684 + }
1.1685 +
1.1686 + if (group->dbin->activegroup == group) {
1.1687 + GST_WARNING ("Group %p is already exposed", group);
1.1688 + return TRUE;
1.1689 + }
1.1690 +
1.1691 + if (!group->dbin->groups
1.1692 + || (group != (GstDecodeGroup *) group->dbin->groups->data)) {
1.1693 + GST_WARNING ("Group %p is not the first group to expose", group);
1.1694 + return FALSE;
1.1695 + }
1.1696 +
1.1697 + if (group->nbdynamic) {
1.1698 + GST_WARNING ("Group %p still has %d dynamic objects, not exposing yet",
1.1699 + group, group->nbdynamic);
1.1700 + return FALSE;
1.1701 + }
1.1702 +
1.1703 + GST_LOG ("Exposing group %p", group);
1.1704 +
1.1705 + /* re-order pads : video, then audio, then others */
1.1706 + group->endpads = g_list_sort (group->endpads, (GCompareFunc) sort_end_pads);
1.1707 +
1.1708 + /* Expose pads */
1.1709 +
1.1710 + for (tmp = group->endpads; tmp; tmp = next) {
1.1711 + GstDecodePad *dpad = (GstDecodePad *) tmp->data;
1.1712 + gchar *padname;
1.1713 + GstPad *ghost;
1.1714 +
1.1715 + next = g_list_next (tmp);
1.1716 +
1.1717 + /* 1. ghost pad */
1.1718 + padname = g_strdup_printf ("src%d", group->dbin->nbpads);
1.1719 + group->dbin->nbpads++;
1.1720 +
1.1721 + GST_LOG_OBJECT (group->dbin, "About to expose pad %s:%s",
1.1722 + GST_DEBUG_PAD_NAME (dpad->pad));
1.1723 +
1.1724 + ghost = gst_ghost_pad_new (padname, dpad->pad);
1.1725 + gst_pad_set_active (ghost, TRUE);
1.1726 + gst_element_add_pad (GST_ELEMENT (group->dbin), ghost);
1.1727 + group->ghosts = g_list_append (group->ghosts, ghost);
1.1728 +
1.1729 + g_free (padname);
1.1730 +
1.1731 + /* 2. emit signal */
1.1732 + GST_DEBUG_OBJECT (group->dbin, "emitting new-decoded-pad");
1.1733 + g_signal_emit (G_OBJECT (group->dbin),
1.1734 + gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost,
1.1735 + (next == NULL));
1.1736 + GST_DEBUG_OBJECT (group->dbin, "emitted new-decoded-pad");
1.1737 +
1.1738 + /* 3. Unblock internal pad */
1.1739 + GST_DEBUG_OBJECT (dpad->pad, "unblocking");
1.1740 + gst_pad_set_blocked_async (dpad->pad, FALSE,
1.1741 + (GstPadBlockCallback) source_pad_blocked_cb, dpad);
1.1742 + GST_DEBUG_OBJECT (dpad->pad, "unblocked");
1.1743 +
1.1744 + }
1.1745 +
1.1746 + group->dbin->activegroup = group;
1.1747 +
1.1748 + /* pop off the first group */
1.1749 + group->dbin->groups =
1.1750 + g_list_delete_link (group->dbin->groups, group->dbin->groups);
1.1751 +
1.1752 + remove_fakesink (group->dbin);
1.1753 +
1.1754 + group->exposed = TRUE;
1.1755 +
1.1756 + GST_LOG_OBJECT (group->dbin, "signalling no-more-pads");
1.1757 + gst_element_no_more_pads (GST_ELEMENT (group->dbin));
1.1758 +
1.1759 + GST_LOG_OBJECT (group->dbin, "Group %p exposed", group);
1.1760 + return TRUE;
1.1761 +}
1.1762 +
1.1763 +static void
1.1764 +gst_decode_group_hide (GstDecodeGroup * group)
1.1765 +{
1.1766 + GList *tmp;
1.1767 +
1.1768 + GST_LOG ("Hiding group %p", group);
1.1769 +
1.1770 + if (group != group->dbin->activegroup) {
1.1771 + GST_WARNING ("This group is not the active one, aborting");
1.1772 + return;
1.1773 + }
1.1774 +
1.1775 + GROUP_MUTEX_LOCK (group);
1.1776 +
1.1777 + /* Remove ghost pads */
1.1778 + for (tmp = group->ghosts; tmp; tmp = g_list_next (tmp))
1.1779 + gst_element_remove_pad (GST_ELEMENT (group->dbin), (GstPad *) tmp->data);
1.1780 +
1.1781 + g_list_free (group->ghosts);
1.1782 + group->ghosts = NULL;
1.1783 +
1.1784 + group->exposed = FALSE;
1.1785 +
1.1786 + GROUP_MUTEX_UNLOCK (group);
1.1787 +
1.1788 + group->dbin->activegroup = NULL;
1.1789 + group->dbin->oldgroups = g_list_append (group->dbin->oldgroups, group);
1.1790 +}
1.1791 +
1.1792 +static void
1.1793 +deactivate_free_recursive (GstDecodeGroup * group, GstElement * element)
1.1794 +{
1.1795 + GstIterator *it;
1.1796 + GstIteratorResult res;
1.1797 + gpointer point;
1.1798 +
1.1799 + GST_LOG ("element:%s", GST_ELEMENT_NAME (element));
1.1800 +
1.1801 + /* call on downstream elements */
1.1802 + it = gst_element_iterate_src_pads (element);
1.1803 +
1.1804 +restart:
1.1805 +
1.1806 + while (1) {
1.1807 + res = gst_iterator_next (it, &point);
1.1808 + switch (res) {
1.1809 + case GST_ITERATOR_DONE:
1.1810 + goto done;
1.1811 + case GST_ITERATOR_RESYNC:
1.1812 + gst_iterator_resync (it);
1.1813 + goto restart;
1.1814 + case GST_ITERATOR_ERROR:
1.1815 + {
1.1816 + GST_WARNING ("Had an error while iterating source pads of element: %s",
1.1817 + GST_ELEMENT_NAME (element));
1.1818 + goto beach;
1.1819 + }
1.1820 + case GST_ITERATOR_OK:
1.1821 + {
1.1822 + GstPad *pad = GST_PAD (point);
1.1823 + GstPad *peerpad = NULL;
1.1824 +
1.1825 + if ((peerpad = gst_pad_get_peer (pad))) {
1.1826 + GstObject *parent = gst_pad_get_parent (peerpad);
1.1827 +
1.1828 + if (parent && GST_IS_ELEMENT (parent))
1.1829 + deactivate_free_recursive (group, GST_ELEMENT (parent));
1.1830 + if (parent)
1.1831 + gst_object_unref (parent);
1.1832 + }
1.1833 + }
1.1834 + break;
1.1835 + default:
1.1836 + break;
1.1837 + }
1.1838 + }
1.1839 +
1.1840 +done:
1.1841 + gst_element_set_state (element, GST_STATE_NULL);
1.1842 + gst_bin_remove (GST_BIN (group->dbin), element);
1.1843 +
1.1844 +beach:
1.1845 + gst_iterator_free (it);
1.1846 +
1.1847 + return;
1.1848 +}
1.1849 +
1.1850 +static void
1.1851 +gst_decode_group_free (GstDecodeGroup * group)
1.1852 +{
1.1853 + GList *tmp;
1.1854 +
1.1855 + GST_LOG ("group %p", group);
1.1856 +
1.1857 + GROUP_MUTEX_LOCK (group);
1.1858 + /* Clear all GstDecodePad */
1.1859 + for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
1.1860 + GstDecodePad *dpad = (GstDecodePad *) tmp->data;
1.1861 +
1.1862 + g_free (dpad);
1.1863 + }
1.1864 + g_list_free (group->endpads);
1.1865 + group->endpads = NULL;
1.1866 +
1.1867 + /* disconnect signal handlers on multiqueue */
1.1868 + g_signal_handler_disconnect (group->multiqueue, group->underrunsig);
1.1869 + g_signal_handler_disconnect (group->multiqueue, group->overrunsig);
1.1870 +
1.1871 + /* remove all elements */
1.1872 + deactivate_free_recursive (group, group->multiqueue);
1.1873 +
1.1874 + GROUP_MUTEX_UNLOCK (group);
1.1875 +
1.1876 + g_mutex_free (group->lock);
1.1877 + g_free (group);
1.1878 +}
1.1879 +
1.1880 +/* gst_decode_group_set_complete:
1.1881 + *
1.1882 + * Mark the group as complete. This means no more streams will be controlled
1.1883 + * through this group.
1.1884 + *
1.1885 + * MT safe
1.1886 + */
1.1887 +static void
1.1888 +gst_decode_group_set_complete (GstDecodeGroup * group)
1.1889 +{
1.1890 + GST_LOG_OBJECT (group->dbin, "Setting group %p to COMPLETE", group);
1.1891 +
1.1892 + GROUP_MUTEX_LOCK (group);
1.1893 + group->complete = TRUE;
1.1894 + gst_decode_group_check_if_blocked (group);
1.1895 + GROUP_MUTEX_UNLOCK (group);
1.1896 +}
1.1897 +
1.1898 +
1.1899 +
1.1900 +/*************************
1.1901 + * GstDecodePad functions
1.1902 + *************************/
1.1903 +
1.1904 +static void
1.1905 +source_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodePad * dpad)
1.1906 +{
1.1907 + GST_LOG_OBJECT (pad, "blocked:%d , dpad:%p, dpad->group:%p",
1.1908 + blocked, dpad, dpad->group);
1.1909 +
1.1910 + /* Update this GstDecodePad status */
1.1911 + dpad->blocked = blocked;
1.1912 +
1.1913 + if (blocked) {
1.1914 + GROUP_MUTEX_LOCK (dpad->group);
1.1915 + gst_decode_group_check_if_blocked (dpad->group);
1.1916 + GROUP_MUTEX_UNLOCK (dpad->group);
1.1917 + }
1.1918 +}
1.1919 +
1.1920 +static gboolean
1.1921 +source_pad_event_probe (GstPad * pad, GstEvent * event, GstDecodePad * dpad)
1.1922 +{
1.1923 + GST_LOG_OBJECT (pad, "%s dpad:%p", GST_EVENT_TYPE_NAME (event), dpad);
1.1924 +
1.1925 + if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
1.1926 + /* Set our pad as drained */
1.1927 + dpad->drained = TRUE;
1.1928 +
1.1929 + /* Check if all pads are drained */
1.1930 + gst_decode_group_check_if_drained (dpad->group);
1.1931 + }
1.1932 +
1.1933 + return TRUE;
1.1934 +}
1.1935 +
1.1936 +/*gst_decode_pad_new:
1.1937 + *
1.1938 + * Creates a new GstDecodePad for the given pad.
1.1939 + * If block is TRUE, Sets the pad blocking asynchronously
1.1940 + */
1.1941 +
1.1942 +static GstDecodePad *
1.1943 +gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad, gboolean block)
1.1944 +{
1.1945 + GstDecodePad *dpad;
1.1946 +
1.1947 + dpad = g_new0 (GstDecodePad, 1);
1.1948 + dpad->pad = pad;
1.1949 + dpad->group = group;
1.1950 + dpad->blocked = FALSE;
1.1951 + dpad->drained = TRUE;
1.1952 +
1.1953 + if (block)
1.1954 + gst_pad_set_blocked_async (pad, TRUE,
1.1955 + (GstPadBlockCallback) source_pad_blocked_cb, dpad);
1.1956 + gst_pad_add_event_probe (pad, G_CALLBACK (source_pad_event_probe), dpad);
1.1957 + return dpad;
1.1958 +}
1.1959 +
1.1960 +
1.1961 +/*****
1.1962 + * Element add/remove
1.1963 + *****/
1.1964 +
1.1965 +/*
1.1966 + * add_fakesink / remove_fakesink
1.1967 + *
1.1968 + * We use a sink so that the parent ::change_state returns GST_STATE_CHANGE_ASYNC
1.1969 + * when that sink is present (since it's not connected to anything it will
1.1970 + * always return GST_STATE_CHANGE_ASYNC).
1.1971 + *
1.1972 + * But this is an ugly way of achieving this goal.
1.1973 + * Ideally, we shouldn't use a sink and just return GST_STATE_CHANGE_ASYNC in
1.1974 + * our ::change_state if we have not exposed the active group.
1.1975 + * We also need to override ::get_state to fake the asynchronous behaviour.
1.1976 + * Once the active group is exposed, we would then post a
1.1977 + * GST_MESSAGE_STATE_DIRTY and return GST_STATE_CHANGE_SUCCESS (which will call
1.1978 + * ::get_state .
1.1979 + */
1.1980 +
1.1981 +static gboolean
1.1982 +add_fakesink (GstDecodeBin * decode_bin)
1.1983 +{
1.1984 + GST_DEBUG_OBJECT (decode_bin, "Adding the fakesink");
1.1985 +
1.1986 + if (decode_bin->fakesink)
1.1987 + return TRUE;
1.1988 +
1.1989 + decode_bin->fakesink =
1.1990 + gst_element_factory_make ("fakesink", "async-fakesink");
1.1991 + if (!decode_bin->fakesink)
1.1992 + goto no_fakesink;
1.1993 +
1.1994 + /* hacky, remove sink flag, we don't want our decodebin to become a sink
1.1995 + * just because we add a fakesink element to make us ASYNC */
1.1996 + GST_OBJECT_FLAG_UNSET (decode_bin->fakesink, GST_ELEMENT_IS_SINK);
1.1997 +
1.1998 + if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->fakesink))
1.1999 + goto could_not_add;
1.2000 +
1.2001 + return TRUE;
1.2002 +
1.2003 + /* ERRORS */
1.2004 +no_fakesink:
1.2005 + {
1.2006 + g_warning ("can't find fakesink element, decodebin will not work");
1.2007 + return FALSE;
1.2008 + }
1.2009 +could_not_add:
1.2010 + {
1.2011 + g_warning ("Could not add fakesink to decodebin, decodebin will not work");
1.2012 + gst_object_unref (decode_bin->fakesink);
1.2013 + decode_bin->fakesink = NULL;
1.2014 + return FALSE;
1.2015 + }
1.2016 +}
1.2017 +
1.2018 +static void
1.2019 +remove_fakesink (GstDecodeBin * decode_bin)
1.2020 +{
1.2021 + if (decode_bin->fakesink == NULL)
1.2022 + return;
1.2023 +
1.2024 + GST_DEBUG_OBJECT (decode_bin, "Removing the fakesink");
1.2025 +
1.2026 + gst_element_set_state (decode_bin->fakesink, GST_STATE_NULL);
1.2027 + gst_bin_remove (GST_BIN (decode_bin), decode_bin->fakesink);
1.2028 + decode_bin->fakesink = NULL;
1.2029 +
1.2030 + gst_element_post_message (GST_ELEMENT_CAST (decode_bin),
1.2031 + gst_message_new_state_dirty (GST_OBJECT_CAST (decode_bin)));
1.2032 +}
1.2033 +
1.2034 +/*****
1.2035 + * convenience functions
1.2036 + *****/
1.2037 +
1.2038 +/* find_sink_pad
1.2039 + *
1.2040 + * Returns the first sink pad of the given element, or NULL if it doesn't have
1.2041 + * any.
1.2042 + */
1.2043 +
1.2044 +static GstPad *
1.2045 +find_sink_pad (GstElement * element)
1.2046 +{
1.2047 + GstIterator *it;
1.2048 + GstPad *pad = NULL;
1.2049 + gpointer point;
1.2050 +
1.2051 + it = gst_element_iterate_sink_pads (element);
1.2052 +
1.2053 + if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
1.2054 + pad = (GstPad *) point;
1.2055 +
1.2056 + gst_iterator_free (it);
1.2057 +
1.2058 + return pad;
1.2059 +}
1.2060 +
1.2061 +static GstStateChangeReturn
1.2062 +gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
1.2063 +{
1.2064 + GstStateChangeReturn ret;
1.2065 + GstDecodeBin *dbin = GST_DECODE_BIN (element);
1.2066 +
1.2067 + switch (transition) {
1.2068 + case GST_STATE_CHANGE_NULL_TO_READY:
1.2069 + if (dbin->typefind == NULL)
1.2070 + goto missing_typefind;
1.2071 + break;
1.2072 + case GST_STATE_CHANGE_READY_TO_PAUSED:{
1.2073 + if (!add_fakesink (dbin))
1.2074 + goto missing_fakesink;
1.2075 + break;
1.2076 + }
1.2077 + default:
1.2078 + break;
1.2079 + }
1.2080 +
1.2081 + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1.2082 +
1.2083 + /* FIXME : put some cleanup functions here.. if needed */
1.2084 +
1.2085 + return ret;
1.2086 +
1.2087 +/* ERRORS */
1.2088 +missing_typefind:
1.2089 + {
1.2090 + GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no typefind!"));
1.2091 + return GST_STATE_CHANGE_FAILURE;
1.2092 + }
1.2093 +missing_fakesink:
1.2094 + {
1.2095 + GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no fakesink!"));
1.2096 + return GST_STATE_CHANGE_FAILURE;
1.2097 + }
1.2098 +}
1.2099 +
1.2100 +static gboolean
1.2101 +plugin_init (GstPlugin * plugin)
1.2102 +{
1.2103 + GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0,
1.2104 + "decoder bin");
1.2105 +
1.2106 + return gst_element_register (plugin, "decodebin2", GST_RANK_NONE,
1.2107 + GST_TYPE_DECODE_BIN);
1.2108 +}
1.2109 +
1.2110 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1.2111 + GST_VERSION_MINOR,
1.2112 + "decodebin2",
1.2113 + "decoder bin newer version", plugin_init, VERSION, GST_LICENSE,
1.2114 + GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)