diff -r 567bb019e3e3 -r 7e817e7e631c gst_plugins_base/gst/playback/gstdecodebin2.c --- a/gst_plugins_base/gst/playback/gstdecodebin2.c Tue Aug 31 15:30:33 2010 +0300 +++ b/gst_plugins_base/gst/playback/gstdecodebin2.c Wed Sep 01 12:16:41 2010 +0100 @@ -19,16 +19,17 @@ /** * 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 #GstDecodeBin for its internal auto-plugging. + * decodebin2 instead of the older decodebin for its internal auto-plugging. */ #ifdef HAVE_CONFIG_H @@ -45,6 +46,9 @@ #include "gstplay-enum.h" #include "gstfactorylists.h" +#ifdef __SYMBIAN32__ +#include +#endif /* generic templates */ static GstStaticPadTemplate decoder_bin_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", @@ -63,7 +67,6 @@ typedef struct _GstDecodeGroup GstDecodeGroup; typedef struct _GstDecodePad GstDecodePad; -typedef GstGhostPadClass GstDecodePadClass; typedef struct _GstDecodeBin GstDecodeBin; typedef struct _GstDecodeBin GstDecodeBin2; typedef struct _GstDecodeBinClass GstDecodeBinClass; @@ -89,6 +92,7 @@ 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 */ @@ -99,16 +103,9 @@ 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 @@ -158,9 +155,7 @@ { PROP_0, PROP_CAPS, - PROP_SUBTITLE_ENCODING, - PROP_SINK_CAPS, - PROP_LAST + PROP_SUBTITLE_ENCODING }; static GstBinClass *parent_class; @@ -173,8 +168,8 @@ "Edward Hervey "); -static void do_async_start (GstDecodeBin * dbin); -static void do_async_done (GstDecodeBin * dbin); +static gboolean add_fakesink (GstDecodeBin * decode_bin); +static void remove_fakesink (GstDecodeBin * decode_bin); static void type_found (GstElement * typefind, guint probability, GstCaps * caps, GstDecodeBin * decode_bin); @@ -220,23 +215,6 @@ 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 @@ -247,16 +225,17 @@ GstDecodeBin *dbin; GMutex *lock; GstElement *multiqueue; - gboolean exposed; /* TRUE if this group is exposed */ - gboolean drained; /* TRUE if EOS went through all endpads */ + gboolean drained; /* TRUE if EOS went throug 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; /* the overrun signal for multiqueue */ + gulong overrunsig; + gulong underrunsig; 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. */ }; @@ -283,9 +262,9 @@ static GstPad *gst_decode_group_control_demuxer_pad (GstDecodeGroup * group, GstPad * pad); static gboolean gst_decode_group_control_source_pad (GstDecodeGroup * group, - GstDecodePad * pad); + GstPad * pad); static gboolean gst_decode_group_expose (GstDecodeGroup * group); -static gboolean gst_decode_group_check_if_blocked (GstDecodeGroup * group); +static void 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); @@ -294,26 +273,28 @@ * * GstPad private used for source pads of groups */ + struct _GstDecodePad { - GstGhostPad parent; + 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 +{ GstDecodeBin *dbin; GstDecodeGroup *group; - - 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); +} TempPadStruct; /******************************** * Standard GObject boilerplate * @@ -412,8 +393,7 @@ /** * GstDecodeBin2::new-decoded-pad: - * @bin: The decodebin - * @pad: The newly created pad + * @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 @@ -428,8 +408,7 @@ /** * GstDecodeBin2::removed-decoded-pad: - * @bin: The decodebin - * @pad: The pad that was removed + * @pad: the pad that was removed * * This signal is emitted when a 'final' caps pad has been removed. */ @@ -441,10 +420,8 @@ /** * GstDecodeBin2::unknown-type: - * @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. + * @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. @@ -452,12 +429,11 @@ 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_BOXED, G_TYPE_NONE, 2, + NULL, NULL, gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, GST_TYPE_PAD, GST_TYPE_CAPS); /** * GstDecodeBin2::autoplug-continue: - * @bin: The decodebin * @pad: The #GstPad. * @caps: The #GstCaps found. * @@ -472,12 +448,11 @@ 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_BOXED, + _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT_OBJECT, G_TYPE_BOOLEAN, 2, GST_TYPE_PAD, GST_TYPE_CAPS); /** * GstDecodeBin2::autoplug-factories: - * @bin: The decodebin * @pad: The #GstPad. * @caps: The #GstCaps found. * @@ -498,12 +473,11 @@ 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_BOXED, G_TYPE_VALUE_ARRAY, 2, + gst_play_marshal_BOXED__OBJECT_OBJECT, 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. @@ -520,47 +494,34 @@ 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_BOXED_BOXED, + NULL, NULL, gst_play_marshal_BOXED__OBJECT_OBJECT_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. - * @factory: A #GstElementFactory to use + * @factories: A #GValueArray of possible #GstElementFactory to use, sorted by + * rank (higher ranks come first). * * This signal is emitted once decodebin2 has found all the possible - * #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. + * #GstElementFactory that can be used to handle the given @caps. * - * 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. + * 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). */ 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_BOXED_OBJECT, + gst_play_marshal_ENUM__OBJECT_OBJECT_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. * @@ -573,20 +534,14 @@ 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 | G_PARAM_STATIC_STRINGS)); + GST_TYPE_CAPS, G_PARAM_READWRITE)); 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 | 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)); + "ISO-8859-15 will be assumed.", NULL, G_PARAM_READWRITE)); klass->autoplug_continue = GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_continue); @@ -629,7 +584,7 @@ } /* get the sinkpad */ - pad = gst_element_get_static_pad (decode_bin->typefind, "sink"); + pad = gst_element_get_pad (decode_bin->typefind, "sink"); /* ghost the sink pad to ourself */ gpad = gst_ghost_pad_new ("sink", pad); @@ -649,96 +604,20 @@ 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;" - "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); + "audio/x-raw-int;audio/x-raw-float;" "text/plain;text/x-pango-markup"); + + add_fakesink (decode_bin); + + /* FILLME */ } static void gst_decode_bin_dispose (GObject * object) { GstDecodeBin *decode_bin; + GList *tmp; decode_bin = GST_DECODE_BIN (object); @@ -746,7 +625,27 @@ g_value_array_free (decode_bin->factories); decode_bin->factories = NULL; - gst_decode_bin_remove_groups (decode_bin); + 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; if (decode_bin->caps) gst_caps_unref (decode_bin->caps); @@ -755,8 +654,7 @@ g_free (decode_bin->encoding); decode_bin->encoding = NULL; - g_list_free (decode_bin->subtitles); - decode_bin->subtitles = NULL; + remove_fakesink (decode_bin); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -773,11 +671,6 @@ 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); } @@ -792,22 +685,15 @@ static void gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps) { - GstCaps *old; - GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps); - 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); + 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); } /* _get_caps @@ -816,6 +702,7 @@ * * MT-safe */ + static GstCaps * gst_decode_bin_get_caps (GstDecodeBin * dbin) { @@ -823,31 +710,11 @@ GST_DEBUG_OBJECT (dbin, "Getting currently set caps"); - GST_OBJECT_LOCK (dbin); + DECODE_BIN_LOCK (dbin); caps = dbin->caps; if (caps) gst_caps_ref (caps); - 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); + DECODE_BIN_UNLOCK (dbin); return caps; } @@ -855,21 +722,11 @@ 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); } @@ -880,9 +737,9 @@ GST_DEBUG_OBJECT (dbin, "Getting currently set encoding"); - GST_OBJECT_LOCK (dbin); + DECODE_BIN_LOCK (dbin); encoding = g_strdup (dbin->encoding); - GST_OBJECT_UNLOCK (dbin); + DECODE_BIN_UNLOCK (dbin); return encoding; } @@ -902,9 +759,6 @@ 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; @@ -925,9 +779,6 @@ 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; @@ -935,6 +786,9 @@ } +static GValueArray *find_compatibles (GstDecodeBin * decode_bin, + GstPad * pad, const GstCaps * caps); + /***** * Default autoplug signal handlers *****/ @@ -954,11 +808,8 @@ { GValueArray *result; - GST_DEBUG_OBJECT (element, "finding factories"); - /* return all compatible factories for caps */ - result = - gst_factory_list_filter (GST_DECODE_BIN_CAST (element)->factories, caps); + result = find_compatibles (GST_DECODE_BIN (element), pad, caps); GST_DEBUG_OBJECT (element, "autoplug-factories returns %p", result); @@ -997,12 +848,12 @@ static gboolean is_demuxer_element (GstElement * srcelement); static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src, - GstDecodePad * dpad, GstPad * pad, GstCaps * caps, GValueArray * factories, + 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, - GstDecodePad * dpad, GstPad * pad, GstDecodeGroup * group); +static void expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, + GstDecodeGroup * group); static void pad_added_group_cb (GstElement * element, GstPad * pad, GstDecodeGroup * group); @@ -1016,8 +867,7 @@ GstDecodeBin * dbin); static void no_more_pads_cb (GstElement * element, GstDecodeBin * dbin); -static GstDecodeGroup *get_current_group (GstDecodeBin * dbin, - gboolean create, gboolean demux, gboolean * created); +static GstDecodeGroup *get_current_group (GstDecodeBin * dbin); /* called when a new pad is discovered. It will perform some basic actions * before trying to link something to it. @@ -1037,7 +887,6 @@ { 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); @@ -1048,12 +897,10 @@ 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, dpad, caps, + gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, pad, caps, &apcontinue); /* 1.a if autoplug-continue is FALSE or caps is a raw format, goto pad_is_final */ @@ -1068,7 +915,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, dpad, caps, + gst_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES], 0, pad, caps, &factories); /* NULL means that we can expose the pad */ @@ -1079,22 +926,20 @@ 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, dpad, caps, factories, + gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT], 0, pad, 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, dpad, pad, caps, factories, group); - - gst_object_unref (dpad); + connect_pad (dbin, src, pad, caps, factories, group); + g_value_array_free (factories); return; @@ -1102,8 +947,7 @@ expose_pad: { GST_LOG_OBJECT (dbin, "Pad is final. autoplug-continue:%d", apcontinue); - expose_pad (dbin, src, dpad, pad, group); - gst_object_unref (dpad); + expose_pad (dbin, src, pad, group); return; } unknown_type: @@ -1112,10 +956,9 @@ 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, commit our state */ - if (dbin->groups == NULL) { - do_async_done (dbin); - } + /* Check if there are no pending groups, if so, remove fakesink */ + if (dbin->groups == NULL) + remove_fakesink (dbin); if (src == dbin->typefind) { gchar *desc; @@ -1136,7 +979,6 @@ non_fixed: { GST_DEBUG_OBJECT (pad, "pad has non-fixed caps delay autoplugging"); - gst_object_unref (dpad); goto setup_caps_delay; } any_caps: @@ -1151,8 +993,7 @@ if (group) { GROUP_MUTEX_LOCK (group); group->nbdynamic++; - GST_LOG_OBJECT (dbin, "Group %p has now %d dynamic elements", group, - group->nbdynamic); + GST_LOG ("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); @@ -1169,15 +1010,11 @@ * 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, GstDecodePad * dpad, - GstPad * pad, GstCaps * caps, GValueArray * factories, - GstDecodeGroup * group) +connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, + GstCaps * caps, GValueArray * factories, GstDecodeGroup * group) { gboolean res = FALSE; GstPad *mqpad = NULL; @@ -1193,14 +1030,17 @@ GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue"); if (!group) - group = get_current_group (dbin, TRUE, TRUE, NULL); - - gst_ghost_pad_set_target (GST_GHOST_PAD (dpad), NULL); + 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); + } + 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 */ @@ -1209,7 +1049,6 @@ GstElementFactory *factory; GstElement *element; GstPad *sinkpad; - gboolean subtitle; /* take first factory */ factory = g_value_get_object (g_value_array_get_nth (factories, 0)); @@ -1219,7 +1058,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, dpad, caps, factory, &ret); + 0, pad, caps, factory, &ret); switch (ret) { case GST_AUTOPLUG_SELECT_TRY: @@ -1228,7 +1067,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, dpad, pad, group); + expose_pad (dbin, src, pad, group); res = TRUE; goto beach; case GST_AUTOPLUG_SELECT_SKIP: @@ -1239,9 +1078,6 @@ 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", @@ -1264,7 +1100,6 @@ 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; } @@ -1274,7 +1109,6 @@ 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; } @@ -1294,17 +1128,6 @@ /* 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) { @@ -1314,13 +1137,6 @@ 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; @@ -1363,7 +1179,7 @@ case GST_PAD_ALWAYS: { /* get the pad that we need to autoplug */ - GstPad *pad = gst_element_get_static_pad (element, templ_name); + GstPad *pad = gst_element_get_pad (element, templ_name); if (pad) { GST_DEBUG_OBJECT (dbin, "got the pad for always template %s", @@ -1382,7 +1198,7 @@ { /* try to get the pad to see if it is already created or * not */ - GstPad *pad = gst_element_get_static_pad (element, templ_name); + GstPad *pad = gst_element_get_pad (element, templ_name); if (pad) { GST_DEBUG_OBJECT (dbin, "got the pad for sometimes template %s", @@ -1407,12 +1223,11 @@ /* 2. if there are more potential pads, connect to relevent signals */ if (dynamic) { if (group) { - GST_LOG_OBJECT (dbin, "Adding signals to element %s in group %p", + GST_LOG ("Adding signals to element %s in group %p", GST_ELEMENT_NAME (element), group); GROUP_MUTEX_LOCK (group); group->nbdynamic++; - GST_LOG_OBJECT (dbin, "Group %p has now %d dynamic elements", group, - group->nbdynamic); + GST_LOG ("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); @@ -1454,8 +1269,8 @@ * If group is NULL, a GstDecodeGroup will be created and setup properly. */ static void -expose_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad, - GstPad * pad, GstDecodeGroup * group) +expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, + GstDecodeGroup * group) { gboolean newgroup = FALSE; gboolean isdemux; @@ -1467,19 +1282,23 @@ isdemux = is_demuxer_element (src); if (!group) - group = get_current_group (dbin, TRUE, isdemux, &newgroup); + 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; + } 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, dpad); + gst_decode_group_control_source_pad (group, pad); if (newgroup && !isdemux) { /* If we have discovered a raw pad and it doesn't belong to any group, @@ -1502,16 +1321,6 @@ 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) @@ -1534,33 +1343,27 @@ { 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 (dbin, element, pad, caps, group); + analyze_new_pad (group->dbin, element, pad, caps, group); if (caps) gst_caps_unref (caps); GROUP_MUTEX_LOCK (group); - if (group->nbdynamic > 0) - group->nbdynamic--; - GST_LOG_OBJECT (dbin, "Group %p has now %d dynamic objects", group, - group->nbdynamic); + group->nbdynamic--; + GST_LOG ("Group %p has now %d dynamic objects", group, group->nbdynamic); if (group->nbdynamic == 0) expose = TRUE; GROUP_MUTEX_UNLOCK (group); if (expose) { - 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); + 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); } } @@ -1579,7 +1382,7 @@ { GST_LOG_OBJECT (element, "no more pads, setting group %p to complete", group); - /* when we received no_more_pads, we can complete the pads of the group */ + /* FIXME : FILLME */ gst_decode_group_set_complete (group); } @@ -1610,16 +1413,15 @@ 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, FALSE, FALSE, NULL))) + if (!(group = get_current_group (dbin))) goto no_group; gst_decode_group_set_complete (group); - return; no_group: { - GST_DEBUG_OBJECT (dbin, "We couldn't find a non-completed group"); + GST_WARNING_OBJECT (dbin, "We couldn't find a non-completed group !!"); return; } } @@ -1632,10 +1434,6 @@ 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); @@ -1650,10 +1448,6 @@ 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); @@ -1661,6 +1455,21 @@ 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 @@ -1724,10 +1533,7 @@ 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))); @@ -1743,45 +1549,38 @@ * 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) { - 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; + 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); +} + +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); } - 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); - } + 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. @@ -1796,7 +1595,7 @@ if (use_queue) { if (!(mq = gst_element_factory_make ("multiqueue", NULL))) { - GST_ERROR_OBJECT (dbin, "Couldn't create multiqueue element"); + GST_WARNING ("Couldn't create multiqueue element"); return NULL; } } else { @@ -1820,11 +1619,15 @@ * memory. When this queue overruns, we assume the group is complete and can * be exposed. */ g_object_set (G_OBJECT (mq), - "max-size-bytes", (guint) 2 * 1024 * 1024, - "max-size-time", (guint64) 0, "max-size-buffers", (guint) 0, NULL); + "max-size-bytes", 2 * 1024 * 1024, + "max-size-time", 5 * GST_SECOND, "max-size-buffers", 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); @@ -1835,20 +1638,14 @@ return 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 +/** get_current_group: * - * Returns the current non-completed group. The dynamic refcount of the group is - * increased when dealing with a demuxer. + * Returns the current non-completed group. * - * 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, gboolean create, gboolean as_demux, - gboolean * created) +get_current_group (GstDecodeBin * dbin) { GList *tmp; GstDecodeGroup *group = NULL; @@ -1857,27 +1654,13 @@ 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); @@ -1885,6 +1668,20 @@ 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. @@ -1895,27 +1692,24 @@ static GstPad * gst_decode_group_control_demuxer_pad (GstDecodeGroup * group, GstPad * pad) { - GstDecodeBin *dbin; GstPad *srcpad, *sinkpad; gchar *nb, *sinkname, *srcname; - dbin = group->dbin; - - GST_LOG_OBJECT (dbin, "group:%p pad %s:%s", group, GST_DEBUG_PAD_NAME (pad)); + GST_LOG ("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_OBJECT (dbin, "Couldn't get sinkpad from multiqueue"); + GST_ERROR ("Couldn't get sinkpad from multiqueue"); return NULL; } if ((gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) { - GST_ERROR_OBJECT (dbin, "Couldn't link demuxer and multiqueue"); + GST_ERROR ("Couldn't link demuxer and multiqueue"); goto beach; } - group->reqpads = g_list_prepend (group->reqpads, sinkpad); + group->reqpads = g_list_append (group->reqpads, sinkpad); sinkname = gst_pad_get_name (sinkpad); nb = sinkname + 4; @@ -1924,11 +1718,14 @@ GROUP_MUTEX_LOCK (group); - if (!(srcpad = gst_element_get_static_pad (group->multiqueue, srcname))) { - GST_ERROR_OBJECT (dbin, "Couldn't get srcpad %s from multiqueue", srcname); + if (!(srcpad = gst_element_get_pad (group->multiqueue, srcname))) { + GST_ERROR ("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); @@ -1939,18 +1736,23 @@ } static gboolean -gst_decode_group_control_source_pad (GstDecodeGroup * group, - GstDecodePad * dpad) +gst_decode_group_control_source_pad (GstDecodeGroup * group, GstPad * pad) { + GstDecodePad *dpad; + g_return_val_if_fail (group != NULL, FALSE); - GST_DEBUG_OBJECT (dpad, "adding decode pad to group %p", group); + GST_LOG ("group:%p , pad %s:%s", group, GST_DEBUG_PAD_NAME (pad)); /* FIXME : check if pad is already controlled */ - gst_decode_pad_activate (dpad, group); GROUP_MUTEX_LOCK (group); - group->endpads = g_list_prepend (group->endpads, gst_object_ref (dpad)); + + /* Create GstDecodePad for the pad */ + dpad = gst_decode_pad_new (group, pad, TRUE); + + group->endpads = g_list_append (group->endpads, dpad); + GROUP_MUTEX_UNLOCK (group); return TRUE; @@ -1963,25 +1765,20 @@ * 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 gboolean +static void gst_decode_group_check_if_blocked (GstDecodeGroup * group) { - GstDecodeBin *dbin; GList *tmp; gboolean blocked = TRUE; - dbin = group->dbin; - - GST_LOG_OBJECT (dbin, "group : %p , ->complete:%d , ->nbdynamic:%d", + GST_LOG ("group : %p , ->complete:%d , ->nbdynamic:%d", group, group->complete, group->nbdynamic); - /* don't do anything if group is not complete */ + /* 1. 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 FALSE; + return; } for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) { @@ -1993,100 +1790,64 @@ } } - /* Update status of group */ + /* 2. Update status of group */ group->blocked = blocked; - GST_LOG_OBJECT (dbin, "group is blocked:%d", blocked); - - return 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); } -/* 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_pad_handle_eos (GstDecodePad * pad) +gst_decode_group_check_if_drained (GstDecodeGroup * group) { GList *tmp; - GstDecodeBin *dbin; - GstDecodeGroup *group; + GstDecodeBin *dbin = group->dbin; gboolean drained = TRUE; - 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; + GST_LOG ("group : %p", group); for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) { GstDecodePad *dpad = (GstDecodePad *) tmp->data; - GST_LOG_OBJECT (dbin, "testing dpad %p %d", dpad, dpad->drained); + GST_LOG ("testing dpad %p", dpad); if (!dpad->drained) { drained = FALSE; break; } } + group->drained = drained; - GROUP_MUTEX_UNLOCK (group); + 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); if (drained) { - /* 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; + /* 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); } } @@ -2102,13 +1863,17 @@ 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; - capsa = gst_pad_get_caps (GST_PAD (da)); - capsb = gst_pad_get_caps (GST_PAD (db)); + a = da->pad; + b = db->pad; + + capsa = gst_pad_get_caps (a); + capsb = gst_pad_get_caps (b); sa = gst_caps_get_structure ((const GstCaps *) capsa, 0); sb = gst_caps_get_structure ((const GstCaps *) capsb, 0); @@ -2148,159 +1913,146 @@ * * Expose this group's pads. * - * Not MT safe, please take the decodebin lock + * Not MT safe, please take the group lock */ static gboolean gst_decode_group_expose (GstDecodeGroup * group) { GList *tmp; GList *next = NULL; - GstDecodeBin *dbin; - - dbin = group->dbin; - - GST_DEBUG_OBJECT (dbin, "going to expose group %p", group); + + if (group->dbin->activegroup) { + GST_DEBUG_OBJECT (group->dbin, "A group is already active and exposed"); + return TRUE; + } + + if (group->dbin->activegroup == group) { + GST_WARNING ("Group %p is already exposed", 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_DEBUG_OBJECT (dbin, - "Group %p still has %d dynamic objects, not exposing yet", group, - group->nbdynamic); + GST_WARNING ("Group %p still has %d dynamic objects, not exposing yet", + group, group->nbdynamic); return FALSE; } - if (dbin->activegroup == group) { - GST_DEBUG_OBJECT (dbin, "Group %p is already exposed, all is fine", group); - return TRUE; - } + 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-buffers", 5, NULL); + "max-size-bytes", 2 * 1024 * 1024, + "max-size-time", 2 * GST_SECOND, "max-size-buffers", 5, NULL); /* we can now disconnect any overrun signal, which is used to expose the * group. */ if (group->overrunsig) { - GST_LOG_OBJECT (dbin, "Disconnecting overrun"); + GST_LOG ("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. 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); + /* 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); + g_free (padname); - /* 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, + /* 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, (next == NULL)); - GST_DEBUG_OBJECT (dbin, "emitted new-decoded-pad"); + GST_DEBUG_OBJECT (group->dbin, "emitted new-decoded-pad"); } /* signal no-more-pads. This allows the application to hook stuff to the * exposed pads */ - 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 + 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 * 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, "unblocking"); - gst_decode_pad_unblock (dpad); - GST_DEBUG_OBJECT (dpad, "unblocked"); + 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"); } - dbin->activegroup = group; + group->dbin->activegroup = group; /* pop off the first group */ - 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->dbin->groups = + g_list_delete_link (group->dbin->groups, group->dbin->groups); + + remove_fakesink (group->dbin); group->exposed = TRUE; - GST_LOG_OBJECT (dbin, "Group %p exposed", group); + GST_LOG_OBJECT (group->dbin, "Group %p exposed", group); return TRUE; } -/* must be called with the decodebin lock */ static void gst_decode_group_hide (GstDecodeGroup * group) { GList *tmp; - 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"); + + GST_LOG ("Hiding group %p", group); + + if (group != group->dbin->activegroup) { + GST_WARNING ("This group is not the active one, aborting"); return; } GROUP_MUTEX_LOCK (group); + /* Remove ghost pads */ - 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; - } + 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; + group->exposed = FALSE; + GROUP_MUTEX_UNLOCK (group); group->dbin->activegroup = NULL; - group->dbin->oldgroups = g_list_prepend (group->dbin->oldgroups, group); + group->dbin->oldgroups = g_list_append (group->dbin->oldgroups, group); } static void @@ -2309,11 +2061,8 @@ GstIterator *it; GstIteratorResult res; gpointer point; - GstDecodeBin *dbin; - - dbin = group->dbin; - - GST_LOG_OBJECT (dbin, "element:%s", GST_ELEMENT_NAME (element)); + + GST_LOG ("element:%s", GST_ELEMENT_NAME (element)); /* call on downstream elements */ it = gst_element_iterate_src_pads (element); @@ -2330,8 +2079,7 @@ goto restart; case GST_ITERATOR_ERROR: { - GST_WARNING_OBJECT (dbin, - "Had an error while iterating source pads of element: %s", + GST_WARNING ("Had an error while iterating source pads of element: %s", GST_ELEMENT_NAME (element)); goto beach; } @@ -2360,11 +2108,7 @@ done: gst_element_set_state (element, GST_STATE_NULL); - 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); + gst_bin_remove (GST_BIN (group->dbin), element); beach: gst_iterator_free (it); @@ -2375,29 +2119,27 @@ static void gst_decode_group_free (GstDecodeGroup * group) { - GstDecodeBin *dbin; GList *tmp; - dbin = group->dbin; - - GST_LOG_OBJECT (dbin, "group %p", group); + GST_LOG ("group %p", group); GROUP_MUTEX_LOCK (group); - /* 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; - } + /* 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; } /* Clear all GstDecodePad */ - for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) - gst_object_unref (tmp->data); + for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) { + GstDecodePad *dpad = (GstDecodePad *) tmp->data; + + g_free (dpad); + } g_list_free (group->endpads); group->endpads = NULL; @@ -2410,6 +2152,8 @@ /* 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); @@ -2426,85 +2170,40 @@ /* gst_decode_group_set_complete: * * Mark the group as complete. This means no more streams will be controlled - * 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. + * through this group. * * MT safe */ static void gst_decode_group_set_complete (GstDecodeGroup * group) { - gboolean expose = FALSE; - GstDecodeBin *dbin; - - dbin = group->dbin; - - GST_LOG_OBJECT (dbin, "Setting group %p to COMPLETE", group); + GST_LOG_OBJECT (group->dbin, "Setting group %p to COMPLETE", group); GROUP_MUTEX_LOCK (group); group->complete = TRUE; - if (group->nbdynamic > 0) - group->nbdynamic--; - expose = gst_decode_group_check_if_blocked (group); + 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 -gst_decode_pad_class_init (GstDecodePadClass * klass) -{ -} - -static void -gst_decode_pad_init (GstDecodePad * pad) +source_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodePad * dpad) { - 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); + GST_LOG_OBJECT (pad, "blocked:%d , dpad:%p, dpad->group:%p", + blocked, dpad, dpad->group); + /* Update this GstDecodePad status */ dpad->blocked = blocked; - 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); + + if (blocked) { + GROUP_MUTEX_LOCK (dpad->group); + gst_decode_group_check_if_blocked (dpad->group); + GROUP_MUTEX_UNLOCK (dpad->group); } } @@ -2514,82 +2213,40 @@ 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_pad_handle_eos (dpad); + gst_decode_group_check_if_drained (dpad->group); } /* 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 (GstDecodeBin * dbin, GstPad * pad, GstDecodeGroup * group) +gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad, gboolean block) { GstDecodePad *dpad; - 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 = g_new0 (GstDecodePad, 1); + dpad->pad = pad; dpad->group = group; - dpad->dbin = dbin; - + 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); return dpad; } @@ -2598,28 +2255,73 @@ * Element add/remove *****/ -static void -do_async_start (GstDecodeBin * dbin) +/* + * 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) { - 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); + 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; + } } static void -do_async_done (GstDecodeBin * dbin) +remove_fakesink (GstDecodeBin * decode_bin) { - 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; - } + 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; } /***** @@ -2649,35 +2351,10 @@ 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 = GST_STATE_CHANGE_SUCCESS; + GstStateChangeReturn ret; GstDecodeBin *dbin = GST_DECODE_BIN (element); switch (transition) { @@ -2685,47 +2362,19 @@ if (dbin->typefind == NULL) goto missing_typefind; break; - 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); + case GST_STATE_CHANGE_READY_TO_PAUSED:{ dbin->have_type = FALSE; - ret = GST_STATE_CHANGE_ASYNC; - do_async_start (dbin); + if (!add_fakesink (dbin)) + goto missing_fakesink; 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; } - { - 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; - } + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + /* FIXME : put some cleanup functions here.. if needed */ return ret; @@ -2737,19 +2386,16 @@ GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no typefind!")); return GST_STATE_CHANGE_FAILURE; } -activate_failed: +missing_fakesink: { - GST_DEBUG_OBJECT (element, - "element failed to change states -- activation problem?"); + gst_element_post_message (element, + gst_missing_element_message_new (element, "fakesink")); + GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no fakesink!")); return GST_STATE_CHANGE_FAILURE; } } -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - - -gboolean + +static gboolean gst_decode_bin_plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0, @@ -2759,7 +2405,6 @@ 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,