From f2f9bf045ba32d7a79069837ed63fb103c6b995a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 5 Dec 2007 17:11:48 +0000 Subject: [PATCH] gst/playback/Makefile.am: Group decodebin2 and uridecodebin into the same plugin so that they can share the GEnumType. Original commit message from CVS: * 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. --- ChangeLog | 48 +++++++ gst/playback/Makefile.am | 15 +-- gst/playback/gstdecodebin2.c | 204 +++++++++++++++++++++--------- gst/playback/gstfactorylists.c | 163 +++++++++++++----------- gst/playback/gstfactorylists.h | 13 +- gst/playback/gstplay-marshal.list | 5 +- gst/playback/gstplaybin2.c | 119 ++++++++++++++--- gst/playback/gstplaysink.c | 110 +++++++++------- gst/playback/gstplaysink.h | 33 +++-- gst/playback/gsturidecodebin.c | 63 +++++++-- 10 files changed, 546 insertions(+), 227 deletions(-) diff --git a/ChangeLog b/ChangeLog index 49676b3d1d..1f181cc24e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,51 @@ +2007-12-05 Wim Taymans + + * 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 * gst-libs/gst/rtp/gstbasertppayload.c: (gst_basertppayload_push): diff --git a/gst/playback/Makefile.am b/gst/playback/Makefile.am index 5f5c9b882d..b694885f0c 100644 --- a/gst/playback/Makefile.am +++ b/gst/playback/Makefile.am @@ -7,8 +7,7 @@ built_headers = gstplay-marshal.h 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 \ @@ -16,6 +15,7 @@ libgstplaybin_la_SOURCES = \ gstplaybin2.c \ gstplaysink.c \ gstplaybasebin.c \ + gstplay-enum.c \ gstfactorylists.c \ gststreaminfo.c \ gststreamselector.c @@ -35,7 +35,7 @@ libgstdecodebin_la_LIBADD = \ $(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) @@ -49,19 +49,12 @@ libgstqueue2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) 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 diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 10a8ac79dd..314481d0d6 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -43,6 +43,7 @@ #include #include "gstplay-marshal.h" +#include "gstplay-enum.h" #include "gstfactorylists.h" /* generic templates */ @@ -121,9 +122,12 @@ struct _GstDecodeBinClass /* 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); @@ -138,6 +142,7 @@ enum SIGNAL_AUTOPLUG_CONTINUE, SIGNAL_AUTOPLUG_FACTORIES, SIGNAL_AUTOPLUG_SELECT, + SIGNAL_AUTOPLUG_SORT, SIGNAL_DRAINED, LAST_SIGNAL }; @@ -170,8 +175,10 @@ static gboolean gst_decode_bin_autoplug_continue (GstElement * element, 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); @@ -336,6 +343,33 @@ _gst_boolean_accumulator (GSignalInvocationHint * ihint, 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) { @@ -435,10 +469,31 @@ 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. @@ -451,14 +506,16 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass) * * 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 @@ -487,6 +544,7 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass) 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, @@ -504,7 +562,8 @@ static void 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"); @@ -754,17 +813,28 @@ gst_decode_bin_autoplug_factories (GstElement * element, GstPad * pad, 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; } /******** @@ -776,7 +846,7 @@ static gboolean is_demuxer_element (GstElement * srcelement); 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, @@ -813,7 +883,8 @@ analyze_new_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); @@ -856,12 +927,22 @@ analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, 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: @@ -934,7 +1015,8 @@ setup_caps_delay: */ 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; @@ -942,6 +1024,8 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, 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); @@ -964,32 +1048,37 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, /* 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", @@ -997,30 +1086,31 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, 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; } @@ -1053,10 +1143,10 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad, break; } +beach: if (mqpad) gst_object_unref (mqpad); -beach: return res; } @@ -2306,8 +2396,8 @@ missing_fakesink: } } -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"); @@ -2321,9 +2411,3 @@ plugin_init (GstPlugin * plugin) 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) diff --git a/gst/playback/gstfactorylists.c b/gst/playback/gstfactorylists.c index ca6166d837..667beaf0fe 100644 --- a/gst/playback/gstfactorylists.c +++ b/gst/playback/gstfactorylists.c @@ -20,6 +20,11 @@ #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 @@ -44,61 +49,15 @@ compare_ranks (GValue * v1, GValue * v2) 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 && @@ -108,7 +67,7 @@ decoders_filter (GstPluginFeature * feature) } /* 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; @@ -118,16 +77,12 @@ decoders_filter (GstPluginFeature * feature) /* 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; @@ -139,53 +94,115 @@ sinks_filter (GstPluginFeature * feature) } /* 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 diff --git a/gst/playback/gstfactorylists.h b/gst/playback/gstfactorylists.h index 100535c2cb..c8e50757df 100644 --- a/gst/playback/gstfactorylists.h +++ b/gst/playback/gstfactorylists.h @@ -25,8 +25,17 @@ 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); diff --git a/gst/playback/gstplay-marshal.list b/gst/playback/gstplay-marshal.list index 03b6bfd5ea..300a5b44c0 100644 --- a/gst/playback/gstplay-marshal.list +++ b/gst/playback/gstplay-marshal.list @@ -1,4 +1,7 @@ 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 diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 5c6132ec01..8cb00f6c1d 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -248,6 +248,7 @@ #include #include +#include "gstplay-enum.h" #include "gstplaysink.h" #include "gstfactorylists.h" #include "gststreaminfo.h" @@ -321,8 +322,7 @@ struct _GstPlayBin /* 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 @@ -530,20 +530,28 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group) { /* 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]; @@ -551,7 +559,9 @@ gst_play_bin_init (GstPlayBin * playbin) 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 */ } @@ -563,7 +573,7 @@ gst_play_bin_finalize (GObject * object) 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); } @@ -868,7 +878,6 @@ not_linked: GST_DEBUG_OBJECT (playbin, "pad not linked"); return; } - } /* we get called when all pads are available and we must connect the sinks to @@ -949,25 +958,96 @@ drained_cb (GstElement * decodebin, GstSourceGroup * group) } } -/* 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) @@ -1022,11 +1102,14 @@ activate_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; diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 387a70635e..bdc2217e2b 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -74,7 +74,9 @@ struct _GstPlaySink GstPlayChain *videochain; GstPad *audio_pad; + gboolean audio_pad_raw; GstPad *video_pad; + gboolean video_pad_raw; GstPad *text_pad; /* properties */ @@ -388,7 +390,7 @@ beach: play_sink); } -static void +void gst_play_sink_set_video_sink (GstPlaySink * play_sink, GstElement * sink) { GST_OBJECT_LOCK (play_sink); @@ -403,7 +405,7 @@ gst_play_sink_set_video_sink (GstPlaySink * play_sink, GstElement * 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); @@ -418,7 +420,7 @@ gst_play_sink_set_audio_sink (GstPlaySink * play_sink, GstElement * sink) GST_OBJECT_UNLOCK (play_sink); } -static void +void gst_play_sink_set_vis_plugin (GstPlaySink * play_sink, GstElement * pending_visualisation) { @@ -622,7 +624,7 @@ activate_chain (GstPlayChain * chain, gboolean activate) * */ static GstPlayChain * -gen_video_chain (GstPlaySink * play_sink) +gen_video_chain (GstPlaySink * play_sink, gboolean raw) { GstPlayVideoChain *chain; GstBin *bin; @@ -650,11 +652,17 @@ gen_video_chain (GstPlaySink * play_sink) 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 @@ -665,19 +673,21 @@ gen_video_chain (GstPlaySink * play_sink) "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); @@ -817,7 +827,7 @@ no_overlay: * +-------------------------------------------------------------+ */ static GstPlayChain * -gen_audio_chain (GstPlaySink * play_sink) +gen_audio_chain (GstPlaySink * play_sink, gboolean raw) { GstPlayAudioChain *chain; GstBin *bin; @@ -843,27 +853,32 @@ gen_audio_chain (GstPlaySink * play_sink) 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); @@ -1078,7 +1093,8 @@ gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode) { 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), @@ -1094,7 +1110,8 @@ gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode) 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), @@ -1118,22 +1135,29 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type) { 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: diff --git a/gst/playback/gstplaysink.h b/gst/playback/gstplaysink.h index e319e2c84f..50da18e521 100644 --- a/gst/playback/gstplaysink.h +++ b/gst/playback/gstplaysink.h @@ -45,17 +45,30 @@ G_BEGIN_DECLS * 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; @@ -66,6 +79,10 @@ GType gst_play_sink_get_type (void); 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); diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c index 90d031a8f7..6013ba48de 100644 --- a/gst/playback/gsturidecodebin.c +++ b/gst/playback/gsturidecodebin.c @@ -34,6 +34,7 @@ #include #include "gstplay-marshal.h" +#include "gstplay-enum.h" #define GST_TYPE_URI_DECODE_BIN \ (gst_uri_decode_bin_get_type()) @@ -85,8 +86,8 @@ struct _GstURIDecodeBinClass 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); @@ -174,6 +175,32 @@ _gst_boolean_accumulator (GSignalInvocationHint * ihint, 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) @@ -267,7 +294,7 @@ gst_uri_decode_bin_class_init (GstURIDecodeBinClass * klass) 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); @@ -289,9 +316,10 @@ gst_uri_decode_bin_class_init (GstURIDecodeBinClass * klass) 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: @@ -871,14 +899,14 @@ proxy_autoplug_factories_signal (GstElement * element, GstPad * pad, 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); @@ -1558,8 +1586,10 @@ setup_failed: } } +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"); @@ -1574,6 +1604,17 @@ plugin_init (GstPlugin * plugin) 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", -- 2.34.1