diff --git a/ChangeLog b/ChangeLog index c56e924ffb..41ed97447d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2007-10-25 Wim Taymans + + * gst/playback/gstdecodebin2.c: (gst_decode_bin_class_init), + (gst_decode_bin_dispose), (gst_decode_bin_set_caps), + (gst_decode_bin_set_subs_encoding), + (gst_decode_bin_get_subs_encoding), (gst_decode_bin_set_property), + (gst_decode_bin_get_property), (analyze_new_pad): + Move subtitle encoding property to decodebin2 so that it can set the + property value on all elements that it autoplugs and that require it. + Make caps refcounting more consistent in get/set. + + * gst/playback/gsturidecodebin.c: (_gst_boolean_accumulator), + (gst_uri_decode_bin_class_init), (gst_uri_decode_bin_init), + (gst_uri_decode_bin_finalize), (gst_uri_decode_bin_set_property), + (gst_uri_decode_bin_get_property), (proxy_unknown_type_signal), + (proxy_autoplug_continue_signal), + (proxy_autoplug_factories_signal), (proxy_autoplug_select_signal), + (make_decoder): + Proxy properties and relevant signals from the internal decodebin. + Make properties MT safe. + 2007-10-25 Tim-Philipp Müller * gst-libs/gst/tag/tag.h: (GST_TAG_MUSICBRAINZ_SORTNAME): diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 365bd3660e..f0a481c3bd 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -82,6 +82,10 @@ struct _GstDecodeBin { GstBin bin; /* we extend GstBin */ + /* properties */ + GstCaps *caps; /* caps on which to stop decoding */ + gchar *encoding; /* encoding of subtitles */ + GstElement *typefind; /* this holds the typefind object */ GstElement *fakesink; @@ -92,7 +96,6 @@ struct _GstDecodeBin GList *oldgroups; /* List of no-longer-used GstDecodeGroups. * Should be freed in dispose */ gint nbpads; /* unique identifier for source pads */ - GstCaps *caps; /* caps on which to stop decoding */ GList *factories; /* factories we can use for selecting elements */ @@ -139,6 +142,7 @@ enum { PROP_0, PROP_CAPS, + PROP_SUBTITLE_ENCODING }; static GstBinClass *parent_class; @@ -451,6 +455,13 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass) g_param_spec_boxed ("caps", "Caps", "The caps on which to stop decoding.", 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)); + klass->autoplug_continue = GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_continue); klass->autoplug_factories = @@ -625,6 +636,10 @@ gst_decode_bin_dispose (GObject * object) if (decode_bin->caps) gst_caps_unref (decode_bin->caps); decode_bin->caps = NULL; + + g_free (decode_bin->encoding); + decode_bin->encoding = NULL; + remove_fakesink (decode_bin); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -645,52 +660,14 @@ gst_decode_bin_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } -static void -gst_decode_bin_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstDecodeBin *dbin; - - dbin = GST_DECODE_BIN (object); - - switch (prop_id) { - case PROP_CAPS: - gst_decode_bin_set_caps (dbin, (GstCaps *) g_value_dup_boxed (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_decode_bin_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstDecodeBin *dbin; - - dbin = GST_DECODE_BIN (object); - switch (prop_id) { - case PROP_CAPS:{ - g_value_take_boxed (value, gst_decode_bin_get_caps (dbin)); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - -} - /* _set_caps * Changes the caps on which decodebin will stop decoding. * Will unref the previously set one. The refcount of the given caps will be - * taken. + * increased. * @caps can be NULL. * * MT-safe */ - static void gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps) { @@ -699,6 +676,8 @@ gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps) DECODE_BIN_LOCK (dbin); if (dbin->caps) gst_caps_unref (dbin->caps); + if (caps) + gst_caps_ref (caps); dbin->caps = caps; DECODE_BIN_UNLOCK (dbin); } @@ -726,6 +705,73 @@ gst_decode_bin_get_caps (GstDecodeBin * dbin) return caps; } +static void +gst_decode_bin_set_subs_encoding (GstDecodeBin * dbin, const gchar * encoding) +{ + GST_DEBUG_OBJECT (dbin, "Setting new encoding: %s", GST_STR_NULL (encoding)); + + DECODE_BIN_LOCK (dbin); + g_free (dbin->encoding); + dbin->encoding = g_strdup (encoding); + DECODE_BIN_UNLOCK (dbin); +} + +static gchar * +gst_decode_bin_get_subs_encoding (GstDecodeBin * dbin) +{ + gchar *encoding; + + GST_DEBUG_OBJECT (dbin, "Getting currently set encoding"); + + DECODE_BIN_LOCK (dbin); + encoding = g_strdup (dbin->encoding); + DECODE_BIN_UNLOCK (dbin); + + return encoding; +} + +static void +gst_decode_bin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDecodeBin *dbin; + + dbin = GST_DECODE_BIN (object); + + switch (prop_id) { + case PROP_CAPS: + gst_decode_bin_set_caps (dbin, g_value_get_boxed (value)); + break; + case PROP_SUBTITLE_ENCODING: + gst_decode_bin_set_subs_encoding (dbin, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_decode_bin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstDecodeBin *dbin; + + dbin = GST_DECODE_BIN (object); + switch (prop_id) { + case PROP_CAPS: + g_value_take_boxed (value, gst_decode_bin_get_caps (dbin)); + break; + case PROP_SUBTITLE_ENCODING: + g_value_take_string (value, gst_decode_bin_get_subs_encoding (dbin)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + static GValueArray *find_compatibles (GstDecodeBin * decode_bin, GstPad * pad, const GstCaps * caps); @@ -846,7 +892,6 @@ expose_pad: expose_pad (dbin, src, pad, group); return; } - unknown_type: { GST_LOG_OBJECT (pad, "Unknown type, firing signal"); @@ -861,7 +906,6 @@ unknown_type: gst_missing_decoder_message_new (GST_ELEMENT_CAST (dbin), caps)); return; } - non_fixed: { GST_DEBUG_OBJECT (pad, "pad has non-fixed caps delay autoplugging"); diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c index f9dc018760..995fd637ac 100644 --- a/gst/playback/gsturidecodebin.c +++ b/gst/playback/gsturidecodebin.c @@ -33,6 +33,8 @@ #include #include +#include "gstplay-marshal.h" + #define GST_TYPE_URI_DECODE_BIN \ (gst_uri_decode_bin_get_type()) #define GST_URI_DECODE_BIN(obj) \ @@ -53,6 +55,8 @@ struct _GstURIDecodeBin gchar *uri; guint connection_speed; + GstCaps *caps; + gchar *encoding; gboolean is_stream; GstElement *source; @@ -70,6 +74,19 @@ struct _GstURIDecodeBin struct _GstURIDecodeBinClass { GstBinClass parent_class; + + /* signal fired when we found a pad that we cannot decode */ + void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps); + + /* signal fired to know if we continue trying to decode the given caps */ + gboolean (*autoplug_continue) (GstElement * element, GstPad * pad, + GstCaps * caps); + /* signal fired to get a list of factories to try to autoplug */ + 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); }; static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src%d", @@ -86,16 +103,34 @@ GST_ELEMENT_DETAILS ("URI Decoder", "Autoplug and decode an URI to raw media", "Wim Taymans "); -#define DEFAULT_PROP_URI NULL +/* signals */ +enum +{ + SIGNAL_UNKNOWN_TYPE, + SIGNAL_AUTOPLUG_CONTINUE, + SIGNAL_AUTOPLUG_FACTORIES, + SIGNAL_AUTOPLUG_SELECT, + LAST_SIGNAL +}; + +/* properties */ +#define DEFAULT_PROP_URI NULL #define DEFAULT_CONNECTION_SPEED 0 +#define DEFAULT_CAPS NULL +#define DEFAULT_SUBTITLE_ENCODING NULL + enum { PROP_0, PROP_URI, PROP_CONNECTION_SPEED, + PROP_CAPS, + PROP_SUBTITLE_ENCODING, PROP_LAST }; +static guint gst_uri_decode_bin_signals[LAST_SIGNAL] = { 0 }; + GST_BOILERPLATE (GstURIDecodeBin, gst_uri_decode_bin, GstBin, GST_TYPE_BIN); static void gst_uri_decode_bin_set_property (GObject * object, guint prop_id, @@ -119,6 +154,20 @@ gst_uri_decode_bin_base_init (gpointer g_class) gst_element_class_set_details (gstelement_class, &gst_uri_decode_bin_details); } +static gboolean +_gst_boolean_accumulator (GSignalInvocationHint * ihint, + GValue * return_accu, const GValue * handler_return, gpointer dummy) +{ + gboolean myboolean; + + myboolean = g_value_get_boolean (handler_return); + if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP)) + g_value_set_boolean (return_accu, myboolean); + + /* stop emission if FALSE */ + return myboolean; +} + static void gst_uri_decode_bin_class_init (GstURIDecodeBinClass * klass) { @@ -143,6 +192,93 @@ gst_uri_decode_bin_class_init (GstURIDecodeBinClass * klass) "Network connection speed in kbps (0 = unknown)", 0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_CAPS, + g_param_spec_boxed ("caps", "Caps", + "The caps on which to stop decoding. (NULL = default)", + GST_TYPE_CAPS, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, 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)); + + /** + * GstURIDecodeBin::unknown-type: + * @pad: the new pad containing caps that cannot be resolved to a 'final' stream type. + * @caps: the #GstCaps of the pad that cannot be resolved. + * + * This signal is emitted when a pad for which there is no further possible + * decoding is added to the uridecodebin. + */ + gst_uri_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] = + g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass, unknown_type), + NULL, NULL, gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, + GST_TYPE_PAD, GST_TYPE_CAPS); + + /** + * GstURIDecodeBin::autoplug-continue: + * @pad: The #GstPad. + * @caps: The #GstCaps found. + * + * This signal is emitted whenever uridecodebin finds a new stream. It is + * emitted before looking for any elements that can handle that stream. + * + * Returns: #TRUE if you wish uridecodebin to look for elements that can + * handle the given @caps. If #FALSE, those caps will be considered as + * final and the pad will be exposed as such (see 'new-decoded-pad' + * signal). + */ + gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE] = + g_signal_new ("autoplug-continue", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass, + autoplug_continue), _gst_boolean_accumulator, NULL, + gst_play_marshal_BOOLEAN__OBJECT_OBJECT, G_TYPE_BOOLEAN, 2, GST_TYPE_PAD, + GST_TYPE_CAPS); + + /** + * GstURIDecodeBin::autoplug-factories: + * @pad: The #GstPad. + * @caps: The #GstCaps found. + * + * This function is emited when an array of possible factories for @caps on + * @pad is needed. Decodebin2 will by default return + * + * Returns: a #GValueArray* with a list of factories to try. The factories are + * by default tried in the returned order or based on the index returned by + * "autoplug-select". + */ + 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, + gst_play_marshal_BOXED__OBJECT_OBJECT, G_TYPE_VALUE_ARRAY, 2, + GST_TYPE_PAD, GST_TYPE_CAPS); + + /** + * GstURIDecodeBin::autoplug-select: + * @pad: The #GstPad. + * @caps: The #GstCaps. + * @factories: A #GValueArray of possible #GstElementFactory to use, sorted by + * rank (higher ranks come first). + * + * This signal is emitted once uridecodebin has found all the possible + * #GstElementFactory that can be used to handle the given @caps. + * + * Returns: A #gint indicating what factory index from the @factories array + * that you wish uridecodebin 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. + */ + 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); + gstelement_class->query = GST_DEBUG_FUNCPTR (gst_uri_decode_bin_query); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_uri_decode_bin_change_state); @@ -152,7 +288,9 @@ static void gst_uri_decode_bin_init (GstURIDecodeBin * dec, GstURIDecodeBinClass * klass) { dec->uri = g_strdup (DEFAULT_PROP_URI); - dec->uri = DEFAULT_CONNECTION_SPEED; + dec->connection_speed = DEFAULT_CONNECTION_SPEED; + dec->caps = DEFAULT_CAPS; + dec->encoding = g_strdup (DEFAULT_SUBTITLE_ENCODING); } static void @@ -161,7 +299,7 @@ gst_uri_decode_bin_finalize (GObject * obj) GstURIDecodeBin *dec = GST_URI_DECODE_BIN (obj); g_free (dec->uri); - dec->uri = NULL; + g_free (dec->encoding); G_OBJECT_CLASS (parent_class)->finalize (obj); } @@ -174,11 +312,28 @@ gst_uri_decode_bin_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_URI: + GST_OBJECT_LOCK (dec); g_free (dec->uri); dec->uri = g_value_dup_string (value); + GST_OBJECT_UNLOCK (dec); break; case PROP_CONNECTION_SPEED: + GST_OBJECT_LOCK (dec); dec->connection_speed = g_value_get_uint (value) * 1000; + GST_OBJECT_UNLOCK (dec); + break; + case PROP_CAPS: + GST_OBJECT_LOCK (dec); + if (dec->caps) + gst_caps_unref (dec->caps); + dec->caps = g_value_dup_boxed (value); + GST_OBJECT_UNLOCK (dec); + break; + case PROP_SUBTITLE_ENCODING: + GST_OBJECT_LOCK (dec); + g_free (dec->encoding); + dec->encoding = g_value_dup_string (value); + GST_OBJECT_UNLOCK (dec); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -194,10 +349,24 @@ gst_uri_decode_bin_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_URI: + GST_OBJECT_LOCK (dec); g_value_set_string (value, dec->uri); + GST_OBJECT_UNLOCK (dec); break; case PROP_CONNECTION_SPEED: + GST_OBJECT_LOCK (dec); g_value_set_uint (value, dec->connection_speed / 1000); + GST_OBJECT_UNLOCK (dec); + break; + case PROP_CAPS: + GST_OBJECT_LOCK (dec); + g_value_set_boxed (value, dec->caps); + GST_OBJECT_UNLOCK (dec); + break; + case PROP_SUBTITLE_ENCODING: + GST_OBJECT_LOCK (dec); + g_value_set_string (value, dec->encoding); + GST_OBJECT_UNLOCK (dec); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -602,6 +771,50 @@ remove_pads (GstURIDecodeBin * bin) bin->srcpads = NULL; } +static void +proxy_unknown_type_signal (GstElement * element, GstPad * pad, GstCaps * caps, + GstURIDecodeBin * dec) +{ + g_signal_emit (G_OBJECT (dec), + gst_uri_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps); +} + +static gboolean +proxy_autoplug_continue_signal (GstElement * element, GstPad * pad, + GstCaps * caps, GstURIDecodeBin * dec) +{ + gboolean result; + + g_signal_emit (G_OBJECT (dec), + gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, pad, caps, + &result); + return result; +} + +static GValueArray * +proxy_autoplug_factories_signal (GstElement * element, GstPad * pad, + GstCaps * caps, GstURIDecodeBin * dec) +{ + GValueArray *result; + + g_signal_emit (G_OBJECT (dec), + gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES], 0, pad, caps, + &result); + return result; +} + +static gint +proxy_autoplug_select_signal (GstElement * element, GstPad * pad, + GstCaps * caps, GValueArray * array, GstURIDecodeBin * dec) +{ + gint result; + + g_signal_emit (G_OBJECT (dec), + gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT], 0, pad, caps, array, + &result); + return result; +} + static GstElement * make_decoder (GstURIDecodeBin * decoder, gboolean use_queue) { @@ -612,6 +825,16 @@ make_decoder (GstURIDecodeBin * decoder, gboolean use_queue) if (!decodebin) goto no_decodebin; + /* connect signals to proxy */ + g_signal_connect (G_OBJECT (decodebin), "unknown-type", + G_CALLBACK (proxy_unknown_type_signal), decoder); + g_signal_connect (G_OBJECT (decodebin), "autoplug-continue", + G_CALLBACK (proxy_autoplug_continue_signal), decoder); + g_signal_connect (G_OBJECT (decodebin), "autoplug-factories", + G_CALLBACK (proxy_autoplug_factories_signal), decoder); + g_signal_connect (G_OBJECT (decodebin), "autoplug-select", + G_CALLBACK (proxy_autoplug_select_signal), decoder); + if (use_queue) { GstElement *queue; GstPad *gpad, *pad;