+2007-12-05 Wim Taymans <wim.taymans@gmail.com>
+
+ * gst/playback/Makefile.am:
+ Group decodebin2 and uridecodebin into the same plugin so that they
+ can share the GEnumType.
+
+ * gst/playback/gstdecodebin2.c: (_gst_array_accumulator),
+ (_gst_select_accumulator), (gst_decode_bin_class_init),
+ (gst_decode_bin_init), (gst_decode_bin_autoplug_sort),
+ (gst_decode_bin_autoplug_select), (gst_decode_bin_autoplug_add),
+ (analyze_new_pad), (connect_pad), (gst_decode_bin_plugin_init):
+ Add signal to sort factories instead of the more awkward autoplug-select
+ signal.
+ Modify autoplug_select so that we can try, skip or expose the
+ autopluggin of an element on a pad.
+
+ * gst/playback/gstfactorylists.c: (compare_ranks),
+ (decoders_filter), (sinks_filter), (gst_factory_list_is_type),
+ (element_filter), (gst_factory_list_get_elements),
+ (gst_factory_list_debug), (gst_factory_list_filter):
+ * gst/playback/gstfactorylists.h:
+ Simplify the API, allow getting elements based on mask.
+
+ * gst/playback/gstplay-marshal.list:
+ Add some more marshallers.
+
+ * gst/playback/gstplaybin2.c: (init_group), (gst_play_bin_init),
+ (gst_play_bin_finalize), (pad_removed_cb), (autoplug_factories_cb),
+ (autoplug_select_cb), (activate_group):
+ Add support for managing non-raw sinks by providing a custom element and
+ sink list to decodebin2.
+ Try to plug non-raw sinks when decodebin2 using autoplug-select of
+ decodebin2.
+
+ * gst/playback/gstplaysink.c: (gen_video_chain), (gen_audio_chain),
+ (gst_play_sink_set_mode), (gst_play_sink_request_pad):
+ * gst/playback/gstplaysink.h:
+ Add support for raw and non-raw sinks.
+ Add support to force sinks selected by playbin2.
+ Don't plug raw converters for non-raw sinks.
+
+ * gst/playback/gsturidecodebin.c: (_gst_array_accumulator),
+ (_gst_select_accumulator), (gst_uri_decode_bin_class_init),
+ (proxy_autoplug_select_signal), (gst_uri_decode_bin_plugin_init),
+ (plugin_init):
+ Use right accumulators.
+ Proxy new signal.
+
2007-12-03 Wim Taymans <wim.taymans@gmail.com>
* gst-libs/gst/rtp/gstbasertppayload.c: (gst_basertppayload_push):
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
-plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la libgstdecodebin2.la libgstqueue2.la \
- libgsturidecodebin.la
+plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la libgstdecodebin2.la libgstqueue2.la
libgstplaybin_la_SOURCES = \
gstplayback.c \
gstplaybin2.c \
gstplaysink.c \
gstplaybasebin.c \
+ gstplay-enum.c \
gstfactorylists.c \
gststreaminfo.c \
gststreamselector.c
$(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
$(GST_LIBS)
-libgstdecodebin2_la_SOURCES = gstdecodebin2.c gstfactorylists.c
+libgstdecodebin2_la_SOURCES = gstdecodebin2.c gsturidecodebin.c gstfactorylists.c gstplay-enum.c
nodist_libgstdecodebin2_la_SOURCES = $(built_sources)
libgstdecodebin2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstdecodebin2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstqueue2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstqueue2_la_LIBADD = $(GST_LIBS)
-libgsturidecodebin_la_SOURCES = gsturidecodebin.c
-nodist_libgsturidecodebin_la_SOURCES = $(built_sources)
-libgsturidecodebin_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
-libgsturidecodebin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgsturidecodebin_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
- $(GST_LIBS)
-
noinst_HEADERS = \
gstplaybasebin.h \
gstplaysink.h \
gststreaminfo.h \
gstfactorylists.h \
+ gstplay-enum.h \
gststreamselector.h
noinst_PROGRAMS = test decodetest test2 test3 test4 test5 test6 test7
#include <gst/pbutils/pbutils.h>
#include "gstplay-marshal.h"
+#include "gstplay-enum.h"
#include "gstfactorylists.h"
/* generic templates */
/* signal fired to get a list of factories to try to autoplug */
GValueArray *(*autoplug_factories) (GstElement * element, GstPad * pad,
GstCaps * caps);
+ /* signal fired to sort the factories */
+ GValueArray *(*autoplug_sort) (GstElement * element, GstPad * pad,
+ GstCaps * caps, GValueArray * factories);
/* signal fired to select from the proposed list of factories */
- gint (*autoplug_select) (GstElement * element, GstPad * pad, GstCaps * caps,
- GValueArray * factories);
+ GstAutoplugSelectResult (*autoplug_select) (GstElement * element,
+ GstPad * pad, GstCaps * caps, GstElementFactory * factory);
/* fired when the last group is drained */
void (*drained) (GstElement * element);
SIGNAL_AUTOPLUG_CONTINUE,
SIGNAL_AUTOPLUG_FACTORIES,
SIGNAL_AUTOPLUG_SELECT,
+ SIGNAL_AUTOPLUG_SORT,
SIGNAL_DRAINED,
LAST_SIGNAL
};
GstPad * pad, GstCaps * caps);
static GValueArray *gst_decode_bin_autoplug_factories (GstElement *
element, GstPad * pad, GstCaps * caps);
-static gint gst_decode_bin_autoplug_select (GstElement * element,
- GstPad * pad, GstCaps * caps, GValueArray * list);
+static GValueArray *gst_decode_bin_autoplug_sort (GstElement * element,
+ GstPad * pad, GstCaps * caps, GValueArray * factories);
+static GstAutoplugSelectResult gst_decode_bin_autoplug_select (GstElement *
+ element, GstPad * pad, GstCaps * caps, GstElementFactory * factory);
static void gst_decode_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
return myboolean;
}
+/* we collect the first result */
+static gboolean
+_gst_array_accumulator (GSignalInvocationHint * ihint,
+ GValue * return_accu, const GValue * handler_return, gpointer dummy)
+{
+ gpointer array;
+
+ array = g_value_get_boxed (handler_return);
+ if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
+ g_value_set_boxed (return_accu, array);
+
+ return FALSE;
+}
+
+static gboolean
+_gst_select_accumulator (GSignalInvocationHint * ihint,
+ GValue * return_accu, const GValue * handler_return, gpointer dummy)
+{
+ GstAutoplugSelectResult res;
+
+ res = g_value_get_enum (handler_return);
+ if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
+ g_value_set_enum (return_accu, res);
+
+ return FALSE;
+}
+
static void
gst_decode_bin_class_init (GstDecodeBinClass * klass)
{
gst_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES] =
g_signal_new ("autoplug-factories", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass,
- autoplug_factories), NULL, NULL,
+ autoplug_factories), _gst_array_accumulator, NULL,
gst_play_marshal_BOXED__OBJECT_OBJECT, G_TYPE_VALUE_ARRAY, 2,
GST_TYPE_PAD, GST_TYPE_CAPS);
+ /**
+ * GstDecodeBin2::autoplug-sort:
+ * @pad: The #GstPad.
+ * @caps: The #GstCaps.
+ * @factories: A #GValueArray of possible #GstElementFactory to use.
+ *
+ * Once decodebin2 has found the possible #GstElementFactory objects to try
+ * for @caps on @pad, this signal is emited. The purpose of the signal is for
+ * the application to perform additional sorting or filtering on the element
+ * factory array.
+ *
+ * The callee should copy and modify @factories.
+ *
+ * Returns: A new sorted array of #GstElementFactory objects.
+ */
+ 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,
+ G_TYPE_VALUE_ARRAY, 3, GST_TYPE_PAD, GST_TYPE_CAPS, G_TYPE_VALUE_ARRAY);
+
/**
* GstDecodeBin2::autoplug-select:
* @pad: The #GstPad.
*
* Returns: A #gint indicating what factory index from the @factories array
* that you wish decodebin2 to use for trying to decode the given @caps.
- * -1 to stop selection of a factory. The default handler always
- * returns the first possible factory.
+ * 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),
- NULL, NULL, gst_play_marshal_INT__OBJECT_OBJECT_BOXED,
- G_TYPE_INT, 3, GST_TYPE_PAD, GST_TYPE_CAPS, G_TYPE_VALUE_ARRAY);
+ _gst_select_accumulator, NULL,
+ 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
GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_continue);
klass->autoplug_factories =
GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_factories);
+ klass->autoplug_sort = GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_sort);
klass->autoplug_select = GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_select);
gst_element_class_add_pad_template (gstelement_klass,
gst_decode_bin_init (GstDecodeBin * decode_bin)
{
/* first filter out the interesting element factories */
- decode_bin->factories = gst_factory_list_get_decoders ();
+ decode_bin->factories =
+ gst_factory_list_get_elements (GST_FACTORY_LIST_DECODER);
/* we create the typefind element only once */
decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
return result;
}
-static gint
-gst_decode_bin_autoplug_select (GstElement * element, GstPad * pad,
+static GValueArray *
+gst_decode_bin_autoplug_sort (GstElement * element, GstPad * pad,
GstCaps * caps, GValueArray * factories)
{
- g_return_val_if_fail (factories != NULL, -1);
- g_return_val_if_fail (factories->n_values > 0, -1);
+ GValueArray *result;
+
+ result = g_value_array_copy (factories);
- GST_DEBUG_OBJECT (element, "default autoplug-select returns 0");
+ GST_DEBUG_OBJECT (element, "autoplug-sort returns %p", result);
- /* Return first factory. */
- return 0;
+ /* return input */
+ return result;
+}
+
+static GstAutoplugSelectResult
+gst_decode_bin_autoplug_select (GstElement * element, GstPad * pad,
+ GstCaps * caps, GstElementFactory * factory)
+{
+ GST_DEBUG_OBJECT (element, "default autoplug-select returns TRY");
+
+ /* Try factory. */
+ return GST_AUTOPLUG_SELECT_TRY;
}
/********
static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src,
GstPad * pad, GstCaps * caps, GValueArray * factories,
- GstDecodeGroup * group);
+ GstDecodeGroup * group, gboolean * expose);
static gboolean connect_element (GstDecodeBin * dbin, GstElement * element,
GstDecodeGroup * group);
static void expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
GstCaps * caps, GstDecodeGroup * group)
{
gboolean apcontinue = TRUE;
- GValueArray *factories = NULL;
+ GValueArray *factories = NULL, *result = NULL;
+ gboolean expose;
GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (pad), caps);
goto unknown_type;
}
- /* 1.d else continue autoplugging something from the list. */
+ /* 1.d sort some more. */
+ g_signal_emit (G_OBJECT (dbin),
+ 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, pad, caps, factories, group);
+ connect_pad (dbin, src, pad, caps, factories, group, &expose);
g_value_array_free (factories);
+ if (expose)
+ goto expose_pad;
+
return;
expose_pad:
*/
static gboolean
connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
- GstCaps * caps, GValueArray * factories, GstDecodeGroup * group)
+ GstCaps * caps, GValueArray * factories, GstDecodeGroup * group,
+ gboolean * expose)
{
gboolean res = FALSE;
GstPad *mqpad = NULL;
g_return_val_if_fail (factories != NULL, FALSE);
g_return_val_if_fail (factories->n_values > 0, FALSE);
+ *expose = FALSE;
+
GST_DEBUG_OBJECT (dbin, "pad %s:%s , group:%p",
GST_DEBUG_PAD_NAME (pad), group);
/* 2. Try to create an element and link to it */
while (factories->n_values > 0) {
- gint factidx;
+ GstAutoplugSelectResult ret;
GstElementFactory *factory;
GstElement *element;
GstPad *sinkpad;
- /* emit autoplug-select */
+ /* take first factory */
+ factory = g_value_get_object (g_value_array_get_nth (factories, 0));
+ /* Remove selected factory from the list. */
+ g_value_array_remove (factories, 0);
+
+ /* 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, factories, &factidx);
+ 0, pad, caps, factory, &ret);
- /* when the function returns -1, we leave the loop and stop */
- if (factidx == -1) {
- GST_DEBUG_OBJECT (dbin, "autoplug select returned -1");
- break;
+ switch (ret) {
+ case GST_AUTOPLUG_SELECT_TRY:
+ GST_DEBUG_OBJECT (dbin, "autoplug select requested try");
+ break;
+ case GST_AUTOPLUG_SELECT_EXPOSE:
+ GST_DEBUG_OBJECT (dbin, "autoplug select requested expose");
+ *expose = TRUE;
+ goto beach;
+ case GST_AUTOPLUG_SELECT_SKIP:
+ GST_DEBUG_OBJECT (dbin, "autoplug select requested skip");
+ continue;
+ default:
+ GST_WARNING_OBJECT (dbin, "autoplug select returned unhandled %d", ret);
+ break;
}
- GST_DEBUG_OBJECT (dbin, "autoplug select returned %d", factidx);
-
- factory = g_value_get_object (g_value_array_get_nth (factories, factidx));
-
- /* factory is != NULL now since the default handler selects the first
- * factory if all connected user handlers returned NULL. */
-
- /* Remove selected factory from the list. */
- g_value_array_remove (factories, factidx);
-
/* 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",
continue;
}
- /* 2.3. Find its sink pad */
- if (!(sinkpad = find_sink_pad (element))) {
- GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
+ /* ... activate it ... We do this before adding it to the bin so that we
+ * don't accidentally make it post error messages that will stop
+ * everything. */
+ if ((gst_element_set_state (element,
+ GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
GST_ELEMENT_NAME (element));
gst_object_unref (element);
continue;
}
- /* 2.4 add it ... */
- if (!(gst_bin_add (GST_BIN (dbin), element))) {
- GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
+ /* 2.3. Find its sink pad, this should work after activating it. */
+ if (!(sinkpad = find_sink_pad (element))) {
+ GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
GST_ELEMENT_NAME (element));
- gst_object_unref (sinkpad);
gst_object_unref (element);
continue;
}
- /* ... activate it ... */
- if ((gst_element_set_state (element,
- GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
- GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
+ /* 2.4 add it ... */
+ if (!(gst_bin_add (GST_BIN_CAST (dbin), element))) {
+ GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
GST_ELEMENT_NAME (element));
gst_object_unref (sinkpad);
- gst_bin_remove (GST_BIN (dbin), element);
+ gst_object_unref (element);
continue;
}
break;
}
+beach:
if (mqpad)
gst_object_unref (mqpad);
-beach:
return res;
}
}
}
-static gboolean
-plugin_init (GstPlugin * plugin)
+gboolean
+gst_decode_bin_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0,
"decoder bin");
return gst_element_register (plugin, "decodebin2", GST_RANK_NONE,
GST_TYPE_DECODE_BIN);
}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "decodebin2",
- "decoder bin newer version", plugin_init, VERSION, GST_LICENSE,
- GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
#include "gstfactorylists.h"
+typedef struct
+{
+ GstFactoryListType type;
+} FilterData;
+
/* function used to sort element features. We first sort on the rank, then
* on the element name (to get a consistent, predictable list) */
static gint
return diff;
}
-#if 0
-static void
-print_feature (GstPluginFeature * feature)
-{
- const gchar *rname;
-
- rname = gst_plugin_feature_get_name (feature);
-
- GST_DEBUG ("%s", rname);
-}
-#endif
-
-/* get a filtered feature list as a GValueArray */
-static GValueArray *
-get_feature_array (GstPluginFeatureFilter filter)
-{
- GValueArray *result;
- GList *walk, *list;
-
- result = g_value_array_new (0);
-
- /* get the feature list using the filter */
- list = gst_default_registry_feature_filter (filter, FALSE, NULL);
-
- /* convert to an array */
- for (walk = list; walk; walk = g_list_next (walk)) {
- GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
- GValue val = { 0, };
-
- g_value_init (&val, G_TYPE_OBJECT);
- g_value_set_object (&val, factory);
- g_value_array_append (result, &val);
- g_value_unset (&val);
- }
- gst_plugin_feature_list_free (list);
-
- /* sort on rank and name */
- g_value_array_sort (result, (GCompareFunc) compare_ranks);
-
- return result;
-}
-
/* the filter function for selecting the elements we can use in
* autoplugging */
static gboolean
-decoders_filter (GstPluginFeature * feature)
+decoders_filter (GstElementFactory * factory)
{
guint rank;
const gchar *klass;
- /* we only care about element factories */
- if (!GST_IS_ELEMENT_FACTORY (feature))
- return FALSE;
-
- klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
+ klass = gst_element_factory_get_klass (factory);
/* only demuxers, decoders, depayloaders and parsers can play */
if (strstr (klass, "Demux") == NULL &&
strstr (klass, "Decoder") == NULL &&
}
/* only select elements with autoplugging rank */
- rank = gst_plugin_feature_get_rank (feature);
+ rank = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory));
if (rank < GST_RANK_MARGINAL)
return FALSE;
/* the filter function for selecting the elements we can use in
* autoplugging */
static gboolean
-sinks_filter (GstPluginFeature * feature)
+sinks_filter (GstElementFactory * factory)
{
guint rank;
const gchar *klass;
- /* we only care about element factories */
- if (!GST_IS_ELEMENT_FACTORY (feature))
- return FALSE;
-
- klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
+ klass = gst_element_factory_get_klass (factory);
/* only sinks can play */
if (strstr (klass, "Sink") == NULL) {
return FALSE;
}
/* only select elements with autoplugging rank */
- rank = gst_plugin_feature_get_rank (feature);
+ rank = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory));
if (rank < GST_RANK_MARGINAL)
return FALSE;
return TRUE;
}
-
/**
- * gst_factory_list_get_decoders:
+ * gst_factory_list_is_type:
+ * @factory: a #GstElementFactory
+ * @type: a #GstFactoryListType
*
- * Get a sorted list of factories that can be used in decoding pipelines.
+ * Check if @factory if of the given types.
*
- * Returns: a #GValueArray of #GstElementFactory elements. Use
- * g_value_array_free() after usage.
+ * Returns: %TRUE if @factory is of @type.
*/
-GValueArray *
-gst_factory_list_get_decoders (void)
+gboolean
+gst_factory_list_is_type (GstElementFactory * factory, GstFactoryListType type)
{
- GValueArray *result;
+ gboolean res = FALSE;
- /* first filter out the interesting element factories */
- result = get_feature_array ((GstPluginFeatureFilter) decoders_filter);
+ if (!res && (type & GST_FACTORY_LIST_SINK))
+ res = sinks_filter (factory);
+ if (!res && (type & GST_FACTORY_LIST_DECODER))
+ res = decoders_filter (factory);
- return result;
+ return res;
+}
+
+static gboolean
+element_filter (GstPluginFeature * feature, FilterData * data)
+{
+ gboolean res;
+
+ /* we only care about element factories */
+ if (!GST_IS_ELEMENT_FACTORY (feature))
+ return FALSE;
+
+ res = gst_factory_list_is_type (GST_ELEMENT_FACTORY (feature), data->type);
+
+ return res;
}
/**
- * gst_factory_list_get_sinks:
+ * gst_factory_list_get_elements:
+ * @type: a #GstFactoryListType
*
- * Get a sorted list of factories that can be used as sinks in a decoding
- * pipeline.
+ * Get a sorted list of factories of @type.
*
* Returns: a #GValueArray of #GstElementFactory elements. Use
* g_value_array_free() after usage.
*/
GValueArray *
-gst_factory_list_get_sinks (void)
+gst_factory_list_get_elements (GstFactoryListType type)
{
GValueArray *result;
+ GList *walk, *list;
+ FilterData data;
- /* first filter out the interesting element factories */
- result = get_feature_array ((GstPluginFeatureFilter) sinks_filter);
+ result = g_value_array_new (0);
+
+ /* prepare type */
+ data.type = type;
+
+ /* get the feature list using the filter */
+ list =
+ gst_default_registry_feature_filter ((GstPluginFeatureFilter)
+ element_filter, FALSE, &data);
+
+ /* convert to an array */
+ for (walk = list; walk; walk = g_list_next (walk)) {
+ GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
+ GValue val = { 0, };
+
+ g_value_init (&val, G_TYPE_OBJECT);
+ g_value_set_object (&val, factory);
+ g_value_array_append (result, &val);
+ g_value_unset (&val);
+ }
+ gst_plugin_feature_list_free (list);
+
+ /* sort on rank and name */
+ g_value_array_sort (result, (GCompareFunc) compare_ranks);
return result;
}
+/**
+ * gst_factory_list_debug:
+ * @array: an array of element factories
+ *
+ * Debug the element factory names in @array.
+ */
+void
+gst_factory_list_debug (GValueArray * array)
+{
+ gint i;
+
+ for (i = 0; i < array->n_values; i++) {
+ GValue *value;
+ GstPluginFeature *feature;
+
+ value = g_value_array_get_nth (array, i);
+ feature = g_value_get_object (value);
+
+ GST_DEBUG ("%s", gst_plugin_feature_get_name (feature));
+ }
+}
+
/**
* gst_factory_list_filter:
* @array: a #GValueArray to filter
G_BEGIN_DECLS
-GValueArray * gst_factory_list_get_decoders (void);
-GValueArray * gst_factory_list_get_sinks (void);
+typedef enum {
+ GST_FACTORY_LIST_DECODER = (1 << 0),
+ GST_FACTORY_LIST_ENCODER = (1 << 1),
+ GST_FACTORY_LIST_SINK = (1 << 2),
+ GST_FACTORY_LIST_SRC = (1 << 3)
+} GstFactoryListType;
+
+gboolean gst_factory_list_is_type (GstElementFactory *factory, GstFactoryListType type);
+GValueArray * gst_factory_list_get_elements (GstFactoryListType type);
+
+void gst_factory_list_debug (GValueArray *array);
GValueArray * gst_factory_list_filter (GValueArray *array, const GstCaps *caps);
BOOLEAN:OBJECT,OBJECT
+BOOLEAN:OBJECT,OBJECT,OBJECT
BOXED:OBJECT,OBJECT
VOID:OBJECT,BOOLEAN
-INT:OBJECT,OBJECT,BOXED
+ENUM:OBJECT,OBJECT,BOXED
+ENUM:OBJECT,OBJECT,OBJECT
+BOXED:OBJECT,OBJECT,BOXED
#include <gst/gst-i18n-plugin.h>
#include <gst/pbutils/pbutils.h>
+#include "gstplay-enum.h"
#include "gstplaysink.h"
#include "gstfactorylists.h"
#include "gststreaminfo.h"
/* our play sink */
GstPlaySink *playsink;
- GValueArray *elements; /* factories we can use for selecting sinks */
- GValueArray *sinks; /* factories we can use for selecting sinks */
+ GValueArray *elements; /* factories we can use for selecting elements */
};
struct _GstPlayBinClass
{
/* init selectors */
group->playbin = playbin;
- group->selector[0].media = "audio/";
- group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO;
+ group->selector[0].media = "audio/x-raw-";
+ group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
group->selector[0].mode = GST_PLAY_SINK_MODE_AUDIO;
- group->selector[1].media = "video/";
- group->selector[1].type = GST_PLAY_SINK_TYPE_VIDEO;
- group->selector[1].mode = GST_PLAY_SINK_MODE_VIDEO;
- group->selector[2].media = "text/";
- group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
- group->selector[2].mode = GST_PLAY_SINK_MODE_TEXT;
+ group->selector[1].media = "audio/";
+ group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
+ group->selector[1].mode = GST_PLAY_SINK_MODE_AUDIO;
+ group->selector[2].media = "video/x-raw-";
+ group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
+ group->selector[2].mode = GST_PLAY_SINK_MODE_VIDEO;
+ group->selector[3].media = "video/";
+ group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO;
+ group->selector[3].mode = GST_PLAY_SINK_MODE_VIDEO;
+ group->selector[4].media = "text/";
+ group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT;
+ group->selector[4].mode = GST_PLAY_SINK_MODE_TEXT;
}
static void
gst_play_bin_init (GstPlayBin * playbin)
{
+ GstFactoryListType type;
+
/* init groups */
playbin->curr_group = &playbin->groups[0];
playbin->next_group = &playbin->groups[1];
init_group (playbin, &playbin->groups[1]);
/* first filter out the interesting element factories */
- playbin->sinks = gst_factory_list_get_sinks ();
+ type = GST_FACTORY_LIST_DECODER | GST_FACTORY_LIST_SINK;
+ playbin->elements = gst_factory_list_get_elements (type);
+ gst_factory_list_debug (playbin->elements);
/* get the caps */
}
play_bin = GST_PLAY_BIN (object);
- g_value_array_free (play_bin->sinks);
+ g_value_array_free (play_bin->elements);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
GST_DEBUG_OBJECT (playbin, "pad not linked");
return;
}
-
}
/* we get called when all pads are available and we must connect the sinks to
}
}
-/* a callback is called */
+/* Called when we must provide a list of factories to plug to @pad with @caps.
+ * We first check if we have a sink that can handle the format and if we do, we
+ * return NULL, to expose the pad. If we have no sink (or the sink does not
+ * work), we return the list of elements that can connect. */
static GValueArray *
autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
GstCaps * caps, GstSourceGroup * group)
{
GstPlayBin *playbin;
- GValueArray *result = NULL;
+ GValueArray *result;
playbin = group->playbin;
- GST_DEBUG_OBJECT (playbin, "continue group %p for %s:%s, %" GST_PTR_FORMAT,
+ GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
group, GST_DEBUG_PAD_NAME (pad), caps);
+ /* filter out the elements based on the caps. */
+ result = gst_factory_list_filter (playbin->elements, caps);
GST_DEBUG_OBJECT (playbin, "found factories %p", result);
+ gst_factory_list_debug (result);
return result;
}
+/* We are asked to select an element. See if the next element to check
+ * is a sink. If this is the case, we see if the sink works by setting it to
+ * READY. If the sink works, we return -2 to make decodebin expose the raw pad
+ * so that we can setup the mixers. */
+static GstAutoplugSelectResult
+autoplug_select_cb (GstElement * decodebin, GstPad * pad,
+ GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
+{
+ GstPlayBin *playbin;
+ GstElement *element;
+ const gchar *klass;
+
+ playbin = group->playbin;
+
+ GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
+ group, GST_DEBUG_PAD_NAME (pad), caps);
+
+ GST_DEBUG_OBJECT (playbin, "checking factory %s",
+ GST_PLUGIN_FEATURE_NAME (factory));
+
+ /* if it's not a sink, we just make decodebin try it */
+ if (!gst_factory_list_is_type (factory, GST_FACTORY_LIST_SINK))
+ return GST_AUTOPLUG_SELECT_TRY;
+
+ /* it's a sink, see if an instance of it actually works */
+ GST_DEBUG_OBJECT (playbin, "we found a sink");
+
+ if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
+ GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
+ gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
+ return GST_AUTOPLUG_SELECT_SKIP;
+ }
+
+ /* ... activate it ... We do this before adding it to the bin so that we
+ * don't accidentally make it post error messages that will stop
+ * everything. */
+ if ((gst_element_set_state (element,
+ GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING_OBJECT (playbin, "Couldn't set %s to READY",
+ GST_ELEMENT_NAME (element));
+ gst_object_unref (element);
+ return GST_AUTOPLUG_SELECT_SKIP;
+ }
+
+ /* at this point, we have the sink working, configure it in playsink */
+ klass = gst_element_factory_get_klass (factory);
+
+ /* get klass to figure out if it's audio or video */
+ if (strstr (klass, "Audio")) {
+ GST_DEBUG_OBJECT (playbin, "configure audio sink");
+ gst_play_sink_set_audio_sink (playbin->playsink, element);
+ } else if (strstr (klass, "Video")) {
+ GST_DEBUG_OBJECT (playbin, "configure video sink");
+ gst_play_sink_set_video_sink (playbin->playsink, element);
+ } else {
+ GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
+ }
+
+ /* tell decodebin to expose the pad because we are going to use this
+ * sink */
+ GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
+
+ return GST_AUTOPLUG_SELECT_EXPOSE;
+}
+
/* unlink a group of uridecodebins from the sink */
static void
unlink_group (GstPlayBin * playbin, GstSourceGroup * group)
* next uri */
g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb), group);
- /* will be called when a new media type is found. We will see if we have a
- * working sink that can natively handle this format. */
+ /* will be called when a new media type is found. We return a list of decoders
+ * including sinks for decodebin to try */
g_signal_connect (uridecodebin, "autoplug-factories",
G_CALLBACK (autoplug_factories_cb), group);
+ g_signal_connect (uridecodebin, "autoplug-select",
+ G_CALLBACK (autoplug_select_cb), group);
+
/* */
gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
group->uridecodebin = uridecodebin;
GstPlayChain *videochain;
GstPad *audio_pad;
+ gboolean audio_pad_raw;
GstPad *video_pad;
+ gboolean video_pad_raw;
GstPad *text_pad;
/* properties */
play_sink);
}
-static void
+void
gst_play_sink_set_video_sink (GstPlaySink * play_sink, GstElement * sink)
{
GST_OBJECT_LOCK (play_sink);
GST_OBJECT_UNLOCK (play_sink);
}
-static void
+void
gst_play_sink_set_audio_sink (GstPlaySink * play_sink, GstElement * sink)
{
GST_OBJECT_LOCK (play_sink);
GST_OBJECT_UNLOCK (play_sink);
}
-static void
+void
gst_play_sink_set_vis_plugin (GstPlaySink * play_sink,
GstElement * pending_visualisation)
{
*
*/
static GstPlayChain *
-gen_video_chain (GstPlaySink * play_sink)
+gen_video_chain (GstPlaySink * play_sink, gboolean raw)
{
GstPlayVideoChain *chain;
GstBin *bin;
gst_object_sink (bin);
gst_bin_add (bin, chain->sink);
+ if (raw) {
+ chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
+ if (chain->conv == NULL)
+ goto no_colorspace;
+ gst_bin_add (bin, chain->conv);
- chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
- if (chain->conv == NULL)
- goto no_colorspace;
- gst_bin_add (bin, chain->conv);
+ chain->scale = gst_element_factory_make ("videoscale", "vscale");
+ if (chain->scale == NULL)
+ goto no_videoscale;
+ gst_bin_add (bin, chain->scale);
+ }
/* decouple decoder from sink, this improves playback quite a lot since the
* decoder can continue while the sink blocks for synchronisation. We don't
"max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
gst_bin_add (bin, chain->queue);
- chain->scale = gst_element_factory_make ("videoscale", "vscale");
- if (chain->scale == NULL)
- goto no_videoscale;
- gst_bin_add (bin, chain->scale);
+ if (raw) {
+ gst_element_link_pads (chain->conv, "src", chain->queue, "sink");
+ gst_element_link_pads (chain->queue, "src", chain->scale, "sink");
+ /* be more careful with the pad from the custom sink element, it might not
+ * be named 'sink' */
+ if (!gst_element_link_pads (chain->scale, "src", chain->sink, NULL))
+ goto link_failed;
- gst_element_link_pads (chain->conv, "src", chain->queue, "sink");
- gst_element_link_pads (chain->queue, "src", chain->scale, "sink");
- /* be more careful with the pad from the custom sink element, it might not
- * be named 'sink' */
- if (!gst_element_link_pads (chain->scale, "src", chain->sink, NULL))
- goto link_failed;
+ pad = gst_element_get_pad (chain->conv, "sink");
+ } else {
+ if (!gst_element_link_pads (chain->queue, "src", chain->sink, NULL))
+ goto link_failed;
+ pad = gst_element_get_pad (chain->queue, "sink");
+ }
- pad = gst_element_get_pad (chain->conv, "sink");
chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad);
gst_object_unref (pad);
gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad);
* +-------------------------------------------------------------+
*/
static GstPlayChain *
-gen_audio_chain (GstPlaySink * play_sink)
+gen_audio_chain (GstPlaySink * play_sink, gboolean raw)
{
GstPlayAudioChain *chain;
GstBin *bin;
gst_object_sink (bin);
gst_bin_add (bin, chain->sink);
- chain->conv = gst_element_factory_make ("audioconvert", "aconv");
- if (chain->conv == NULL)
- goto no_audioconvert;
- gst_bin_add (bin, chain->conv);
-
- chain->resample = gst_element_factory_make ("audioresample", "aresample");
- if (chain->resample == NULL)
- goto no_audioresample;
- gst_bin_add (bin, chain->resample);
-
- chain->volume = gst_element_factory_make ("volume", "volume");
- g_object_set (G_OBJECT (chain->volume), "volume", play_sink->volume, NULL);
- gst_bin_add (bin, chain->volume);
-
- res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
- res &= gst_element_link_pads (chain->resample, "src", chain->volume, "sink");
- res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL);
- if (!res)
- goto link_failed;
-
- pad = gst_element_get_pad (chain->conv, "sink");
+ if (raw) {
+ chain->conv = gst_element_factory_make ("audioconvert", "aconv");
+ if (chain->conv == NULL)
+ goto no_audioconvert;
+ gst_bin_add (bin, chain->conv);
+
+ chain->resample = gst_element_factory_make ("audioresample", "aresample");
+ if (chain->resample == NULL)
+ goto no_audioresample;
+ gst_bin_add (bin, chain->resample);
+
+ chain->volume = gst_element_factory_make ("volume", "volume");
+ g_object_set (G_OBJECT (chain->volume), "volume", play_sink->volume, NULL);
+ gst_bin_add (bin, chain->volume);
+
+ res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
+ res &=
+ gst_element_link_pads (chain->resample, "src", chain->volume, "sink");
+ res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL);
+ if (!res)
+ goto link_failed;
+
+ pad = gst_element_get_pad (chain->conv, "sink");
+ } else {
+ pad = gst_element_get_pad (chain->sink, "sink");
+ }
chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad);
gst_object_unref (pad);
gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad);
{
if (mode & GST_PLAY_SINK_MODE_AUDIO && playsink->audio_pad) {
if (!playsink->audiochain)
- playsink->audiochain = gen_audio_chain (playsink);
+ playsink->audiochain =
+ gen_audio_chain (playsink, playsink->audio_pad_raw);
add_chain (playsink->audiochain, TRUE);
activate_chain (playsink->audiochain, TRUE);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->audio_pad),
if (mode & GST_PLAY_SINK_MODE_VIDEO && playsink->video_pad) {
if (!playsink->videochain)
- playsink->videochain = gen_video_chain (playsink);
+ playsink->videochain =
+ gen_video_chain (playsink, playsink->video_pad_raw);
add_chain (playsink->videochain, TRUE);
activate_chain (playsink->videochain, TRUE);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad),
{
GstPad *res = NULL;
gboolean created = FALSE;
+ gboolean raw = FALSE;
switch (type) {
+ case GST_PLAY_SINK_TYPE_AUDIO_RAW:
+ raw = TRUE;
case GST_PLAY_SINK_TYPE_AUDIO:
if (!playsink->audio_pad) {
playsink->audio_pad =
gst_ghost_pad_new_no_target ("audio_sink", GST_PAD_SINK);
created = TRUE;
}
+ playsink->audio_pad_raw = raw;
res = playsink->audio_pad;
break;
+ case GST_PLAY_SINK_TYPE_VIDEO_RAW:
+ raw = TRUE;
case GST_PLAY_SINK_TYPE_VIDEO:
if (!playsink->video_pad) {
playsink->video_pad =
gst_ghost_pad_new_no_target ("video_sink", GST_PAD_SINK);
created = TRUE;
}
+ playsink->video_pad_raw = raw;
res = playsink->video_pad;
break;
case GST_PLAY_SINK_TYPE_TEXT:
* Features to enable in the sink.
*/
typedef enum {
- GST_PLAY_SINK_MODE_VIDEO = (1 << 0),
- GST_PLAY_SINK_MODE_AUDIO = (1 << 1),
- GST_PLAY_SINK_MODE_TEXT = (1 << 2),
- GST_PLAY_SINK_MODE_VIS = (1 << 3)
+ GST_PLAY_SINK_MODE_VIDEO = (1 << 0),
+ GST_PLAY_SINK_MODE_AUDIO = (1 << 1),
+ GST_PLAY_SINK_MODE_TEXT = (1 << 2),
+ GST_PLAY_SINK_MODE_VIS = (1 << 3)
} GstPlaySinkMode;
+/**
+ * GstPlaySinkType:
+ * @GST_PLAY_SINK_TYPE_AUDIO: A non-raw audio pad
+ * @GST_PLAY_SINK_TYPE_AUDIO_RAW: a raw audio pad
+ * @GST_PLAY_SINK_TYPE_VIDEO: a non-raw video pad
+ * @GST_PLAY_SINK_TYPE_VIDEO_RAW: a raw video pad
+ * @GST_PLAY_SINK_TYPE_TEXT: a raw text pad
+ * @GST_PLAY_SINK_TYPE_LAST: the last type
+ *
+ * Types of pads that can be requested from the sinks.
+ */
typedef enum {
- GST_PLAY_SINK_TYPE_AUDIO = 0,
- GST_PLAY_SINK_TYPE_VIDEO = 1,
- GST_PLAY_SINK_TYPE_TEXT = 2,
- GST_PLAY_SINK_TYPE_LAST = 3
+ GST_PLAY_SINK_TYPE_AUDIO = 0,
+ GST_PLAY_SINK_TYPE_AUDIO_RAW = 1,
+ GST_PLAY_SINK_TYPE_VIDEO = 2,
+ GST_PLAY_SINK_TYPE_VIDEO_RAW = 3,
+ GST_PLAY_SINK_TYPE_TEXT = 4,
+ GST_PLAY_SINK_TYPE_LAST = 5
} GstPlaySinkType;
typedef struct _GstPlaySink GstPlaySink;
GstPad * gst_play_sink_request_pad (GstPlaySink *playsink, GstPlaySinkType type);
void gst_play_sink_release_pad (GstPlaySink *playsink, GstPad *pad);
+void gst_play_sink_set_video_sink (GstPlaySink * play_sink, GstElement * sink);
+void gst_play_sink_set_audio_sink (GstPlaySink * play_sink, GstElement * sink);
+void gst_play_sink_set_vis_plugin (GstPlaySink * play_sink, GstElement * vis);
+
GstPlaySinkMode gst_play_sink_get_mode (GstPlaySink *playsink);
gboolean gst_play_sink_set_mode (GstPlaySink *playsink, GstPlaySinkMode mode);
#include <gst/gst-i18n-plugin.h>
#include "gstplay-marshal.h"
+#include "gstplay-enum.h"
#define GST_TYPE_URI_DECODE_BIN \
(gst_uri_decode_bin_get_type())
GValueArray *(*autoplug_factories) (GstElement * element, GstPad * pad,
GstCaps * caps);
/* signal fired to select from the proposed list of factories */
- gint (*autoplug_select) (GstElement * element, GstPad * pad, GstCaps * caps,
- GValueArray * factories);
+ GstAutoplugSelectResult (*autoplug_select) (GstElement * element,
+ GstPad * pad, GstCaps * caps, GValueArray * factories);
/* emited when all data is decoded */
void (*drained) (GstElement * element);
return myboolean;
}
+static gboolean
+_gst_array_accumulator (GSignalInvocationHint * ihint,
+ GValue * return_accu, const GValue * handler_return, gpointer dummy)
+{
+ gpointer array;
+
+ array = g_value_get_boxed (handler_return);
+ if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
+ g_value_set_boxed (return_accu, array);
+
+ return FALSE;
+}
+
+static gboolean
+_gst_select_accumulator (GSignalInvocationHint * ihint,
+ GValue * return_accu, const GValue * handler_return, gpointer dummy)
+{
+ GstAutoplugSelectResult res;
+
+ res = g_value_get_enum (handler_return);
+ if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
+ g_value_set_enum (return_accu, res);
+
+ return FALSE;
+}
+
static gboolean
gst_uri_decode_bin_autoplug_continue (GstElement * element, GstPad * pad,
GstCaps * caps)
gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES] =
g_signal_new ("autoplug-factories", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass,
- autoplug_factories), NULL, NULL,
+ autoplug_factories), _gst_array_accumulator, NULL,
gst_play_marshal_BOXED__OBJECT_OBJECT, G_TYPE_VALUE_ARRAY, 2,
GST_TYPE_PAD, GST_TYPE_CAPS);
gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT] =
g_signal_new ("autoplug-select", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass,
- autoplug_select), NULL, NULL,
- gst_play_marshal_INT__OBJECT_OBJECT_BOXED, G_TYPE_INT, 3, GST_TYPE_PAD,
- GST_TYPE_CAPS, G_TYPE_VALUE_ARRAY);
+ autoplug_select), _gst_select_accumulator, NULL,
+ gst_play_marshal_ENUM__OBJECT_OBJECT_OBJECT,
+ GST_TYPE_AUTOPLUG_SELECT_RESULT, 3, GST_TYPE_PAD, GST_TYPE_CAPS,
+ GST_TYPE_ELEMENT_FACTORY);
/**
* GstURIDecodeBin::drained:
return result;
}
-static gint
+static GstAutoplugSelectResult
proxy_autoplug_select_signal (GstElement * element, GstPad * pad,
- GstCaps * caps, GValueArray * array, GstURIDecodeBin * dec)
+ GstCaps * caps, GstElementFactory * factory, GstURIDecodeBin * dec)
{
- gint result;
+ GstAutoplugSelectResult result;
g_signal_emit (G_OBJECT (dec),
- gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT], 0, pad, caps, array,
+ gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT], 0, pad, caps, factory,
&result);
GST_DEBUG_OBJECT (dec, "autoplug-select returned %d", result);
}
}
+gboolean gst_decode_bin_plugin_init (GstPlugin * plugin);
+
static gboolean
-plugin_init (GstPlugin * plugin)
+gst_uri_decode_bin_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_uri_decode_bin_debug, "uridecodebin", 0,
"URI decoder element");
GST_TYPE_URI_DECODE_BIN);
}
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_decode_bin_plugin_init (plugin))
+ return FALSE;
+ if (!gst_uri_decode_bin_plugin_init (plugin))
+ return FALSE;
+
+ return TRUE;
+}
+
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"uridecodebin",