--- a/gst_plugins_base/gst/playback/gstdecodebin2.c Wed Mar 31 22:03:18 2010 +0300
+++ b/gst_plugins_base/gst/playback/gstdecodebin2.c Tue Aug 31 15:30:33 2010 +0300
@@ -19,17 +19,16 @@
/**
* SECTION:element-decodebin2
- * @short_description: Next-generation automatic decoding bin
*
* #GstBin that auto-magically constructs a decoding pipeline using available
* decoders and demuxers via auto-plugging.
*
* At this stage, decodebin2 is considered UNSTABLE. The API provided in the
- * signals is expected to change in the near future.
+ * signals is expected to change in the near future.
*
- * To try out decodebin2, you can set the USE_DECODEBIN2 environment
+ * To try out decodebin2, you can set the USE_DECODEBIN2 environment
* variable (USE_DECODEBIN2=1 for example). This will cause playbin to use
- * decodebin2 instead of the older decodebin for its internal auto-plugging.
+ * decodebin2 instead of the older #GstDecodeBin for its internal auto-plugging.
*/
#ifdef HAVE_CONFIG_H
@@ -46,9 +45,6 @@
#include "gstplay-enum.h"
#include "gstfactorylists.h"
-#ifdef __SYMBIAN32__
-#include <glib_global.h>
-#endif
/* generic templates */
static GstStaticPadTemplate decoder_bin_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
@@ -67,6 +63,7 @@
typedef struct _GstDecodeGroup GstDecodeGroup;
typedef struct _GstDecodePad GstDecodePad;
+typedef GstGhostPadClass GstDecodePadClass;
typedef struct _GstDecodeBin GstDecodeBin;
typedef struct _GstDecodeBin GstDecodeBin2;
typedef struct _GstDecodeBinClass GstDecodeBinClass;
@@ -92,7 +89,6 @@
gchar *encoding; /* encoding of subtitles */
GstElement *typefind; /* this holds the typefind object */
- GstElement *fakesink;
GMutex *lock; /* Protects activegroup and groups */
GstDecodeGroup *activegroup; /* group currently active */
@@ -103,9 +99,16 @@
gint nbpads; /* unique identifier for source pads */
GValueArray *factories; /* factories we can use for selecting elements */
+ GList *subtitles; /* List of elements with subtitle-encoding */
gboolean have_type; /* if we received the have_type signal */
guint have_type_id; /* signal id for have-type from typefind */
+
+ gboolean async_pending; /* async-start has been emited */
+
+ GMutex *dyn_lock; /* lock protecting pad blocking */
+ gboolean shutdown; /* if we are shutting down */
+ GList *blocked_pads; /* pads that have set to block */
};
struct _GstDecodeBinClass
@@ -155,7 +158,9 @@
{
PROP_0,
PROP_CAPS,
- PROP_SUBTITLE_ENCODING
+ PROP_SUBTITLE_ENCODING,
+ PROP_SINK_CAPS,
+ PROP_LAST
};
static GstBinClass *parent_class;
@@ -168,8 +173,8 @@
"Edward Hervey <edward@fluendo.com>");
-static gboolean add_fakesink (GstDecodeBin * decode_bin);
-static void remove_fakesink (GstDecodeBin * decode_bin);
+static void do_async_start (GstDecodeBin * dbin);
+static void do_async_done (GstDecodeBin * dbin);
static void type_found (GstElement * typefind, guint probability,
GstCaps * caps, GstDecodeBin * decode_bin);
@@ -215,6 +220,23 @@
g_mutex_unlock (GST_DECODE_BIN_CAST(dbin)->lock); \
} G_STMT_END
+#define DECODE_BIN_DYN_LOCK(dbin) G_STMT_START { \
+ GST_LOG_OBJECT (dbin, \
+ "dynlocking from thread %p", \
+ g_thread_self ()); \
+ g_mutex_lock (GST_DECODE_BIN_CAST(dbin)->dyn_lock); \
+ GST_LOG_OBJECT (dbin, \
+ "dynlocked from thread %p", \
+ g_thread_self ()); \
+} G_STMT_END
+
+#define DECODE_BIN_DYN_UNLOCK(dbin) G_STMT_START { \
+ GST_LOG_OBJECT (dbin, \
+ "dynunlocking from thread %p", \
+ g_thread_self ()); \
+ g_mutex_unlock (GST_DECODE_BIN_CAST(dbin)->dyn_lock); \
+} G_STMT_END
+
/* GstDecodeGroup
*
* Streams belonging to the same group/chain of a media file
@@ -225,17 +247,16 @@
GstDecodeBin *dbin;
GMutex *lock;
GstElement *multiqueue;
+
gboolean exposed; /* TRUE if this group is exposed */
- gboolean drained; /* TRUE if EOS went throug all endpads */
+ gboolean drained; /* TRUE if EOS went through all endpads */
gboolean blocked; /* TRUE if all endpads are blocked */
gboolean complete; /* TRUE if we are not expecting anymore streams
* on this group */
- gulong overrunsig;
- gulong underrunsig;
+ gulong overrunsig; /* the overrun signal for multiqueue */
guint nbdynamic; /* number of dynamic pads in the group. */
GList *endpads; /* List of GstDecodePad of source pads to be exposed */
- GList *ghosts; /* List of GstGhostPad for the endpads */
GList *reqpads; /* List of RequestPads for multiqueue. */
};
@@ -262,9 +283,9 @@
static GstPad *gst_decode_group_control_demuxer_pad (GstDecodeGroup * group,
GstPad * pad);
static gboolean gst_decode_group_control_source_pad (GstDecodeGroup * group,
- GstPad * pad);
+ GstDecodePad * pad);
static gboolean gst_decode_group_expose (GstDecodeGroup * group);
-static void gst_decode_group_check_if_blocked (GstDecodeGroup * group);
+static gboolean gst_decode_group_check_if_blocked (GstDecodeGroup * group);
static void gst_decode_group_set_complete (GstDecodeGroup * group);
static void gst_decode_group_hide (GstDecodeGroup * group);
static void gst_decode_group_free (GstDecodeGroup * group);
@@ -273,28 +294,26 @@
*
* GstPad private used for source pads of groups
*/
-
struct _GstDecodePad
{
- GstPad *pad;
- GstDecodeGroup *group;
- gboolean blocked;
- gboolean drained;
-};
-
-static GstDecodePad *gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad,
- gboolean block);
-static void source_pad_blocked_cb (GstPad * pad, gboolean blocked,
- GstDecodePad * dpad);
-
-/* TempPadStruct
- * Internal structure used for pads which have more than one structure.
- */
-typedef struct _TempPadStruct
-{
+ GstGhostPad parent;
GstDecodeBin *dbin;
GstDecodeGroup *group;
-} TempPadStruct;
+
+ gboolean blocked; /* the pad is blocked */
+ gboolean drained; /* an EOS has been seen on the pad */
+ gboolean added; /* the pad is added to decodebin */
+};
+
+G_DEFINE_TYPE (GstDecodePad, gst_decode_pad, GST_TYPE_GHOST_PAD);
+#define GST_TYPE_DECODE_PAD (gst_decode_pad_get_type ())
+#define GST_DECODE_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECODE_PAD,GstDecodePad))
+
+static GstDecodePad *gst_decode_pad_new (GstDecodeBin * dbin, GstPad * pad,
+ GstDecodeGroup * group);
+static void gst_decode_pad_activate (GstDecodePad * dpad,
+ GstDecodeGroup * group);
+static void gst_decode_pad_unblock (GstDecodePad * dpad);
/********************************
* Standard GObject boilerplate *
@@ -393,7 +412,8 @@
/**
* GstDecodeBin2::new-decoded-pad:
- * @pad: the newly created pad
+ * @bin: The decodebin
+ * @pad: The newly created pad
* @islast: #TRUE if this is the last pad to be added. Deprecated.
*
* This signal gets emitted as soon as a new pad of the same type as one of
@@ -408,7 +428,8 @@
/**
* GstDecodeBin2::removed-decoded-pad:
- * @pad: the pad that was removed
+ * @bin: The decodebin
+ * @pad: The pad that was removed
*
* This signal is emitted when a 'final' caps pad has been removed.
*/
@@ -420,8 +441,10 @@
/**
* GstDecodeBin2::unknown-type:
- * @pad: the new pad containing caps that cannot be resolved to a 'final' stream type.
- * @caps: the #GstCaps of the pad that cannot be resolved.
+ * @bin: The decodebin
+ * @pad: The new pad containing caps that cannot be resolved to a 'final'
+ * stream type.
+ * @caps: The #GstCaps of the pad that cannot be resolved.
*
* This signal is emitted when a pad for which there is no further possible
* decoding is added to the decodebin.
@@ -429,11 +452,12 @@
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] =
g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
- NULL, NULL, gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2,
+ NULL, NULL, gst_marshal_VOID__OBJECT_BOXED, G_TYPE_NONE, 2,
GST_TYPE_PAD, GST_TYPE_CAPS);
/**
* GstDecodeBin2::autoplug-continue:
+ * @bin: The decodebin
* @pad: The #GstPad.
* @caps: The #GstCaps found.
*
@@ -448,11 +472,12 @@
gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE] =
g_signal_new ("autoplug-continue", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_continue),
- _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT_OBJECT,
+ _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT_BOXED,
G_TYPE_BOOLEAN, 2, GST_TYPE_PAD, GST_TYPE_CAPS);
/**
* GstDecodeBin2::autoplug-factories:
+ * @bin: The decodebin
* @pad: The #GstPad.
* @caps: The #GstCaps found.
*
@@ -473,11 +498,12 @@
g_signal_new ("autoplug-factories", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass,
autoplug_factories), _gst_array_accumulator, NULL,
- gst_play_marshal_BOXED__OBJECT_OBJECT, G_TYPE_VALUE_ARRAY, 2,
+ gst_play_marshal_BOXED__OBJECT_BOXED, G_TYPE_VALUE_ARRAY, 2,
GST_TYPE_PAD, GST_TYPE_CAPS);
/**
* GstDecodeBin2::autoplug-sort:
+ * @bin: The decodebin
* @pad: The #GstPad.
* @caps: The #GstCaps.
* @factories: A #GValueArray of possible #GstElementFactory to use.
@@ -494,34 +520,47 @@
gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT] =
g_signal_new ("autoplug-sort", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_sort),
- NULL, NULL, gst_play_marshal_BOXED__OBJECT_OBJECT_BOXED,
+ NULL, NULL, gst_play_marshal_BOXED__OBJECT_BOXED_BOXED,
G_TYPE_VALUE_ARRAY, 3, GST_TYPE_PAD, GST_TYPE_CAPS, G_TYPE_VALUE_ARRAY);
/**
* GstDecodeBin2::autoplug-select:
+ * @bin: The decodebin
* @pad: The #GstPad.
* @caps: The #GstCaps.
- * @factories: A #GValueArray of possible #GstElementFactory to use, sorted by
- * rank (higher ranks come first).
+ * @factory: A #GstElementFactory to use
*
* This signal is emitted once decodebin2 has found all the possible
- * #GstElementFactory that can be used to handle the given @caps.
+ * #GstElementFactory that can be used to handle the given @caps. For each of
+ * those factories, this signal is emited.
+ *
+ * The signal handler should return a #GST_TYPE_AUTOPLUG_SELECT_RESULT enum
+ * value indicating what decodebin2 should do next.
+ *
+ * A value of #GST_AUTOPLUG_SELECT_TRY will try to autoplug an element from
+ * @factory.
*
- * Returns: A #gint indicating what factory index from the @factories array
- * that you wish decodebin2 to use for trying to decode the given @caps.
- * Return -1 to stop selection of a factory and expose the pad as a raw type.
- * The default handler always returns the first possible factory (index 0).
+ * A value of #GST_AUTOPLUG_SELECT_EXPOSE will expose @pad without plugging
+ * any element to it.
+ *
+ * A value of #GST_AUTOPLUG_SELECT_SKIP will skip @factory and move to the
+ * next factory.
+ *
+ * Returns: a #GST_TYPE_AUTOPLUG_SELECT_RESULT that indicates the required
+ * operation. the default handler will always return
+ * #GST_AUTOPLUG_SELECT_TRY.
*/
gst_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT] =
g_signal_new ("autoplug-select", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_select),
_gst_select_accumulator, NULL,
- gst_play_marshal_ENUM__OBJECT_OBJECT_OBJECT,
+ gst_play_marshal_ENUM__OBJECT_BOXED_OBJECT,
GST_TYPE_AUTOPLUG_SELECT_RESULT, 3, GST_TYPE_PAD, GST_TYPE_CAPS,
GST_TYPE_ELEMENT_FACTORY);
/**
* GstDecodeBin2::drained
+ * @bin: The decodebin
*
* This signal is emitted once decodebin2 has finished decoding all the data.
*
@@ -534,14 +573,20 @@
g_object_class_install_property (gobject_klass, PROP_CAPS,
g_param_spec_boxed ("caps", "Caps", "The caps on which to stop decoding.",
- GST_TYPE_CAPS, G_PARAM_READWRITE));
+ GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
g_param_spec_string ("subtitle-encoding", "subtitle encoding",
"Encoding to assume if input subtitles are not in UTF-8 encoding. "
"If not set, the GST_SUBTITLE_ENCODING environment variable will "
"be checked for an encoding to use. If that is not set either, "
- "ISO-8859-15 will be assumed.", NULL, G_PARAM_READWRITE));
+ "ISO-8859-15 will be assumed.", NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_klass, PROP_SINK_CAPS,
+ g_param_spec_boxed ("sink-caps", "Sink Caps",
+ "The caps of the input data. (NULL = use typefind element)",
+ GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
klass->autoplug_continue =
GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_continue);
@@ -584,7 +629,7 @@
}
/* get the sinkpad */
- pad = gst_element_get_pad (decode_bin->typefind, "sink");
+ pad = gst_element_get_static_pad (decode_bin->typefind, "sink");
/* ghost the sink pad to ourself */
gpad = gst_ghost_pad_new ("sink", pad);
@@ -604,20 +649,96 @@
decode_bin->activegroup = NULL;
decode_bin->groups = NULL;
+ decode_bin->dyn_lock = g_mutex_new ();
+ decode_bin->shutdown = FALSE;
+ decode_bin->blocked_pads = NULL;
+
decode_bin->caps =
gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray;"
- "audio/x-raw-int;audio/x-raw-float;" "text/plain;text/x-pango-markup");
-
- add_fakesink (decode_bin);
-
- /* FILLME */
+ "audio/x-raw-int;audio/x-raw-float;" "text/plain;text/x-pango-markup;"
+ "video/x-dvd-subpicture; subpicture/x-pgs");
+}
+
+static void
+gst_decode_bin_remove_groups (GstDecodeBin * dbin)
+{
+ GList *tmp;
+ GstIterator *it;
+ gpointer point;
+ gboolean done;
+ GstIteratorResult res;
+
+ GST_DEBUG_OBJECT (dbin, "cleaning up");
+
+ if (dbin->activegroup) {
+ GST_DEBUG_OBJECT (dbin, "free active group %p", dbin->activegroup);
+ gst_decode_group_free (dbin->activegroup);
+ dbin->activegroup = NULL;
+ }
+
+ /* remove groups */
+ for (tmp = dbin->groups; tmp; tmp = g_list_next (tmp)) {
+ GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
+
+ GST_DEBUG_OBJECT (dbin, "free group %p", group);
+ gst_decode_group_free (group);
+ }
+ g_list_free (dbin->groups);
+ dbin->groups = NULL;
+
+ for (tmp = dbin->oldgroups; tmp; tmp = g_list_next (tmp)) {
+ GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
+
+ GST_DEBUG_OBJECT (dbin, "free old group %p", group);
+ gst_decode_group_free (group);
+ }
+ g_list_free (dbin->oldgroups);
+ dbin->oldgroups = NULL;
+
+ GST_DEBUG_OBJECT (dbin, "removing last elements");
+
+ /* remove all remaining elements */
+ it = gst_bin_iterate_elements (GST_BIN_CAST (dbin));
+restart:
+ done = FALSE;
+ while (!done) {
+ res = gst_iterator_next (it, &point);
+ switch (res) {
+ case GST_ITERATOR_DONE:
+ done = TRUE;
+ break;
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (it);
+ goto restart;
+ case GST_ITERATOR_ERROR:
+ GST_WARNING_OBJECT (dbin,
+ "Had an error while iterating bin %s", GST_ELEMENT_NAME (dbin));
+ done = TRUE;
+ break;
+ case GST_ITERATOR_OK:
+ {
+ GstElement *elem = GST_ELEMENT_CAST (point);
+
+ /* don't remove the typefind element */
+ if (elem != dbin->typefind) {
+ GST_DEBUG_OBJECT (dbin, "remove element %s", GST_ELEMENT_NAME (elem));
+ gst_bin_remove (GST_BIN_CAST (dbin), elem);
+ gst_element_set_state (elem, GST_STATE_NULL);
+ }
+ gst_object_unref (elem);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ gst_iterator_free (it);
}
static void
gst_decode_bin_dispose (GObject * object)
{
GstDecodeBin *decode_bin;
- GList *tmp;
decode_bin = GST_DECODE_BIN (object);
@@ -625,27 +746,7 @@
g_value_array_free (decode_bin->factories);
decode_bin->factories = NULL;
- if (decode_bin->activegroup) {
- gst_decode_group_free (decode_bin->activegroup);
- decode_bin->activegroup = NULL;
- }
-
- /* remove groups */
- for (tmp = decode_bin->groups; tmp; tmp = g_list_next (tmp)) {
- GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
-
- gst_decode_group_free (group);
- }
- g_list_free (decode_bin->groups);
- decode_bin->groups = NULL;
-
- for (tmp = decode_bin->oldgroups; tmp; tmp = g_list_next (tmp)) {
- GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
-
- gst_decode_group_free (group);
- }
- g_list_free (decode_bin->oldgroups);
- decode_bin->oldgroups = NULL;
+ gst_decode_bin_remove_groups (decode_bin);
if (decode_bin->caps)
gst_caps_unref (decode_bin->caps);
@@ -654,7 +755,8 @@
g_free (decode_bin->encoding);
decode_bin->encoding = NULL;
- remove_fakesink (decode_bin);
+ g_list_free (decode_bin->subtitles);
+ decode_bin->subtitles = NULL;
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -671,6 +773,11 @@
decode_bin->lock = NULL;
}
+ if (decode_bin->dyn_lock) {
+ g_mutex_free (decode_bin->dyn_lock);
+ decode_bin->dyn_lock = NULL;
+ }
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -685,15 +792,22 @@
static void
gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps)
{
+ GstCaps *old;
+
GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps);
- DECODE_BIN_LOCK (dbin);
- if (dbin->caps)
- gst_caps_unref (dbin->caps);
- if (caps)
- gst_caps_ref (caps);
- dbin->caps = caps;
- DECODE_BIN_UNLOCK (dbin);
+ GST_OBJECT_LOCK (dbin);
+ old = dbin->caps;
+ if (old != caps) {
+ if (caps)
+ gst_caps_ref (caps);
+
+ dbin->caps = caps;
+
+ if (old)
+ gst_caps_unref (old);
+ }
+ GST_OBJECT_UNLOCK (dbin);
}
/* _get_caps
@@ -702,7 +816,6 @@
*
* MT-safe
*/
-
static GstCaps *
gst_decode_bin_get_caps (GstDecodeBin * dbin)
{
@@ -710,11 +823,31 @@
GST_DEBUG_OBJECT (dbin, "Getting currently set caps");
- DECODE_BIN_LOCK (dbin);
+ GST_OBJECT_LOCK (dbin);
caps = dbin->caps;
if (caps)
gst_caps_ref (caps);
- DECODE_BIN_UNLOCK (dbin);
+ GST_OBJECT_UNLOCK (dbin);
+
+ return caps;
+}
+
+static void
+gst_decode_bin_set_sink_caps (GstDecodeBin * dbin, GstCaps * caps)
+{
+ GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps);
+
+ g_object_set (dbin->typefind, "force-caps", caps, NULL);
+}
+
+static GstCaps *
+gst_decode_bin_get_sink_caps (GstDecodeBin * dbin)
+{
+ GstCaps *caps;
+
+ GST_DEBUG_OBJECT (dbin, "Getting currently set caps");
+
+ g_object_get (dbin->typefind, "force-caps", &caps, NULL);
return caps;
}
@@ -722,11 +855,21 @@
static void
gst_decode_bin_set_subs_encoding (GstDecodeBin * dbin, const gchar * encoding)
{
+ GList *walk;
+
GST_DEBUG_OBJECT (dbin, "Setting new encoding: %s", GST_STR_NULL (encoding));
DECODE_BIN_LOCK (dbin);
+ GST_OBJECT_LOCK (dbin);
g_free (dbin->encoding);
dbin->encoding = g_strdup (encoding);
+ GST_OBJECT_UNLOCK (dbin);
+
+ /* set the subtitle encoding on all added elements */
+ for (walk = dbin->subtitles; walk; walk = g_list_next (walk)) {
+ g_object_set (G_OBJECT (walk->data), "subtitle-encoding", dbin->encoding,
+ NULL);
+ }
DECODE_BIN_UNLOCK (dbin);
}
@@ -737,9 +880,9 @@
GST_DEBUG_OBJECT (dbin, "Getting currently set encoding");
- DECODE_BIN_LOCK (dbin);
+ GST_OBJECT_LOCK (dbin);
encoding = g_strdup (dbin->encoding);
- DECODE_BIN_UNLOCK (dbin);
+ GST_OBJECT_UNLOCK (dbin);
return encoding;
}
@@ -759,6 +902,9 @@
case PROP_SUBTITLE_ENCODING:
gst_decode_bin_set_subs_encoding (dbin, g_value_get_string (value));
break;
+ case PROP_SINK_CAPS:
+ gst_decode_bin_set_sink_caps (dbin, g_value_get_boxed (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -779,6 +925,9 @@
case PROP_SUBTITLE_ENCODING:
g_value_take_string (value, gst_decode_bin_get_subs_encoding (dbin));
break;
+ case PROP_SINK_CAPS:
+ g_value_take_boxed (value, gst_decode_bin_get_sink_caps (dbin));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -786,9 +935,6 @@
}
-static GValueArray *find_compatibles (GstDecodeBin * decode_bin,
- GstPad * pad, const GstCaps * caps);
-
/*****
* Default autoplug signal handlers
*****/
@@ -808,8 +954,11 @@
{
GValueArray *result;
+ GST_DEBUG_OBJECT (element, "finding factories");
+
/* return all compatible factories for caps */
- result = find_compatibles (GST_DECODE_BIN (element), pad, caps);
+ result =
+ gst_factory_list_filter (GST_DECODE_BIN_CAST (element)->factories, caps);
GST_DEBUG_OBJECT (element, "autoplug-factories returns %p", result);
@@ -848,12 +997,12 @@
static gboolean is_demuxer_element (GstElement * srcelement);
static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src,
- GstPad * pad, GstCaps * caps, GValueArray * factories,
+ GstDecodePad * dpad, GstPad * pad, GstCaps * caps, GValueArray * factories,
GstDecodeGroup * group);
static gboolean connect_element (GstDecodeBin * dbin, GstElement * element,
GstDecodeGroup * group);
-static void expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
- GstDecodeGroup * group);
+static void expose_pad (GstDecodeBin * dbin, GstElement * src,
+ GstDecodePad * dpad, GstPad * pad, GstDecodeGroup * group);
static void pad_added_group_cb (GstElement * element, GstPad * pad,
GstDecodeGroup * group);
@@ -867,7 +1016,8 @@
GstDecodeBin * dbin);
static void no_more_pads_cb (GstElement * element, GstDecodeBin * dbin);
-static GstDecodeGroup *get_current_group (GstDecodeBin * dbin);
+static GstDecodeGroup *get_current_group (GstDecodeBin * dbin,
+ gboolean create, gboolean demux, gboolean * created);
/* called when a new pad is discovered. It will perform some basic actions
* before trying to link something to it.
@@ -887,6 +1037,7 @@
{
gboolean apcontinue = TRUE;
GValueArray *factories = NULL, *result = NULL;
+ GstDecodePad *dpad;
GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (pad), caps);
@@ -897,10 +1048,12 @@
if (gst_caps_is_any (caps))
goto any_caps;
+ dpad = gst_decode_pad_new (dbin, pad, group);
+
/* 1. Emit 'autoplug-continue' the result will tell us if this pads needs
* further autoplugging. */
g_signal_emit (G_OBJECT (dbin),
- gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, pad, caps,
+ gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, dpad, caps,
&apcontinue);
/* 1.a if autoplug-continue is FALSE or caps is a raw format, goto pad_is_final */
@@ -915,7 +1068,7 @@
/* 1.c else get the factories and if there's no compatible factory goto
* unknown_type */
g_signal_emit (G_OBJECT (dbin),
- gst_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES], 0, pad, caps,
+ gst_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES], 0, dpad, caps,
&factories);
/* NULL means that we can expose the pad */
@@ -926,20 +1079,22 @@
if (factories->n_values == 0) {
/* no compatible factories */
g_value_array_free (factories);
+ gst_object_unref (dpad);
goto unknown_type;
}
/* 1.d sort some more. */
g_signal_emit (G_OBJECT (dbin),
- gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT], 0, pad, caps, factories,
+ gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT], 0, dpad, caps, factories,
&result);
g_value_array_free (factories);
factories = result;
/* 1.e else continue autoplugging something from the list. */
GST_LOG_OBJECT (pad, "Let's continue discovery on this pad");
- connect_pad (dbin, src, pad, caps, factories, group);
-
+ connect_pad (dbin, src, dpad, pad, caps, factories, group);
+
+ gst_object_unref (dpad);
g_value_array_free (factories);
return;
@@ -947,7 +1102,8 @@
expose_pad:
{
GST_LOG_OBJECT (dbin, "Pad is final. autoplug-continue:%d", apcontinue);
- expose_pad (dbin, src, pad, group);
+ expose_pad (dbin, src, dpad, pad, group);
+ gst_object_unref (dpad);
return;
}
unknown_type:
@@ -956,9 +1112,10 @@
g_signal_emit (G_OBJECT (dbin),
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
- /* Check if there are no pending groups, if so, remove fakesink */
- if (dbin->groups == NULL)
- remove_fakesink (dbin);
+ /* Check if there are no pending groups, if so, commit our state */
+ if (dbin->groups == NULL) {
+ do_async_done (dbin);
+ }
if (src == dbin->typefind) {
gchar *desc;
@@ -979,6 +1136,7 @@
non_fixed:
{
GST_DEBUG_OBJECT (pad, "pad has non-fixed caps delay autoplugging");
+ gst_object_unref (dpad);
goto setup_caps_delay;
}
any_caps:
@@ -993,7 +1151,8 @@
if (group) {
GROUP_MUTEX_LOCK (group);
group->nbdynamic++;
- GST_LOG ("Group %p has now %d dynamic elements", group, group->nbdynamic);
+ GST_LOG_OBJECT (dbin, "Group %p has now %d dynamic elements", group,
+ group->nbdynamic);
GROUP_MUTEX_UNLOCK (group);
g_signal_connect (G_OBJECT (pad), "notify::caps",
G_CALLBACK (caps_notify_group_cb), group);
@@ -1010,11 +1169,15 @@
* Try to connect the given pad to an element created from one of the factories,
* and recursively.
*
+ * Note that dpad is ghosting pad, and so pad is linked; be sure to unset dpad's
+ * target before trying to link pad.
+ *
* Returns TRUE if an element was properly created and linked
*/
static gboolean
-connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
- GstCaps * caps, GValueArray * factories, GstDecodeGroup * group)
+connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
+ GstPad * pad, GstCaps * caps, GValueArray * factories,
+ GstDecodeGroup * group)
{
gboolean res = FALSE;
GstPad *mqpad = NULL;
@@ -1030,17 +1193,14 @@
GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
if (!group)
- if (!(group = get_current_group (dbin))) {
- group = gst_decode_group_new (dbin, TRUE);
- DECODE_BIN_LOCK (dbin);
- dbin->groups = g_list_append (dbin->groups, group);
- DECODE_BIN_UNLOCK (dbin);
- }
-
+ group = get_current_group (dbin, TRUE, TRUE, NULL);
+
+ gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), NULL);
if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
goto beach;
src = group->multiqueue;
pad = mqpad;
+ gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad);
}
/* 2. Try to create an element and link to it */
@@ -1049,6 +1209,7 @@
GstElementFactory *factory;
GstElement *element;
GstPad *sinkpad;
+ gboolean subtitle;
/* take first factory */
factory = g_value_get_object (g_value_array_get_nth (factories, 0));
@@ -1058,7 +1219,7 @@
/* emit autoplug-select to see what we should do with it. */
g_signal_emit (G_OBJECT (dbin),
gst_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT],
- 0, pad, caps, factory, &ret);
+ 0, dpad, caps, factory, &ret);
switch (ret) {
case GST_AUTOPLUG_SELECT_TRY:
@@ -1067,7 +1228,7 @@
case GST_AUTOPLUG_SELECT_EXPOSE:
GST_DEBUG_OBJECT (dbin, "autoplug select requested expose");
/* expose the pad, we don't have the source element */
- expose_pad (dbin, src, pad, group);
+ expose_pad (dbin, src, dpad, pad, group);
res = TRUE;
goto beach;
case GST_AUTOPLUG_SELECT_SKIP:
@@ -1078,6 +1239,9 @@
break;
}
+ /* 2.0. Unlink pad */
+ gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), NULL);
+
/* 2.1. Try to create an element */
if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
GST_WARNING_OBJECT (dbin, "Could not create an element from %s",
@@ -1100,6 +1264,7 @@
if (!(sinkpad = find_sink_pad (element))) {
GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
GST_ELEMENT_NAME (element));
+ gst_element_set_state (element, GST_STATE_NULL);
gst_object_unref (element);
continue;
}
@@ -1109,6 +1274,7 @@
GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
GST_ELEMENT_NAME (element));
gst_object_unref (sinkpad);
+ gst_element_set_state (element, GST_STATE_NULL);
gst_object_unref (element);
continue;
}
@@ -1128,6 +1294,17 @@
/* link this element further */
connect_element (dbin, element, group);
+ /* try to configure the subtitle encoding property when we can */
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (element),
+ "subtitle-encoding")) {
+ GST_DEBUG_OBJECT (dbin,
+ "setting subtitle-encoding=%s to element", dbin->encoding);
+ g_object_set (G_OBJECT (element), "subtitle-encoding", dbin->encoding,
+ NULL);
+ subtitle = TRUE;
+ } else
+ subtitle = FALSE;
+
/* Bring the element to the state of the parent */
if ((gst_element_set_state (element,
GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
@@ -1137,6 +1314,13 @@
gst_bin_remove (GST_BIN (dbin), element);
continue;
}
+ if (subtitle) {
+ DECODE_BIN_LOCK (dbin);
+ /* we added the element now, add it to the list of subtitle-encoding
+ * elements when we can set the property */
+ dbin->subtitles = g_list_prepend (dbin->subtitles, element);
+ DECODE_BIN_UNLOCK (dbin);
+ }
res = TRUE;
break;
@@ -1179,7 +1363,7 @@
case GST_PAD_ALWAYS:
{
/* get the pad that we need to autoplug */
- GstPad *pad = gst_element_get_pad (element, templ_name);
+ GstPad *pad = gst_element_get_static_pad (element, templ_name);
if (pad) {
GST_DEBUG_OBJECT (dbin, "got the pad for always template %s",
@@ -1198,7 +1382,7 @@
{
/* try to get the pad to see if it is already created or
* not */
- GstPad *pad = gst_element_get_pad (element, templ_name);
+ GstPad *pad = gst_element_get_static_pad (element, templ_name);
if (pad) {
GST_DEBUG_OBJECT (dbin, "got the pad for sometimes template %s",
@@ -1223,11 +1407,12 @@
/* 2. if there are more potential pads, connect to relevent signals */
if (dynamic) {
if (group) {
- GST_LOG ("Adding signals to element %s in group %p",
+ GST_LOG_OBJECT (dbin, "Adding signals to element %s in group %p",
GST_ELEMENT_NAME (element), group);
GROUP_MUTEX_LOCK (group);
group->nbdynamic++;
- GST_LOG ("Group %p has now %d dynamic elements", group, group->nbdynamic);
+ GST_LOG_OBJECT (dbin, "Group %p has now %d dynamic elements", group,
+ group->nbdynamic);
GROUP_MUTEX_UNLOCK (group);
g_signal_connect (G_OBJECT (element), "pad-added",
G_CALLBACK (pad_added_group_cb), group);
@@ -1269,8 +1454,8 @@
* If group is NULL, a GstDecodeGroup will be created and setup properly.
*/
static void
-expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
- GstDecodeGroup * group)
+expose_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
+ GstPad * pad, GstDecodeGroup * group)
{
gboolean newgroup = FALSE;
gboolean isdemux;
@@ -1282,23 +1467,19 @@
isdemux = is_demuxer_element (src);
if (!group)
- if (!(group = get_current_group (dbin))) {
- group = gst_decode_group_new (dbin, isdemux);
- DECODE_BIN_LOCK (dbin);
- dbin->groups = g_list_append (dbin->groups, group);
- DECODE_BIN_UNLOCK (dbin);
- newgroup = TRUE;
- }
+ group = get_current_group (dbin, TRUE, isdemux, &newgroup);
if (isdemux) {
GST_LOG_OBJECT (src, "connecting the pad through multiqueue");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), NULL);
if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
goto beach;
pad = mqpad;
+ gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad);
}
- gst_decode_group_control_source_pad (group, pad);
+ gst_decode_group_control_source_pad (group, dpad);
if (newgroup && !isdemux) {
/* If we have discovered a raw pad and it doesn't belong to any group,
@@ -1321,6 +1502,16 @@
GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
+ /* If the typefinder (but not something else) finds text/plain - i.e. that's
+ * the top-level type of the file - then error out.
+ */
+ if (gst_structure_has_name (gst_caps_get_structure (caps, 0), "text/plain")) {
+ GST_ELEMENT_ERROR (decode_bin, STREAM, WRONG_TYPE,
+ (_("This appears to be a text file")),
+ ("decodebin2 cannot decode plain text files"));
+ goto exit;
+ }
+
/* we can only deal with one type, we don't yet support dynamically changing
* caps from the typefind element */
if (decode_bin->have_type)
@@ -1343,27 +1534,33 @@
{
GstCaps *caps;
gboolean expose = FALSE;
+ GstDecodeBin *dbin;
+
+ dbin = group->dbin;
GST_DEBUG_OBJECT (pad, "pad added, group:%p", group);
caps = gst_pad_get_caps (pad);
- analyze_new_pad (group->dbin, element, pad, caps, group);
+ analyze_new_pad (dbin, element, pad, caps, group);
if (caps)
gst_caps_unref (caps);
GROUP_MUTEX_LOCK (group);
- group->nbdynamic--;
- GST_LOG ("Group %p has now %d dynamic objects", group, group->nbdynamic);
+ if (group->nbdynamic > 0)
+ group->nbdynamic--;
+ GST_LOG_OBJECT (dbin, "Group %p has now %d dynamic objects", group,
+ group->nbdynamic);
if (group->nbdynamic == 0)
expose = TRUE;
GROUP_MUTEX_UNLOCK (group);
if (expose) {
- GST_LOG
- ("That was the last dynamic object, now attempting to expose the group");
- DECODE_BIN_LOCK (group->dbin);
- gst_decode_group_expose (group);
- DECODE_BIN_UNLOCK (group->dbin);
+ GST_LOG_OBJECT (dbin,
+ "That was the last dynamic object, now attempting to expose the group");
+ DECODE_BIN_LOCK (dbin);
+ if (!gst_decode_group_expose (group))
+ GST_WARNING_OBJECT (dbin, "Couldn't expose group");
+ DECODE_BIN_UNLOCK (dbin);
}
}
@@ -1382,7 +1579,7 @@
{
GST_LOG_OBJECT (element, "no more pads, setting group %p to complete", group);
- /* FIXME : FILLME */
+ /* when we received no_more_pads, we can complete the pads of the group */
gst_decode_group_set_complete (group);
}
@@ -1413,15 +1610,16 @@
GST_LOG_OBJECT (element, "No more pads, setting current group to complete");
/* Find the non-complete group, there should only be one */
- if (!(group = get_current_group (dbin)))
+ if (!(group = get_current_group (dbin, FALSE, FALSE, NULL)))
goto no_group;
gst_decode_group_set_complete (group);
+
return;
no_group:
{
- GST_WARNING_OBJECT (dbin, "We couldn't find a non-completed group !!");
+ GST_DEBUG_OBJECT (dbin, "We couldn't find a non-completed group");
return;
}
}
@@ -1434,6 +1632,10 @@
GST_LOG_OBJECT (dbin, "Notified caps for pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
+ /* Disconnect this; if we still need it, we'll reconnect to this in
+ * analyze_new_pad */
+ g_signal_handlers_disconnect_by_func (pad, (gpointer*)caps_notify_cb, dbin);
+
element = GST_ELEMENT_CAST (gst_pad_get_parent (pad));
pad_added_cb (element, pad, dbin);
@@ -1448,6 +1650,10 @@
GST_LOG_OBJECT (pad, "Notified caps for pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+ /* Disconnect this; if we still need it, we'll reconnect to this in
+ * analyze_new_pad */
+ g_signal_handlers_disconnect_by_func (pad, (gpointer*)caps_notify_group_cb, group);
+
element = GST_ELEMENT_CAST (gst_pad_get_parent (pad));
pad_added_group_cb (element, pad, group);
@@ -1455,21 +1661,6 @@
gst_object_unref (element);
}
-/* this function runs through the element factories and returns a value array of
- * all elements that are able to sink the given caps
- */
-static GValueArray *
-find_compatibles (GstDecodeBin * decode_bin, GstPad * pad, const GstCaps * caps)
-{
- GValueArray *result;
-
- GST_DEBUG_OBJECT (decode_bin, "finding factories");
-
- result = gst_factory_list_filter (decode_bin->factories, caps);
-
- return result;
-}
-
/* Decide whether an element is a demuxer based on the
* klass and number/type of src pad templates it has */
static gboolean
@@ -1533,7 +1724,10 @@
GST_LOG_OBJECT (dbin, "Checking with caps %" GST_PTR_FORMAT, caps);
+ /* lock for getting the caps */
+ GST_OBJECT_LOCK (dbin);
intersection = gst_caps_intersect (dbin->caps, caps);
+ GST_OBJECT_UNLOCK (dbin);
res = (!(gst_caps_is_empty (intersection)));
@@ -1549,38 +1743,45 @@
* GstDecodeGroup functions
****/
+/* The overrun callback is used to expose groups that have not yet had their
+ * no_more_pads called while the (large) multiqueue overflowed. When this
+ * happens we must assume that the no_more_pads will not arrive anymore and we
+ * must expose the pads that we have.
+ */
static void
multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group)
{
- GST_LOG_OBJECT (group->dbin, "multiqueue is full");
-
- /* if we haven't exposed the group, do it */
- DECODE_BIN_LOCK (group->dbin);
- gst_decode_group_expose (group);
- DECODE_BIN_UNLOCK (group->dbin);
+ GstDecodeBin *dbin;
+ gboolean expose;
+
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "multiqueue %p is full", queue);
+
+ GROUP_MUTEX_LOCK (group);
+ if (group->complete) {
+ /* the group was already complete (had the no_more_pads called), we
+ * can ignore the overrun signal, the last remaining dynamic element
+ * will expose the group eventually. */
+ GST_LOG_OBJECT (dbin, "group %p was already complete", group);
+ expose = FALSE;
+ } else {
+ /* set number of dynamic element to 0, we don't expect anything anymore
+ * and we need the groups to be 0 for the expose to work */
+ group->nbdynamic = 0;
+ expose = TRUE;
+ }
+ GROUP_MUTEX_UNLOCK (group);
+
+ if (expose) {
+ DECODE_BIN_LOCK (dbin);
+ if (!gst_decode_group_expose (group))
+ GST_WARNING_OBJECT (dbin, "Couldn't expose group");
+ DECODE_BIN_UNLOCK (group->dbin);
+ }
}
-static void
-multi_queue_underrun_cb (GstElement * queue, GstDecodeGroup * group)
-{
- GstDecodeBin *dbin = group->dbin;
-
- GST_LOG_OBJECT (dbin, "multiqueue is empty for group %p", group);
-
- /* Check if we need to activate another group */
- DECODE_BIN_LOCK (dbin);
- if ((group == dbin->activegroup) && dbin->groups) {
- GST_DEBUG_OBJECT (dbin, "Switching to new group");
- /* unexpose current active */
- gst_decode_group_hide (group);
-
- /* expose first group of groups */
- gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
- }
- DECODE_BIN_UNLOCK (dbin);
-}
-
-/* gst_decode_group_new
+/* gst_decode_group_new:
*
* Creates a new GstDecodeGroup. It is up to the caller to add it to the list
* of groups.
@@ -1595,7 +1796,7 @@
if (use_queue) {
if (!(mq = gst_element_factory_make ("multiqueue", NULL))) {
- GST_WARNING ("Couldn't create multiqueue element");
+ GST_ERROR_OBJECT (dbin, "Couldn't create multiqueue element");
return NULL;
}
} else {
@@ -1619,15 +1820,11 @@
* memory. When this queue overruns, we assume the group is complete and can
* be exposed. */
g_object_set (G_OBJECT (mq),
- "max-size-bytes", 2 * 1024 * 1024,
- "max-size-time", 5 * GST_SECOND, "max-size-buffers", 0, NULL);
+ "max-size-bytes", (guint) 2 * 1024 * 1024,
+ "max-size-time", (guint64) 0, "max-size-buffers", (guint) 0, NULL);
/* will expose the group */
group->overrunsig = g_signal_connect (G_OBJECT (mq), "overrun",
G_CALLBACK (multi_queue_overrun_cb), group);
- /* will hide the group again, this is usually called when the multiqueue is
- * drained because of EOS. */
- group->underrunsig = g_signal_connect (G_OBJECT (mq), "underrun",
- G_CALLBACK (multi_queue_underrun_cb), group);
gst_bin_add (GST_BIN (dbin), mq);
gst_element_set_state (mq, GST_STATE_PAUSED);
@@ -1638,14 +1835,20 @@
return group;
}
-/** get_current_group:
+/* get_current_group:
+ * @dbin: the decodebin
+ * @create: create the group when not present
+ * @as_demux: create the group as a demuxer
+ * @created: result when the group was created
*
- * Returns the current non-completed group.
+ * Returns the current non-completed group. The dynamic refcount of the group is
+ * increased when dealing with a demuxer.
*
- * Returns NULL if no groups are available, or all groups are completed.
+ * Returns: %NULL if no groups are available, or all groups are completed.
*/
static GstDecodeGroup *
-get_current_group (GstDecodeBin * dbin)
+get_current_group (GstDecodeBin * dbin, gboolean create, gboolean as_demux,
+ gboolean * created)
{
GList *tmp;
GstDecodeGroup *group = NULL;
@@ -1654,13 +1857,27 @@
for (tmp = dbin->groups; tmp; tmp = g_list_next (tmp)) {
GstDecodeGroup *this = (GstDecodeGroup *) tmp->data;
+ GROUP_MUTEX_LOCK (this);
GST_LOG_OBJECT (dbin, "group %p, complete:%d", this, this->complete);
if (!this->complete) {
group = this;
+ GROUP_MUTEX_UNLOCK (this);
break;
+ } else {
+ GROUP_MUTEX_UNLOCK (this);
}
}
+ if (group == NULL && create) {
+ group = gst_decode_group_new (dbin, as_demux);
+ GST_LOG_OBJECT (dbin, "added group %p, demux %d", group, as_demux);
+ dbin->groups = g_list_prepend (dbin->groups, group);
+ if (created)
+ *created = TRUE;
+ /* demuxers are dynamic, we need no-more-pads or overrun now */
+ if (as_demux)
+ group->nbdynamic++;
+ }
DECODE_BIN_UNLOCK (dbin);
GST_LOG_OBJECT (dbin, "Returning group %p", group);
@@ -1668,20 +1885,6 @@
return group;
}
-static gboolean
-group_demuxer_event_probe (GstPad * pad, GstEvent * event,
- GstDecodeGroup * group)
-{
- if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
- GST_DEBUG_OBJECT (group->dbin,
- "Got EOS on group input pads, exposing group if it wasn't before");
- DECODE_BIN_LOCK (group->dbin);
- gst_decode_group_expose (group);
- DECODE_BIN_UNLOCK (group->dbin);
- }
- return TRUE;
-}
-
/* gst_decode_group_control_demuxer_pad
*
* Adds a new demuxer srcpad to the given group.
@@ -1692,24 +1895,27 @@
static GstPad *
gst_decode_group_control_demuxer_pad (GstDecodeGroup * group, GstPad * pad)
{
+ GstDecodeBin *dbin;
GstPad *srcpad, *sinkpad;
gchar *nb, *sinkname, *srcname;
- GST_LOG ("group:%p pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "group:%p pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
srcpad = NULL;
if (!(sinkpad = gst_element_get_request_pad (group->multiqueue, "sink%d"))) {
- GST_ERROR ("Couldn't get sinkpad from multiqueue");
+ GST_ERROR_OBJECT (dbin, "Couldn't get sinkpad from multiqueue");
return NULL;
}
if ((gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
- GST_ERROR ("Couldn't link demuxer and multiqueue");
+ GST_ERROR_OBJECT (dbin, "Couldn't link demuxer and multiqueue");
goto beach;
}
- group->reqpads = g_list_append (group->reqpads, sinkpad);
+ group->reqpads = g_list_prepend (group->reqpads, sinkpad);
sinkname = gst_pad_get_name (sinkpad);
nb = sinkname + 4;
@@ -1718,14 +1924,11 @@
GROUP_MUTEX_LOCK (group);
- if (!(srcpad = gst_element_get_pad (group->multiqueue, srcname))) {
- GST_ERROR ("Couldn't get srcpad %s from multiqueue", srcname);
+ if (!(srcpad = gst_element_get_static_pad (group->multiqueue, srcname))) {
+ GST_ERROR_OBJECT (dbin, "Couldn't get srcpad %s from multiqueue", srcname);
goto chiringuito;
}
- /* connect event handler on pad to intercept EOS events */
- gst_pad_add_event_probe (pad, G_CALLBACK (group_demuxer_event_probe), group);
-
chiringuito:
g_free (srcname);
GROUP_MUTEX_UNLOCK (group);
@@ -1736,23 +1939,18 @@
}
static gboolean
-gst_decode_group_control_source_pad (GstDecodeGroup * group, GstPad * pad)
+gst_decode_group_control_source_pad (GstDecodeGroup * group,
+ GstDecodePad * dpad)
{
- GstDecodePad *dpad;
-
g_return_val_if_fail (group != NULL, FALSE);
- GST_LOG ("group:%p , pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
+ GST_DEBUG_OBJECT (dpad, "adding decode pad to group %p", group);
/* FIXME : check if pad is already controlled */
+ gst_decode_pad_activate (dpad, group);
GROUP_MUTEX_LOCK (group);
-
- /* Create GstDecodePad for the pad */
- dpad = gst_decode_pad_new (group, pad, TRUE);
-
- group->endpads = g_list_append (group->endpads, dpad);
-
+ group->endpads = g_list_prepend (group->endpads, gst_object_ref (dpad));
GROUP_MUTEX_UNLOCK (group);
return TRUE;
@@ -1765,20 +1963,25 @@
* and will ghost/expose all pads on decodebin if the group is the current one.
*
* Call with the group lock taken ! MT safe
+ *
+ * Returns: TRUE when the group is completely blocked and ready to be exposed.
*/
-static void
+static gboolean
gst_decode_group_check_if_blocked (GstDecodeGroup * group)
{
+ GstDecodeBin *dbin;
GList *tmp;
gboolean blocked = TRUE;
- GST_LOG ("group : %p , ->complete:%d , ->nbdynamic:%d",
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "group : %p , ->complete:%d , ->nbdynamic:%d",
group, group->complete, group->nbdynamic);
- /* 1. don't do anything if group is not complete */
+ /* don't do anything if group is not complete */
if (!group->complete || group->nbdynamic) {
GST_DEBUG_OBJECT (group->dbin, "Group isn't complete yet");
- return;
+ return FALSE;
}
for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
@@ -1790,64 +1993,100 @@
}
}
- /* 2. Update status of group */
+ /* Update status of group */
group->blocked = blocked;
- GST_LOG ("group is blocked:%d", blocked);
-
- /* 3. don't do anything if not blocked completely */
- if (!blocked)
- return;
-
- /* 4. if we're the current group, expose pads */
- DECODE_BIN_LOCK (group->dbin);
- if (!gst_decode_group_expose (group))
- GST_WARNING_OBJECT (group->dbin, "Couldn't expose group");
- DECODE_BIN_UNLOCK (group->dbin);
+ GST_LOG_OBJECT (dbin, "group is blocked:%d", blocked);
+
+ return blocked;
}
+/* activate the next group when there is one
+ *
+ * Returns: TRUE when group was the active group and there was a
+ * next group to activate.
+ */
+static gboolean
+gst_decode_bin_activate_next_group (GstDecodeBin * dbin, GstDecodeGroup * group)
+{
+ gboolean have_next = FALSE;
+
+ DECODE_BIN_LOCK (dbin);
+ /* Check if there is a next group to activate */
+ if ((group == dbin->activegroup) && dbin->groups) {
+ GstDecodeGroup *newgroup;
+
+ /* get the next group */
+ newgroup = (GstDecodeGroup *) dbin->groups->data;
+
+ GST_DEBUG_OBJECT (dbin, "Switching to new group");
+
+ /* hide current group */
+ gst_decode_group_hide (group);
+ /* expose next group */
+ gst_decode_group_expose (newgroup);
+
+ /* we have a next group */
+ have_next = TRUE;
+ }
+ DECODE_BIN_UNLOCK (dbin);
+
+ return have_next;
+}
+
+/* check if the group is drained, meaning all pads have seen an EOS
+ * event. */
static void
-gst_decode_group_check_if_drained (GstDecodeGroup * group)
+gst_decode_pad_handle_eos (GstDecodePad * pad)
{
GList *tmp;
- GstDecodeBin *dbin = group->dbin;
+ GstDecodeBin *dbin;
+ GstDecodeGroup *group;
gboolean drained = TRUE;
- GST_LOG ("group : %p", group);
+ group = pad->group;
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "group : %p, pad %p", group, pad);
+
+ GROUP_MUTEX_LOCK (group);
+ /* mark pad as drained */
+ pad->drained = TRUE;
+
+ /* Ensure we only emit the drained signal once, for this group */
+ if (group->drained)
+ goto was_drained;
for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
GstDecodePad *dpad = (GstDecodePad *) tmp->data;
- GST_LOG ("testing dpad %p", dpad);
+ GST_LOG_OBJECT (dbin, "testing dpad %p %d", dpad, dpad->drained);
if (!dpad->drained) {
drained = FALSE;
break;
}
}
-
group->drained = drained;
- if (!drained)
- return;
-
- /* we are drained. Check if there is a next group to activate */
- DECODE_BIN_LOCK (dbin);
- if ((group == dbin->activegroup) && dbin->groups) {
- GST_DEBUG_OBJECT (dbin, "Switching to new group");
-
- /* hide current group */
- gst_decode_group_hide (group);
- /* expose next group */
- gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
- /* we're not yet drained now */
- drained = FALSE;
- }
- DECODE_BIN_UNLOCK (dbin);
+ GROUP_MUTEX_UNLOCK (group);
if (drained) {
- /* no more groups to activate, we're completely drained now */
- GST_LOG ("all groups drained, fire signal");
- g_signal_emit (G_OBJECT (dbin), gst_decode_bin_signals[SIGNAL_DRAINED], 0,
- NULL);
+ /* the current group is completely drained, try to activate the next
+ * group. this function returns FALSE if there was no next group activated
+ * and so we are really drained. */
+ if (!gst_decode_bin_activate_next_group (dbin, group)) {
+ /* no more groups to activate, we're completely drained now */
+ GST_LOG_OBJECT (dbin, "all groups drained, fire signal");
+ g_signal_emit (G_OBJECT (dbin), gst_decode_bin_signals[SIGNAL_DRAINED], 0,
+ NULL);
+ }
+ }
+ return;
+
+was_drained:
+ {
+ GST_LOG_OBJECT (dbin, "group was already drained");
+ GROUP_MUTEX_UNLOCK (group);
+ return;
}
}
@@ -1863,17 +2102,13 @@
static gint
sort_end_pads (GstDecodePad * da, GstDecodePad * db)
{
- GstPad *a, *b;
gint va, vb;
GstCaps *capsa, *capsb;
GstStructure *sa, *sb;
const gchar *namea, *nameb;
- a = da->pad;
- b = db->pad;
-
- capsa = gst_pad_get_caps (a);
- capsb = gst_pad_get_caps (b);
+ capsa = gst_pad_get_caps (GST_PAD (da));
+ capsb = gst_pad_get_caps (GST_PAD (db));
sa = gst_caps_get_structure ((const GstCaps *) capsa, 0);
sb = gst_caps_get_structure ((const GstCaps *) capsb, 0);
@@ -1913,146 +2148,159 @@
*
* Expose this group's pads.
*
- * Not MT safe, please take the group lock
+ * Not MT safe, please take the decodebin lock
*/
static gboolean
gst_decode_group_expose (GstDecodeGroup * group)
{
GList *tmp;
GList *next = NULL;
-
- if (group->dbin->activegroup) {
- GST_DEBUG_OBJECT (group->dbin, "A group is already active and exposed");
- return TRUE;
+ GstDecodeBin *dbin;
+
+ dbin = group->dbin;
+
+ GST_DEBUG_OBJECT (dbin, "going to expose group %p", group);
+
+ if (group->nbdynamic) {
+ GST_DEBUG_OBJECT (dbin,
+ "Group %p still has %d dynamic objects, not exposing yet", group,
+ group->nbdynamic);
+ return FALSE;
}
- if (group->dbin->activegroup == group) {
- GST_WARNING ("Group %p is already exposed", group);
+ if (dbin->activegroup == group) {
+ GST_DEBUG_OBJECT (dbin, "Group %p is already exposed, all is fine", group);
return TRUE;
}
- if (!group->dbin->groups
- || (group != (GstDecodeGroup *) group->dbin->groups->data)) {
- GST_WARNING ("Group %p is not the first group to expose", group);
- return FALSE;
- }
-
- if (group->nbdynamic) {
- GST_WARNING ("Group %p still has %d dynamic objects, not exposing yet",
- group, group->nbdynamic);
- return FALSE;
- }
-
- GST_LOG ("Exposing group %p", group);
-
if (group->multiqueue) {
/* update runtime limits. At runtime, we try to keep the amount of buffers
* in the queues as low as possible (but at least 5 buffers). */
g_object_set (G_OBJECT (group->multiqueue),
- "max-size-bytes", 2 * 1024 * 1024,
- "max-size-time", 2 * GST_SECOND, "max-size-buffers", 5, NULL);
+ "max-size-bytes", 2 * 1024 * 1024, "max-size-buffers", 5, NULL);
/* we can now disconnect any overrun signal, which is used to expose the
* group. */
if (group->overrunsig) {
- GST_LOG ("Disconnecting overrun");
+ GST_LOG_OBJECT (dbin, "Disconnecting overrun");
g_signal_handler_disconnect (group->multiqueue, group->overrunsig);
group->overrunsig = 0;
}
}
+ if (dbin->activegroup) {
+ GST_DEBUG_OBJECT (dbin,
+ "another group %p is already exposed, waiting for EOS",
+ dbin->activegroup);
+ return TRUE;
+ }
+
+ if (!dbin->groups || (group != (GstDecodeGroup *) dbin->groups->data)) {
+ GST_WARNING_OBJECT (dbin, "Group %p is not the first group to expose",
+ group);
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (dbin, "Exposing group %p", group);
+
/* re-order pads : video, then audio, then others */
group->endpads = g_list_sort (group->endpads, (GCompareFunc) sort_end_pads);
/* Expose pads */
-
for (tmp = group->endpads; tmp; tmp = next) {
GstDecodePad *dpad = (GstDecodePad *) tmp->data;
gchar *padname;
- GstPad *ghost;
next = g_list_next (tmp);
- /* 1. ghost pad */
- padname = g_strdup_printf ("src%d", group->dbin->nbpads);
- group->dbin->nbpads++;
-
- GST_LOG_OBJECT (group->dbin, "About to expose pad %s:%s",
- GST_DEBUG_PAD_NAME (dpad->pad));
-
- ghost = gst_ghost_pad_new (padname, dpad->pad);
- gst_pad_set_active (ghost, TRUE);
- gst_element_add_pad (GST_ELEMENT (group->dbin), ghost);
- group->ghosts = g_list_append (group->ghosts, ghost);
-
+ /* 1. rewrite name */
+ padname = g_strdup_printf ("src%d", dbin->nbpads);
+ dbin->nbpads++;
+ GST_DEBUG_OBJECT (dbin, "About to expose dpad %s as %s",
+ GST_OBJECT_NAME (dpad), padname);
+ gst_object_set_name (GST_OBJECT (dpad), padname);
g_free (padname);
- /* 2. emit signal */
- GST_DEBUG_OBJECT (group->dbin, "emitting new-decoded-pad");
- g_signal_emit (G_OBJECT (group->dbin),
- gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost,
+ /* 2. activate and add */
+ if (!gst_element_add_pad (GST_ELEMENT (dbin), GST_PAD (dpad))) {
+ /* not really fatal, we can try to add the other pads */
+ g_warning ("error adding pad to decodebin2");
+ continue;
+ }
+ dpad->added = TRUE;
+
+ /* 3. emit signal */
+ GST_DEBUG_OBJECT (dbin, "emitting new-decoded-pad");
+ g_signal_emit (G_OBJECT (dbin),
+ gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, dpad,
(next == NULL));
- GST_DEBUG_OBJECT (group->dbin, "emitted new-decoded-pad");
+ GST_DEBUG_OBJECT (dbin, "emitted new-decoded-pad");
}
/* signal no-more-pads. This allows the application to hook stuff to the
* exposed pads */
- GST_LOG_OBJECT (group->dbin, "signalling no-more-pads");
- gst_element_no_more_pads (GST_ELEMENT (group->dbin));
-
- /* 3. Unblock internal pads. The application should have connected stuff now
+ GST_LOG_OBJECT (dbin, "signalling no-more-pads");
+ gst_element_no_more_pads (GST_ELEMENT (dbin));
+
+ /* 4. Unblock internal pads. The application should have connected stuff now
* so that streaming can continue. */
for (tmp = group->endpads; tmp; tmp = next) {
GstDecodePad *dpad = (GstDecodePad *) tmp->data;
next = g_list_next (tmp);
- GST_DEBUG_OBJECT (dpad->pad, "unblocking");
- gst_pad_set_blocked_async (dpad->pad, FALSE,
- (GstPadBlockCallback) source_pad_blocked_cb, dpad);
- GST_DEBUG_OBJECT (dpad->pad, "unblocked");
+ GST_DEBUG_OBJECT (dpad, "unblocking");
+ gst_decode_pad_unblock (dpad);
+ GST_DEBUG_OBJECT (dpad, "unblocked");
}
- group->dbin->activegroup = group;
+ dbin->activegroup = group;
/* pop off the first group */
- group->dbin->groups =
- g_list_delete_link (group->dbin->groups, group->dbin->groups);
-
- remove_fakesink (group->dbin);
+ if (dbin->groups && dbin->groups->data) {
+ GST_LOG_OBJECT (dbin, "removed group %p", dbin->groups->data);
+ dbin->groups = g_list_delete_link (dbin->groups, dbin->groups);
+ } else {
+ GST_LOG_OBJECT (dbin, "no more groups");
+ }
+
+ do_async_done (dbin);
group->exposed = TRUE;
- GST_LOG_OBJECT (group->dbin, "Group %p exposed", group);
+ GST_LOG_OBJECT (dbin, "Group %p exposed", group);
return TRUE;
}
+/* must be called with the decodebin lock */
static void
gst_decode_group_hide (GstDecodeGroup * group)
{
GList *tmp;
-
- GST_LOG ("Hiding group %p", group);
-
- if (group != group->dbin->activegroup) {
- GST_WARNING ("This group is not the active one, aborting");
+ GstDecodeBin *dbin;
+
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "Hiding group %p", group);
+
+ if (group != dbin->activegroup) {
+ GST_WARNING_OBJECT (dbin, "This group is not the active one, ignoring");
return;
}
GROUP_MUTEX_LOCK (group);
-
/* Remove ghost pads */
- for (tmp = group->ghosts; tmp; tmp = g_list_next (tmp))
- gst_element_remove_pad (GST_ELEMENT (group->dbin), (GstPad *) tmp->data);
-
- g_list_free (group->ghosts);
- group->ghosts = NULL;
-
+ for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
+ GstDecodePad *dpad = (GstDecodePad *) tmp->data;
+
+ if (dpad->added)
+ gst_element_remove_pad (GST_ELEMENT (group->dbin), GST_PAD (dpad));
+ dpad->added = FALSE;
+ }
group->exposed = FALSE;
-
GROUP_MUTEX_UNLOCK (group);
group->dbin->activegroup = NULL;
- group->dbin->oldgroups = g_list_append (group->dbin->oldgroups, group);
+ group->dbin->oldgroups = g_list_prepend (group->dbin->oldgroups, group);
}
static void
@@ -2061,8 +2309,11 @@
GstIterator *it;
GstIteratorResult res;
gpointer point;
-
- GST_LOG ("element:%s", GST_ELEMENT_NAME (element));
+ GstDecodeBin *dbin;
+
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "element:%s", GST_ELEMENT_NAME (element));
/* call on downstream elements */
it = gst_element_iterate_src_pads (element);
@@ -2079,7 +2330,8 @@
goto restart;
case GST_ITERATOR_ERROR:
{
- GST_WARNING ("Had an error while iterating source pads of element: %s",
+ GST_WARNING_OBJECT (dbin,
+ "Had an error while iterating source pads of element: %s",
GST_ELEMENT_NAME (element));
goto beach;
}
@@ -2108,7 +2360,11 @@
done:
gst_element_set_state (element, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (group->dbin), element);
+ DECODE_BIN_LOCK (dbin);
+ /* remove possible subtitle element */
+ dbin->subtitles = g_list_remove (dbin->subtitles, element);
+ DECODE_BIN_UNLOCK (dbin);
+ gst_bin_remove (GST_BIN (dbin), element);
beach:
gst_iterator_free (it);
@@ -2119,27 +2375,29 @@
static void
gst_decode_group_free (GstDecodeGroup * group)
{
+ GstDecodeBin *dbin;
GList *tmp;
- GST_LOG ("group %p", group);
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "group %p", group);
GROUP_MUTEX_LOCK (group);
- /* free ghost pads */
- if (group == group->dbin->activegroup) {
- for (tmp = group->ghosts; tmp; tmp = g_list_next (tmp))
- gst_element_remove_pad (GST_ELEMENT (group->dbin), (GstPad *) tmp->data);
-
- g_list_free (group->ghosts);
- group->ghosts = NULL;
+ /* remove exposed pads */
+ if (group == dbin->activegroup) {
+ for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
+ GstDecodePad *dpad = (GstDecodePad *) tmp->data;
+
+ if (dpad->added)
+ gst_element_remove_pad (GST_ELEMENT (dbin), GST_PAD (dpad));
+ dpad->added = FALSE;
+ }
}
/* Clear all GstDecodePad */
- for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
- GstDecodePad *dpad = (GstDecodePad *) tmp->data;
-
- g_free (dpad);
- }
+ for (tmp = group->endpads; tmp; tmp = g_list_next (tmp))
+ gst_object_unref (tmp->data);
g_list_free (group->endpads);
group->endpads = NULL;
@@ -2152,8 +2410,6 @@
/* disconnect signal handlers on multiqueue */
if (group->multiqueue) {
- if (group->underrunsig)
- g_signal_handler_disconnect (group->multiqueue, group->underrunsig);
if (group->overrunsig)
g_signal_handler_disconnect (group->multiqueue, group->overrunsig);
deactivate_free_recursive (group, group->multiqueue);
@@ -2170,40 +2426,85 @@
/* gst_decode_group_set_complete:
*
* Mark the group as complete. This means no more streams will be controlled
- * through this group.
+ * through this group. This method is usually called when we got no_more_pads or
+ * when we added the last pad not from a demuxer.
+ *
+ * When this method is called, it is possible that some dynamic plugging is
+ * going on in streaming threads. We decrement the dynamic counter and when it
+ * reaches zero, we check if all of our pads are blocked before we finally
+ * expose the group.
*
* MT safe
*/
static void
gst_decode_group_set_complete (GstDecodeGroup * group)
{
- GST_LOG_OBJECT (group->dbin, "Setting group %p to COMPLETE", group);
+ gboolean expose = FALSE;
+ GstDecodeBin *dbin;
+
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dbin, "Setting group %p to COMPLETE", group);
GROUP_MUTEX_LOCK (group);
group->complete = TRUE;
- gst_decode_group_check_if_blocked (group);
+ if (group->nbdynamic > 0)
+ group->nbdynamic--;
+ expose = gst_decode_group_check_if_blocked (group);
GROUP_MUTEX_UNLOCK (group);
+
+ /* don't do anything if not blocked completely */
+ if (expose) {
+ DECODE_BIN_LOCK (dbin);
+ if (!gst_decode_group_expose (group))
+ GST_WARNING_OBJECT (dbin, "Couldn't expose group");
+ DECODE_BIN_UNLOCK (dbin);
+ }
}
-
-
/*************************
* GstDecodePad functions
*************************/
static void
-source_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodePad * dpad)
+gst_decode_pad_class_init (GstDecodePadClass * klass)
+{
+}
+
+static void
+gst_decode_pad_init (GstDecodePad * pad)
{
- GST_LOG_OBJECT (pad, "blocked:%d , dpad:%p, dpad->group:%p",
- blocked, dpad, dpad->group);
-
+ pad->group = NULL;
+ pad->blocked = FALSE;
+ pad->drained = FALSE;
+ gst_object_ref (pad);
+ gst_object_sink (pad);
+}
+
+static void
+source_pad_blocked_cb (GstDecodePad * dpad, gboolean blocked, gpointer unused)
+{
+ GstDecodeGroup *group;
+ GstDecodeBin *dbin;
+ gboolean expose = FALSE;
+
+ group = dpad->group;
+ dbin = group->dbin;
+
+ GST_LOG_OBJECT (dpad, "blocked:%d, dpad->group:%p", blocked, group);
+
+ GROUP_MUTEX_LOCK (group);
/* Update this GstDecodePad status */
dpad->blocked = blocked;
-
- if (blocked) {
- GROUP_MUTEX_LOCK (dpad->group);
- gst_decode_group_check_if_blocked (dpad->group);
- GROUP_MUTEX_UNLOCK (dpad->group);
+ if (blocked)
+ expose = gst_decode_group_check_if_blocked (group);
+ GROUP_MUTEX_UNLOCK (group);
+
+ if (expose) {
+ DECODE_BIN_LOCK (dbin);
+ if (!gst_decode_group_expose (group))
+ GST_WARNING_OBJECT (dbin, "Couldn't expose group");
+ DECODE_BIN_UNLOCK (dbin);
}
}
@@ -2213,40 +2514,82 @@
GST_LOG_OBJECT (pad, "%s dpad:%p", GST_EVENT_TYPE_NAME (event), dpad);
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
- /* Set our pad as drained */
- dpad->drained = TRUE;
-
GST_DEBUG_OBJECT (pad, "we received EOS");
/* Check if all pads are drained. If there is a next group to expose, we
* will remove the ghostpad of the current group first, which unlinks the
* peer and so drops the EOS. */
- gst_decode_group_check_if_drained (dpad->group);
+ gst_decode_pad_handle_eos (dpad);
}
/* never drop events */
return TRUE;
}
+static void
+gst_decode_pad_set_blocked (GstDecodePad * dpad, gboolean blocked)
+{
+ GstDecodeBin *dbin = dpad->dbin;
+
+ DECODE_BIN_DYN_LOCK (dbin);
+ gst_pad_set_blocked_async (GST_PAD (dpad), blocked,
+ (GstPadBlockCallback) source_pad_blocked_cb, NULL);
+ if (blocked) {
+ if (dbin->shutdown) {
+ /* deactivate to force flushing state to prevent NOT_LINKED errors */
+ gst_pad_set_active (GST_PAD (dpad), FALSE);
+ } else {
+ gst_object_ref (dpad);
+ dbin->blocked_pads = g_list_prepend (dbin->blocked_pads, dpad);
+ }
+ } else {
+ if (g_list_find (dbin->blocked_pads, dpad))
+ gst_object_unref (dpad);
+ dbin->blocked_pads = g_list_remove (dbin->blocked_pads, dpad);
+ }
+ DECODE_BIN_DYN_UNLOCK (dbin);
+}
+
+static void
+gst_decode_pad_add_drained_check (GstDecodePad * dpad)
+{
+ gst_pad_add_event_probe (GST_PAD (dpad),
+ G_CALLBACK (source_pad_event_probe), dpad);
+}
+
+static void
+gst_decode_pad_activate (GstDecodePad * dpad, GstDecodeGroup * group)
+{
+ g_return_if_fail (group != NULL);
+
+ dpad->group = group;
+ gst_pad_set_active (GST_PAD (dpad), TRUE);
+ gst_decode_pad_set_blocked (dpad, TRUE);
+ gst_decode_pad_add_drained_check (dpad);
+}
+
+static void
+gst_decode_pad_unblock (GstDecodePad * dpad)
+{
+ gst_decode_pad_set_blocked (dpad, FALSE);
+}
+
/*gst_decode_pad_new:
*
* Creates a new GstDecodePad for the given pad.
- * If block is TRUE, Sets the pad blocking asynchronously
*/
static GstDecodePad *
-gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad, gboolean block)
+gst_decode_pad_new (GstDecodeBin * dbin, GstPad * pad, GstDecodeGroup * group)
{
GstDecodePad *dpad;
- dpad = g_new0 (GstDecodePad, 1);
- dpad->pad = pad;
+ dpad =
+ g_object_new (GST_TYPE_DECODE_PAD, "direction", GST_PAD_DIRECTION (pad),
+ NULL);
+ gst_ghost_pad_construct (GST_GHOST_PAD (dpad));
+ gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), pad);
dpad->group = group;
- dpad->blocked = FALSE;
- dpad->drained = TRUE;
-
- if (block)
- gst_pad_set_blocked_async (pad, TRUE,
- (GstPadBlockCallback) source_pad_blocked_cb, dpad);
- gst_pad_add_event_probe (pad, G_CALLBACK (source_pad_event_probe), dpad);
+ dpad->dbin = dbin;
+
return dpad;
}
@@ -2255,73 +2598,28 @@
* Element add/remove
*****/
-/*
- * add_fakesink / remove_fakesink
- *
- * We use a sink so that the parent ::change_state returns GST_STATE_CHANGE_ASYNC
- * when that sink is present (since it's not connected to anything it will
- * always return GST_STATE_CHANGE_ASYNC).
- *
- * But this is an ugly way of achieving this goal.
- * Ideally, we shouldn't use a sink and just return GST_STATE_CHANGE_ASYNC in
- * our ::change_state if we have not exposed the active group.
- * We also need to override ::get_state to fake the asynchronous behaviour.
- * Once the active group is exposed, we would then post a
- * GST_MESSAGE_STATE_DIRTY and return GST_STATE_CHANGE_SUCCESS (which will call
- * ::get_state .
- */
-
-static gboolean
-add_fakesink (GstDecodeBin * decode_bin)
+static void
+do_async_start (GstDecodeBin * dbin)
{
- GST_DEBUG_OBJECT (decode_bin, "Adding the fakesink");
-
- if (decode_bin->fakesink)
- return TRUE;
-
- decode_bin->fakesink =
- gst_element_factory_make ("fakesink", "async-fakesink");
- if (!decode_bin->fakesink)
- goto no_fakesink;
-
- /* enable sync so that we force ASYNC preroll */
- g_object_set (G_OBJECT (decode_bin->fakesink), "sync", TRUE, NULL);
-
- /* hacky, remove sink flag, we don't want our decodebin to become a sink
- * just because we add a fakesink element to make us ASYNC */
- GST_OBJECT_FLAG_UNSET (decode_bin->fakesink, GST_ELEMENT_IS_SINK);
-
- if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->fakesink))
- goto could_not_add;
-
- return TRUE;
-
- /* ERRORS */
-no_fakesink:
- {
- g_warning ("can't find fakesink element, decodebin will not work");
- return FALSE;
- }
-could_not_add:
- {
- g_warning ("Could not add fakesink to decodebin, decodebin will not work");
- gst_object_unref (decode_bin->fakesink);
- decode_bin->fakesink = NULL;
- return FALSE;
- }
+ GstMessage *message;
+
+ dbin->async_pending = TRUE;
+
+ message = gst_message_new_async_start (GST_OBJECT_CAST (dbin), FALSE);
+ parent_class->handle_message (GST_BIN_CAST (dbin), message);
}
static void
-remove_fakesink (GstDecodeBin * decode_bin)
+do_async_done (GstDecodeBin * dbin)
{
- if (decode_bin->fakesink == NULL)
- return;
-
- GST_DEBUG_OBJECT (decode_bin, "Removing the fakesink");
-
- gst_element_set_state (decode_bin->fakesink, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (decode_bin), decode_bin->fakesink);
- decode_bin->fakesink = NULL;
+ GstMessage *message;
+
+ if (dbin->async_pending) {
+ message = gst_message_new_async_done (GST_OBJECT_CAST (dbin));
+ parent_class->handle_message (GST_BIN_CAST (dbin), message);
+
+ dbin->async_pending = FALSE;
+ }
}
/*****
@@ -2351,10 +2649,35 @@
return pad;
}
+/* call with dyn_lock held */
+static void
+unblock_pads (GstDecodeBin * dbin)
+{
+ GList *tmp, *next;
+
+ for (tmp = dbin->blocked_pads; tmp; tmp = next) {
+ GstDecodePad *dpad = (GstDecodePad *) tmp->data;
+
+ next = g_list_next (tmp);
+
+ GST_DEBUG_OBJECT (dpad, "unblocking");
+ gst_pad_set_blocked_async (GST_PAD (dpad), FALSE,
+ (GstPadBlockCallback) source_pad_blocked_cb, NULL);
+ /* make flushing, prevent NOT_LINKED */
+ GST_PAD_SET_FLUSHING (GST_PAD (dpad));
+ gst_object_unref (dpad);
+ GST_DEBUG_OBJECT (dpad, "unblocked");
+ }
+
+ /* clear, no more blocked pads */
+ g_list_free (dbin->blocked_pads);
+ dbin->blocked_pads = NULL;
+}
+
static GstStateChangeReturn
gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
{
- GstStateChangeReturn ret;
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstDecodeBin *dbin = GST_DECODE_BIN (element);
switch (transition) {
@@ -2362,19 +2685,47 @@
if (dbin->typefind == NULL)
goto missing_typefind;
break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:{
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ DECODE_BIN_DYN_LOCK (dbin);
+ GST_LOG_OBJECT (dbin, "clearing shutdown flag");
+ dbin->shutdown = FALSE;
+ DECODE_BIN_DYN_UNLOCK (dbin);
dbin->have_type = FALSE;
- if (!add_fakesink (dbin))
- goto missing_fakesink;
+ ret = GST_STATE_CHANGE_ASYNC;
+ do_async_start (dbin);
break;
- }
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ DECODE_BIN_DYN_LOCK (dbin);
+ GST_LOG_OBJECT (dbin, "setting shutdown flag");
+ dbin->shutdown = TRUE;
+ unblock_pads (dbin);
+ DECODE_BIN_DYN_UNLOCK (dbin);
default:
break;
}
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- /* FIXME : put some cleanup functions here.. if needed */
+ {
+ GstStateChangeReturn bret;
+
+ bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE))
+ goto activate_failed;
+ else if (G_UNLIKELY (bret == GST_STATE_CHANGE_NO_PREROLL)) {
+ do_async_done (dbin);
+ ret = bret;
+ }
+ }
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ do_async_done (dbin);
+ gst_decode_bin_remove_groups (dbin);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_decode_bin_remove_groups (dbin);
+ break;
+ default:
+ break;
+ }
return ret;
@@ -2386,16 +2737,19 @@
GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no typefind!"));
return GST_STATE_CHANGE_FAILURE;
}
-missing_fakesink:
+activate_failed:
{
- gst_element_post_message (element,
- gst_missing_element_message_new (element, "fakesink"));
- GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no fakesink!"));
+ GST_DEBUG_OBJECT (element,
+ "element failed to change states -- activation problem?");
return GST_STATE_CHANGE_FAILURE;
}
}
-
-static gboolean
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+
+gboolean
gst_decode_bin_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0,
@@ -2405,6 +2759,7 @@
GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
LOCALEDIR);
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif /* ENABLE_NLS */
return gst_element_register (plugin, "decodebin2", GST_RANK_NONE,