From: Tim-Philipp Müller Date: Thu, 16 Jun 2011 16:27:21 +0000 (+0100) Subject: Bump git version after unplanned 0.10.35 release X-Git-Tag: freedesktop-RELEASE-0.10.36~246 X-Git-Url: https://git.ti.com/gitweb?p=glsdk%2Fgstreamer0-10.git;a=commitdiff_plain;h=239461f4a104ed55097fb92b1455c98bb843a0b8;hp=783bac2bc4d17850c7ce17759805021574d095e0 Bump git version after unplanned 0.10.35 release Merge remote-tracking branch 'origin/0.10.35' --- diff --git a/common b/common index 46dfcea23..69b981f10 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 46dfcea233cf6df83e3771d8a8066e87d614f893 +Subproject commit 69b981f10caa234ad0ff639179d0fda8505bd94b diff --git a/configure.ac b/configure.ac index f625f86a6..0a03ccdd9 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.60) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, git and prerelease does Werror too -AC_INIT(GStreamer, 0.10.35, +AC_INIT(GStreamer, 0.10.35.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gstreamer) AG_GST_INIT @@ -535,7 +535,7 @@ LIBS="$save_libs" dnl *** checks for dependency libraries *** dnl GLib -GLIB_REQ=2.22 +GLIB_REQ=2.24 AG_GST_GLIB_CHECK([$GLIB_REQ]) diff --git a/docs/faq/general.xml b/docs/faq/general.xml index 1e6641cf3..60e9b7ddc 100644 --- a/docs/faq/general.xml +++ b/docs/faq/general.xml @@ -77,7 +77,7 @@ on the GStreamer project website. GStreamer aims to support every format imaginable, but that doesn't mean the developers have managed to achieve that aim yet. If a GStreamer enabled application doesn't play back your files, you can help us solve that problem -by filing an enhancement request +by filing an enhancement request bug for that format. If you have it, please provide: links to other players, preferrably Open Source and working diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index e1eba92c6..c29ac0531 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -323,6 +323,7 @@ gst_caps_is_equal gst_caps_is_equal_fixed gst_caps_is_always_compatible gst_caps_is_subset +gst_caps_is_subset_structure gst_caps_can_intersect gst_caps_intersect gst_caps_intersect_full @@ -902,14 +903,44 @@ gst_format_get_type
gstghostpad GstGhostPad +GstProxyPad GstGhostPad + gst_ghost_pad_new gst_ghost_pad_new_no_target gst_ghost_pad_new_from_template gst_ghost_pad_new_no_target_from_template + gst_ghost_pad_set_target gst_ghost_pad_get_target + gst_ghost_pad_construct + +gst_ghost_pad_setcaps_default +gst_ghost_pad_unlink_default +gst_ghost_pad_link_default +gst_ghost_pad_activate_pull_default +gst_ghost_pad_activate_push_default + +gst_ghost_pad_internal_activate_push_default +gst_ghost_pad_internal_activate_pull_default + +gst_proxy_pad_get_internal + +gst_proxy_pad_query_type_default +gst_proxy_pad_event_default +gst_proxy_pad_query_default +gst_proxy_pad_iterate_internal_links_default +gst_proxy_pad_bufferalloc_default +gst_proxy_pad_chain_default +gst_proxy_pad_chain_list_default +gst_proxy_pad_getrange_default +gst_proxy_pad_checkgetrange_default +gst_proxy_pad_getcaps_default +gst_proxy_pad_acceptcaps_default +gst_proxy_pad_fixatecaps_default +gst_proxy_pad_setcaps_default +gst_proxy_pad_unlink_default GstGhostPadClass GST_GHOST_PAD @@ -925,7 +956,6 @@ GST_PROXY_PAD GST_PROXY_PAD_CLASS GST_TYPE_PROXY_PAD GstGhostPadPrivate -GstProxyPad GstProxyPadClass GstProxyPadPrivate gst_proxy_pad_get_type @@ -1313,6 +1343,7 @@ GstMiniObject GstMiniObjectFlags GstMiniObjectCopyFunction GstMiniObjectFinalizeFunction +GstMiniObjectWeakNotify GST_MINI_OBJECT_FLAGS GST_MINI_OBJECT_FLAG_IS_SET @@ -1330,6 +1361,9 @@ gst_mini_object_ref gst_mini_object_unref gst_mini_object_replace +gst_mini_object_weak_ref +gst_mini_object_weak_unref + GstParamSpecMiniObject gst_param_spec_mini_object @@ -2175,6 +2209,10 @@ gst_structure_foreach gst_structure_n_fields gst_structure_has_field gst_structure_has_field_typed +gst_structure_is_equal +gst_structure_is_subset +gst_structure_can_intersect +gst_structure_intersect gst_structure_id_has_field gst_structure_id_has_field_typed gst_structure_get_boolean diff --git a/docs/libs/gstreamer-libs-sections.txt b/docs/libs/gstreamer-libs-sections.txt index 1a4326659..621cbbdae 100644 --- a/docs/libs/gstreamer-libs-sections.txt +++ b/docs/libs/gstreamer-libs-sections.txt @@ -286,6 +286,7 @@ gst_base_src_get_blocksize gst_base_src_set_blocksize gst_base_src_get_do_timestamp gst_base_src_set_do_timestamp +gst_base_src_set_dynamic_size gst_base_src_new_seamless_segment GST_BASE_SRC_PAD diff --git a/docs/plugins/gstreamer-plugins.args b/docs/plugins/gstreamer-plugins.args index 75548b2bc..fd88bb8ca 100644 --- a/docs/plugins/gstreamer-plugins.args +++ b/docs/plugins/gstreamer-plugins.args @@ -271,7 +271,7 @@ GstFakeSink::num-buffers gint ->= G_MAXULONG +>= -1 rw num-buffers Number of buffers to accept going EOS. @@ -848,6 +848,16 @@ FALSE + +GstMultiQueue::sync-by-running-time +gboolean + +rw +Sync By Running Time +Synchronize deactivated or not-linked streams by running time. +FALSE + + GstBin::async-handling gboolean @@ -1068,3 +1078,13 @@ FALSE + +GstInputSelector::sync-streams +gboolean + +rw +Sync Streams +Synchronize inactive streams to the running time of the active stream. +FALSE + + diff --git a/docs/plugins/gstreamer-plugins.hierarchy b/docs/plugins/gstreamer-plugins.hierarchy index 4201ecb5b..ea81e4aad 100644 --- a/docs/plugins/gstreamer-plugins.hierarchy +++ b/docs/plugins/gstreamer-plugins.hierarchy @@ -1,44 +1,43 @@ GObject GstObject - GstPad - GstPadTemplate - GstPluginFeature - GstElementFactory - GstTypeFindFactory - GstIndexFactory + GstBus + GstClock GstElement - GstBin - GstPipeline - GstBaseTransform - GstCapsFilter - GstIdentity - GstBaseSrc - GstFakeSrc - GstPushSrc - GstFdSrc - GstFileSrc GstBaseSink GstFakeSink GstFdSink GstFileSink + GstBaseSrc + GstFakeSrc + GstFileSrc + GstPushSrc + GstFdSrc + GstBaseTransform + GstCapsFilter + GstIdentity + GstBin + GstPipeline GstFunnel GstInputSelector + GstMultiQueue GstOutputSelector GstQueue GstQueue2 GstTee GstTypeFindElement - GstMultiQueue GstValve - GstBus - GstTask - GstTaskPool - GstClock - GstPlugin - GstRegistry GstIndex GstMemIndex - GstFileIndex + GstPad + GstPadTemplate + GstPlugin + GstPluginFeature + GstElementFactory + GstIndexFactory + GstTypeFindFactory + GstRegistry + GstTask + GstTaskPool GstSignalObject GInterface GTypePlugin diff --git a/docs/plugins/gstreamer-plugins.interfaces b/docs/plugins/gstreamer-plugins.interfaces index 024530368..03805f5be 100644 --- a/docs/plugins/gstreamer-plugins.interfaces +++ b/docs/plugins/gstreamer-plugins.interfaces @@ -1,6 +1,6 @@ GstBin GstChildProxy -GstPipeline GstChildProxy -GstFdSrc GstURIHandler -GstFileSrc GstURIHandler GstFdSink GstURIHandler +GstFdSrc GstURIHandler GstFileSink GstURIHandler +GstFileSrc GstURIHandler +GstPipeline GstChildProxy diff --git a/docs/plugins/inspect/plugin-coreelements.xml b/docs/plugins/inspect/plugin-coreelements.xml index 50ea185af..e99c7802a 100644 --- a/docs/plugins/inspect/plugin-coreelements.xml +++ b/docs/plugins/inspect/plugin-coreelements.xml @@ -3,10 +3,10 @@ standard GStreamer elements ../../plugins/elements/.libs/libgstcoreelements.so libgstcoreelements.so - 0.10.35 + 0.10.35.1 LGPL gstreamer - GStreamer source release + GStreamer git Unknown package origin @@ -331,4 +331,4 @@ - \ No newline at end of file + diff --git a/docs/plugins/inspect/plugin-coreindexers.xml b/docs/plugins/inspect/plugin-coreindexers.xml index b7741d07e..80f072e2a 100644 --- a/docs/plugins/inspect/plugin-coreindexers.xml +++ b/docs/plugins/inspect/plugin-coreindexers.xml @@ -3,11 +3,11 @@ GStreamer core indexers ../../plugins/indexers/.libs/libgstcoreindexers.so libgstcoreindexers.so - 0.10.35 + 0.10.35.1 LGPL gstreamer - GStreamer source release + GStreamer git Unknown package origin - \ No newline at end of file + diff --git a/docs/random/release b/docs/random/release index 6a8a3779e..f45bf97c1 100644 --- a/docs/random/release +++ b/docs/random/release @@ -129,7 +129,7 @@ RELEASE PROCEDURE: + e.g: scp gstreamer-0.10.42.tar.gz master.gnome.org: ssh master.gnome.org - install-module gstreamer-0.10.42.tar.gz + ftpadmin install gstreamer-0.10.42.tar.gz - Send release announcements to: gstreamer-devel@lists.sourceforge.net gstreamer-announce@lists.sourceforge.net kde-multimedia@kde.org gnome-multimedia@gnome.org diff --git a/gst/gst_private.h b/gst/gst_private.h index 2cafbee61..6bd67250f 100644 --- a/gst/gst_private.h +++ b/gst/gst_private.h @@ -51,6 +51,9 @@ extern const char g_log_domain_gstreamer[]; /* for the pad cache */ #include "gstpad.h" +/* for GstElement */ +#include "gstelement.h" + G_BEGIN_DECLS /* used by gstparse.c and grammar.y */ @@ -113,6 +116,10 @@ gboolean _gst_plugin_loader_client_run (void); void _priv_gst_pad_invalidate_cache (GstPad *pad); +/* Used in GstBin for manual state handling */ +void _priv_gst_element_state_changed (GstElement *element, GstState oldstate, + GstState newstate, GstState pending); + /* used in both gststructure.c and gstcaps.c; numbers are completely made up */ #define STRUCTURE_ESTIMATED_STRING_LEN(s) (16 + (s)->fields->len * 22) @@ -234,5 +241,10 @@ extern GstDebugCategory *_priv_GST_CAT_POLL; #endif +#ifdef GST_DISABLE_DEPRECATED +typedef GList* (*GstPadIntLinkFunction) (GstPad *pad); +#endif + + G_END_DECLS #endif /* __GST_PRIVATE_H__ */ diff --git a/gst/gstbin.c b/gst/gstbin.c index 73758213e..89ad34e72 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -220,6 +220,8 @@ struct _GstBinPrivate GstIndex *index; /* forward messages from our children */ gboolean message_forward; + + gboolean posted_eos; }; typedef struct @@ -238,12 +240,15 @@ static void gst_bin_get_property (GObject * object, guint prop_id, static GstStateChangeReturn gst_bin_change_state_func (GstElement * element, GstStateChange transition); +static void gst_bin_state_changed (GstElement * element, GstState oldstate, + GstState newstate, GstState pending); static GstStateChangeReturn gst_bin_get_state_func (GstElement * element, GstState * state, GstState * pending, GstClockTime timeout); static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret, gboolean flag_pending); static void bin_handle_async_start (GstBin * bin, gboolean new_base_time); static void bin_push_state_continue (BinContinueData * data); +static void bin_do_eos (GstBin * bin); static gboolean gst_bin_add_func (GstBin * bin, GstElement * element); static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element); @@ -502,6 +507,7 @@ gst_bin_class_init (GstBinClass * klass) gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state_func); + gstelement_class->state_changed = GST_DEBUG_FUNCPTR (gst_bin_state_changed); gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state_func); gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_bin_get_index_func); gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func); @@ -987,10 +993,11 @@ bin_remove_messages (GstBin * bin, GstObject * src, GstMessageType types) * * call with bin LOCK */ static gboolean -is_eos (GstBin * bin) +is_eos (GstBin * bin, guint32 * seqnum) { gboolean result; - GList *walk; + gint n_eos = 0; + GList *walk, *msgs; result = TRUE; for (walk = bin->children; walk; walk = g_list_next (walk)) { @@ -999,8 +1006,11 @@ is_eos (GstBin * bin) element = GST_ELEMENT_CAST (walk->data); if (bin_element_is_sink (element, bin) == 0) { /* check if element posted EOS */ - if (find_message (bin, GST_OBJECT_CAST (element), GST_MESSAGE_EOS)) { + if ((msgs = + find_message (bin, GST_OBJECT_CAST (element), GST_MESSAGE_EOS))) { GST_DEBUG ("sink '%s' posted EOS", GST_ELEMENT_NAME (element)); + *seqnum = gst_message_get_seqnum (GST_MESSAGE_CAST (msgs->data)); + n_eos++; } else { GST_DEBUG ("sink '%s' did not post EOS yet", GST_ELEMENT_NAME (element)); @@ -1009,7 +1019,13 @@ is_eos (GstBin * bin) } } } - return result; + /* FIXME: Some tests (e.g. elements/capsfilter) use + * pipelines with a dangling sinkpad but no sink element. + * These tests assume that no EOS message is ever + * posted on the bus so let's keep that behaviour. + * In valid pipelines this doesn't make a difference. + */ + return result && n_eos > 0; } static void @@ -2226,24 +2242,23 @@ unneeded: } /* gst_iterator_fold functions for pads_activate - * Note how we don't stop the iterator when we fail an activation. This is - * probably a FIXME since when one pad activation fails, we don't want to - * continue our state change. */ + * Stop the iterator if activating one pad failed. */ static gboolean activate_pads (GstPad * pad, GValue * ret, gboolean * active) { - if (!gst_pad_set_active (pad, *active)) + gboolean cont = TRUE; + + if (!(cont = gst_pad_set_active (pad, *active))) g_value_set_boolean (ret, FALSE); else if (!*active) gst_pad_set_caps (pad, NULL); /* unref the object that was reffed for us by _fold */ gst_object_unref (pad); - return TRUE; + return cont; } -/* returns false on error or early cutout (will never happen because the fold - * function always returns TRUE, see FIXME above) of the fold, true if all +/* returns false on error or early cutout of the fold, true if all * pads in @iter were (de)activated successfully. */ static gboolean iterator_activate_fold_with_resync (GstIterator * iter, gpointer user_data) @@ -2388,6 +2403,19 @@ gst_bin_do_latency_func (GstBin * bin) return res; } +static void +gst_bin_state_changed (GstElement * element, GstState oldstate, + GstState newstate, GstState pending) +{ + GstElementClass *pklass = (GstElementClass *) parent_class; + + if (newstate == GST_STATE_PLAYING && pending == GST_STATE_VOID_PENDING) + bin_do_eos (GST_BIN_CAST (element)); + + if (pklass->state_changed) + pklass->state_changed (element, oldstate, newstate, pending); +} + static GstStateChangeReturn gst_bin_change_state_func (GstElement * element, GstStateChange transition) { @@ -2428,6 +2456,7 @@ gst_bin_change_state_func (GstElement * element, GstStateChange transition) GST_OBJECT_LOCK (bin); GST_DEBUG_OBJECT (element, "clearing EOS elements"); bin_remove_messages (bin, NULL, GST_MESSAGE_EOS); + bin->priv->posted_eos = FALSE; GST_OBJECT_UNLOCK (bin); if (current == GST_STATE_READY) if (!(gst_bin_src_pads_activate (bin, TRUE))) @@ -2735,6 +2764,7 @@ gst_bin_continue_func (BinContinueData * data) GST_STATE_UNLOCK (bin); GST_DEBUG_OBJECT (bin, "state continue done"); + gst_object_unref (bin); g_slice_free (BinContinueData, data); return; @@ -2829,9 +2859,8 @@ bin_handle_async_start (GstBin * bin, gboolean new_base_time) GST_OBJECT_UNLOCK (bin); /* post message */ - gst_element_post_message (GST_ELEMENT_CAST (bin), - gst_message_new_state_changed (GST_OBJECT_CAST (bin), - new_state, new_state, new_state)); + _priv_gst_element_state_changed (GST_ELEMENT_CAST (bin), new_state, new_state, + new_state); post_start: if (amessage) { @@ -2873,8 +2902,8 @@ bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret, GstState current, pending, target; GstStateChangeReturn old_ret; GstState old_state, old_next; - gboolean toplevel; - GstMessage *smessage = NULL, *amessage = NULL; + gboolean toplevel, state_changed = FALSE; + GstMessage *amessage = NULL; BinContinueData *cont = NULL; if (GST_STATE_RETURN (bin) == GST_STATE_CHANGE_FAILURE) @@ -2953,15 +2982,14 @@ bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret, if (old_next != GST_STATE_PLAYING) { if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) { - smessage = gst_message_new_state_changed (GST_OBJECT_CAST (bin), - old_state, old_next, pending); + state_changed = TRUE; } } GST_OBJECT_UNLOCK (bin); - if (smessage) { - GST_DEBUG_OBJECT (bin, "posting state change message"); - gst_element_post_message (GST_ELEMENT_CAST (bin), smessage); + if (state_changed) { + _priv_gst_element_state_changed (GST_ELEMENT_CAST (bin), old_state, + old_next, pending); } if (amessage) { /* post our combined ASYNC_DONE when all is ASYNC_DONE. */ @@ -3001,6 +3029,33 @@ nothing_pending: } } +static void +bin_do_eos (GstBin * bin) +{ + guint32 seqnum = 0; + gboolean eos; + + GST_OBJECT_LOCK (bin); + /* If all sinks are EOS, we're in PLAYING and no state change is pending + * we forward the EOS message to the parent bin or application + */ + eos = GST_STATE (bin) == GST_STATE_PLAYING + && GST_STATE_PENDING (bin) == GST_STATE_VOID_PENDING + && is_eos (bin, &seqnum); + GST_OBJECT_UNLOCK (bin); + + if (eos + && g_atomic_int_compare_and_exchange (&bin->priv->posted_eos, FALSE, + TRUE)) { + GstMessage *tmessage; + tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin)); + gst_message_set_seqnum (tmessage, seqnum); + GST_DEBUG_OBJECT (bin, + "all sinks posted EOS, posting seqnum #%" G_GUINT32_FORMAT, seqnum); + gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage); + } +} + /* must be called with the object lock. This function releases the lock to post * the message. */ static void @@ -3109,28 +3164,15 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message) } case GST_MESSAGE_EOS: { - gboolean eos; /* collect all eos messages from the children */ GST_OBJECT_LOCK (bin); bin_do_message_forward (bin, message); /* ref message for future use */ - gst_message_ref (message); bin_replace_message (bin, message, GST_MESSAGE_EOS); - eos = is_eos (bin); GST_OBJECT_UNLOCK (bin); - /* if we are completely EOS, we forward an EOS message */ - if (eos) { - seqnum = gst_message_get_seqnum (message); - tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin)); - gst_message_set_seqnum (tmessage, seqnum); - - GST_DEBUG_OBJECT (bin, - "all sinks posted EOS, posting seqnum #%" G_GUINT32_FORMAT, seqnum); - gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage); - } - gst_message_unref (message); + bin_do_eos (bin); break; } case GST_MESSAGE_STATE_DIRTY: diff --git a/gst/gstcaps.c b/gst/gstcaps.c index 5d8912c4d..6cc673132 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -565,82 +565,6 @@ gst_caps_steal_structure (GstCaps * caps, guint index) return gst_caps_remove_and_get_structure (caps, index); } -static gboolean -gst_structure_is_equal_foreach (GQuark field_id, const GValue * val2, - gpointer data) -{ - GstStructure *struct1 = (GstStructure *) data; - const GValue *val1 = gst_structure_id_get_value (struct1, field_id); - - if (G_UNLIKELY (val1 == NULL)) - return FALSE; - if (gst_value_compare (val1, val2) == GST_VALUE_EQUAL) { - return TRUE; - } - - return FALSE; -} - -static gboolean -gst_caps_structure_is_subset_field (GQuark field_id, const GValue * value, - gpointer user_data) -{ - GstStructure *subtract_from = user_data; - GValue subtraction = { 0, }; - const GValue *other; - - if (!(other = gst_structure_id_get_value (subtract_from, field_id))) - /* field is missing in one set */ - return FALSE; - - /* equal values are subset */ - if (gst_value_compare (other, value) == GST_VALUE_EQUAL) - return TRUE; - - /* - * 1 - [1,2] = empty - * -> !subset - * - * [1,2] - 1 = 2 - * -> 1 - [1,2] = empty - * -> subset - * - * [1,3] - [1,2] = 3 - * -> [1,2] - [1,3] = empty - * -> subset - * - * {1,2} - {1,3} = 2 - * -> {1,3} - {1,2} = 3 - * -> !subset - * - * First caps subtraction needs to return a non-empty set, second - * subtractions needs to give en empty set. - */ - if (gst_value_subtract (&subtraction, other, value)) { - g_value_unset (&subtraction); - /* !empty result, swapping must be empty */ - if (!gst_value_subtract (&subtraction, value, other)) - return TRUE; - - g_value_unset (&subtraction); - } - return FALSE; -} - -static gboolean -gst_caps_structure_is_subset (const GstStructure * minuend, - const GstStructure * subtrahend) -{ - if ((minuend->name != subtrahend->name) || - (gst_structure_n_fields (minuend) != - gst_structure_n_fields (subtrahend))) { - return FALSE; - } - - return gst_structure_foreach ((GstStructure *) subtrahend, - gst_caps_structure_is_subset_field, (gpointer) minuend); -} - /** * gst_caps_append: * @caps1: the #GstCaps that will be appended to @@ -810,7 +734,7 @@ gst_caps_merge_structure (GstCaps * caps, GstStructure * structure) for (i = caps->structs->len - 1; i >= 0; i--) { structure1 = gst_caps_get_structure_unchecked (caps, i); /* if structure is a subset of structure1, then skip it */ - if (gst_caps_structure_is_subset (structure1, structure)) { + if (gst_structure_is_subset (structure, structure1)) { unique = FALSE; break; } @@ -982,12 +906,7 @@ gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs) g_warning ("Don't use G_TYPE_DATE, use GST_TYPE_DATE instead\n"); type = GST_TYPE_DATE; } -#if GLIB_CHECK_VERSION(2,23,3) G_VALUE_COLLECT_INIT (&value, type, varargs, 0, &err); -#else - g_value_init (&value, type); - G_VALUE_COLLECT (&value, varargs, 0, &err); -#endif if (G_UNLIKELY (err)) { g_critical ("%s", err); return; @@ -1117,15 +1036,7 @@ gst_caps_is_equal_fixed (const GstCaps * caps1, const GstCaps * caps2) struct1 = gst_caps_get_structure_unchecked (caps1, 0); struct2 = gst_caps_get_structure_unchecked (caps2, 0); - if (struct1->name != struct2->name) { - return FALSE; - } - if (struct1->fields->len != struct2->fields->len) { - return FALSE; - } - - return gst_structure_foreach (struct1, gst_structure_is_equal_foreach, - struct2); + return gst_structure_is_equal (struct1, struct2); } /** @@ -1162,8 +1073,9 @@ gst_caps_is_always_compatible (const GstCaps * caps1, const GstCaps * caps2) gboolean gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset) { - GstCaps *caps; - gboolean ret; + GstStructure *s1, *s2; + gboolean ret = TRUE; + gint i, j; g_return_val_if_fail (subset != NULL, FALSE); g_return_val_if_fail (superset != NULL, FALSE); @@ -1173,12 +1085,65 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset) if (CAPS_IS_ANY (subset) || CAPS_IS_EMPTY (superset)) return FALSE; - caps = gst_caps_subtract (subset, superset); - ret = CAPS_IS_EMPTY_SIMPLE (caps); - gst_caps_unref (caps); + for (i = subset->structs->len - 1; i >= 0; i--) { + for (j = superset->structs->len - 1; j >= 0; j--) { + s1 = gst_caps_get_structure_unchecked (subset, i); + s2 = gst_caps_get_structure_unchecked (superset, j); + if (gst_structure_is_subset (s1, s2)) { + /* If we found a superset, continue with the next + * subset structure */ + break; + } + } + /* If we found no superset for this subset structure + * we return FALSE immediately */ + if (j == -1) { + ret = FALSE; + break; + } + } + return ret; } +/** + * gst_caps_is_subset_structure: + * @caps: a #GstCaps + * @structure: a potential #GstStructure subset of @caps + * + * Checks if @structure is a subset of @caps. See gst_caps_is_subset() + * for more information. + * + * Returns: %TRUE if @structure is a subset of @caps + * + * Since: 0.10.35 + */ +gboolean +gst_caps_is_subset_structure (const GstCaps * caps, + const GstStructure * structure) +{ + GstStructure *s; + gint i; + + g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (structure != NULL, FALSE); + + if (CAPS_IS_ANY (caps)) + return TRUE; + if (CAPS_IS_EMPTY (caps)) + return FALSE; + + for (i = caps->structs->len - 1; i >= 0; i--) { + s = gst_caps_get_structure_unchecked (caps, i); + if (gst_structure_is_subset (structure, s)) { + /* If we found a superset return TRUE */ + return TRUE; + } + } + + return FALSE; +} + /** * gst_caps_is_equal: * @caps1: a #GstCaps @@ -1215,127 +1180,6 @@ gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2) /* intersect operation */ -typedef struct -{ - GstStructure *dest; - const GstStructure *intersect; -} -IntersectData; - -static gboolean -gst_caps_structure_intersect_field1 (GQuark id, const GValue * val1, - gpointer data) -{ - IntersectData *idata = (IntersectData *) data; - const GValue *val2 = gst_structure_id_get_value (idata->intersect, id); - - if (G_UNLIKELY (val2 == NULL)) { - gst_structure_id_set_value (idata->dest, id, val1); - } else { - GValue dest_value = { 0 }; - if (gst_value_intersect (&dest_value, val1, val2)) { - gst_structure_id_set_value (idata->dest, id, &dest_value); - g_value_unset (&dest_value); - } else { - return FALSE; - } - } - return TRUE; -} - -static gboolean -gst_caps_structure_intersect_field2 (GQuark id, const GValue * val1, - gpointer data) -{ - IntersectData *idata = (IntersectData *) data; - const GValue *val2 = gst_structure_id_get_value (idata->intersect, id); - - if (G_UNLIKELY (val2 == NULL)) { - gst_structure_id_set_value (idata->dest, id, val1); - } - return TRUE; -} - -static GstStructure * -gst_caps_structure_intersect (const GstStructure * struct1, - const GstStructure * struct2) -{ - IntersectData data; - - g_assert (struct1 != NULL); - g_assert (struct2 != NULL); - - if (G_UNLIKELY (struct1->name != struct2->name)) - return NULL; - - /* copy fields from struct1 which we have not in struct2 to target - * intersect if we have the field in both */ - data.dest = gst_structure_id_empty_new (struct1->name); - data.intersect = struct2; - if (G_UNLIKELY (!gst_structure_foreach ((GstStructure *) struct1, - gst_caps_structure_intersect_field1, &data))) - goto error; - - /* copy fields from struct2 which we have not in struct1 to target */ - data.intersect = struct1; - if (G_UNLIKELY (!gst_structure_foreach ((GstStructure *) struct2, - gst_caps_structure_intersect_field2, &data))) - goto error; - - return data.dest; - -error: - gst_structure_free (data.dest); - return NULL; -} - -static gboolean -gst_caps_structure_can_intersect_field (GQuark id, const GValue * val1, - gpointer data) -{ - GstStructure *other = (GstStructure *) data; - const GValue *val2 = gst_structure_id_get_value (other, id); - - if (G_LIKELY (val2)) { - if (!gst_value_can_intersect (val1, val2)) { - return FALSE; - } else { - gint eq = gst_value_compare (val1, val2); - - if (eq == GST_VALUE_UNORDERED) { - /* we need to try interseting */ - GValue dest_value = { 0 }; - if (gst_value_intersect (&dest_value, val1, val2)) { - g_value_unset (&dest_value); - } else { - return FALSE; - } - } else if (eq != GST_VALUE_EQUAL) { - return FALSE; - } - } - } - return TRUE; -} - -static gboolean -gst_caps_structure_can_intersect (const GstStructure * struct1, - const GstStructure * struct2) -{ - g_assert (struct1 != NULL); - g_assert (struct2 != NULL); - - if (G_UNLIKELY (struct1->name != struct2->name)) - return FALSE; - - /* tries to intersect if we have the field in both */ - if (G_UNLIKELY (!gst_structure_foreach ((GstStructure *) struct1, - gst_caps_structure_can_intersect_field, (gpointer) struct2))) - return FALSE; - - return TRUE; -} - /** * gst_caps_can_intersect: * @caps1: a #GstCaps to intersect @@ -1403,7 +1247,7 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2) struct1 = gst_caps_get_structure_unchecked (caps1, j); struct2 = gst_caps_get_structure_unchecked (caps2, k); - if (gst_caps_structure_can_intersect (struct1, struct2)) { + if (gst_structure_can_intersect (struct1, struct2)) { return TRUE; } /* move down left */ @@ -1474,9 +1318,9 @@ gst_caps_intersect_zig_zag (const GstCaps * caps1, const GstCaps * caps2) struct1 = gst_caps_get_structure_unchecked (caps1, j); struct2 = gst_caps_get_structure_unchecked (caps2, k); - istruct = gst_caps_structure_intersect (struct1, struct2); + istruct = gst_structure_intersect (struct1, struct2); - gst_caps_append_structure (dest, istruct); + gst_caps_merge_structure (dest, istruct); /* move down left */ k++; if (G_UNLIKELY (j == 0)) @@ -1533,9 +1377,9 @@ gst_caps_intersect_first (const GstCaps * caps1, const GstCaps * caps2) struct1 = gst_caps_get_structure_unchecked (caps1, i); for (j = 0; j < len2; j++) { struct2 = gst_caps_get_structure_unchecked (caps2, j); - istruct = gst_caps_structure_intersect (struct1, struct2); + istruct = gst_structure_intersect (struct1, struct2); if (istruct) - gst_caps_append_structure (dest, istruct); + gst_caps_merge_structure (dest, istruct); } } diff --git a/gst/gstcaps.h b/gst/gstcaps.h index f79939c61..b7c5c0fc3 100644 --- a/gst/gstcaps.h +++ b/gst/gstcaps.h @@ -258,6 +258,8 @@ gboolean gst_caps_is_always_compatible (const GstCaps *caps1, const GstCaps *caps2); gboolean gst_caps_is_subset (const GstCaps *subset, const GstCaps *superset); +gboolean gst_caps_is_subset_structure (const GstCaps *caps, + const GstStructure *structure); gboolean gst_caps_is_equal (const GstCaps *caps1, const GstCaps *caps2); gboolean gst_caps_is_equal_fixed (const GstCaps *caps1, diff --git a/gst/gstchildproxy.c b/gst/gstchildproxy.c index 65e9527a4..2054aa029 100644 --- a/gst/gstchildproxy.c +++ b/gst/gstchildproxy.c @@ -391,13 +391,9 @@ gst_child_proxy_set_valist (GstObject * object, if (!gst_child_proxy_lookup (object, name, &target, &pspec)) goto not_found; -#if GLIB_CHECK_VERSION(2,23,3) G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args, G_VALUE_NOCOPY_CONTENTS, &error); -#else - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error); -#endif + if (error) goto cant_copy; diff --git a/gst/gstclock.h b/gst/gstclock.h index cc1ed0940..230e19058 100644 --- a/gst/gstclock.h +++ b/gst/gstclock.h @@ -205,15 +205,22 @@ G_STMT_START { \ /** * GST_TIME_FORMAT: * - * A format that can be used in printf like format strings to format - * a #GstClockTime value. + * A string that can be used in printf-like format strings to display a + * #GstClockTime value in h:m:s format. Use GST_TIME_ARGS() to construct + * the matching arguments. + * + * Example: + * |[ + * printf("%" GST_TIME_FORMAT "\n", GST_TIME_ARGS(ts)); + * ]| */ #define GST_TIME_FORMAT "u:%02u:%02u.%09u" /** * GST_TIME_ARGS: * @t: a #GstClockTime * - * Format @t for the GST_TIME_FORMAT format string. + * Format @t for the #GST_TIME_FORMAT format string. Note: @t will be + * evaluated more than once. */ #define GST_TIME_ARGS(t) \ GST_CLOCK_TIME_IS_VALID (t) ? \ @@ -407,7 +414,7 @@ typedef enum { * @tv: a #GTimeVal to wait. * * Wait on the clock until the entries changed or the specified timeout - * occurred. + * occurred. */ #define GST_CLOCK_TIMED_WAIT(clock,tv) g_cond_timed_wait(GST_CLOCK_COND(clock),GST_OBJECT_GET_LOCK(clock),tv) /** @@ -430,7 +437,7 @@ struct _GstClock { GMutex *slave_lock; /* order: SLAVE_LOCK, OBJECT_LOCK */ /*< protected >*/ /* with LOCK */ - GstClockTime internal_calibration; + GstClockTime internal_calibration; GstClockTime external_calibration; GstClockTime rate_numerator; GstClockTime rate_denominator; @@ -521,7 +528,7 @@ void gst_clock_get_calibration (GstClock *clock, GstClockTime *internal, /* master/slave clocks */ gboolean gst_clock_set_master (GstClock *clock, GstClock *master); GstClock* gst_clock_get_master (GstClock *clock); -gboolean gst_clock_add_observation (GstClock *clock, GstClockTime slave, +gboolean gst_clock_add_observation (GstClock *clock, GstClockTime slave, GstClockTime master, gdouble *r_squared); diff --git a/gst/gstelement.c b/gst/gstelement.c index 12fc6fac8..ddbba3e40 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -2317,6 +2317,28 @@ nothing_aborted: } } +/* Not static because GstBin has manual state handling too */ +void +_priv_gst_element_state_changed (GstElement * element, GstState oldstate, + GstState newstate, GstState pending) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); + GstMessage *message; + + GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, + "notifying about state-changed %s to %s (%s pending)", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate), + gst_element_state_get_name (pending)); + + if (klass->state_changed) + klass->state_changed (element, oldstate, newstate, pending); + + message = gst_message_new_state_changed (GST_OBJECT_CAST (element), + oldstate, newstate, pending); + gst_element_post_message (element, message); +} + /** * gst_element_continue_state: * @element: a #GstElement to continue the state change of. @@ -2344,7 +2366,6 @@ gst_element_continue_state (GstElement * element, GstStateChangeReturn ret) GstStateChangeReturn old_ret; GstState old_state, old_next; GstState current, next, pending; - GstMessage *message; GstStateChange transition; GST_OBJECT_LOCK (element); @@ -2380,9 +2401,7 @@ gst_element_continue_state (GstElement * element, GstStateChangeReturn ret) gst_element_state_get_name (old_next), gst_element_state_get_name (pending), gst_element_state_get_name (next)); - message = gst_message_new_state_changed (GST_OBJECT_CAST (element), - old_state, old_next, pending); - gst_element_post_message (element, message); + _priv_gst_element_state_changed (element, old_state, old_next, pending); GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "continue state change %s to %s, final %s", @@ -2414,16 +2433,9 @@ complete: * previous return value. * We do signal the cond though as a _get_state() might be blocking * on it. */ - if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) { - GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, - "posting state-changed %s to %s", - gst_element_state_get_name (old_state), - gst_element_state_get_name (old_next)); - message = - gst_message_new_state_changed (GST_OBJECT_CAST (element), old_state, - old_next, GST_STATE_VOID_PENDING); - gst_element_post_message (element, message); - } + if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) + _priv_gst_element_state_changed (element, old_state, old_next, + GST_STATE_VOID_PENDING); GST_STATE_BROADCAST (element); @@ -2496,9 +2508,7 @@ gst_element_lost_state_full (GstElement * element, gboolean new_base_time) GST_ELEMENT_START_TIME (element) = 0; GST_OBJECT_UNLOCK (element); - message = gst_message_new_state_changed (GST_OBJECT_CAST (element), - new_state, new_state, new_state); - gst_element_post_message (element, message); + _priv_gst_element_state_changed (element, new_state, new_state, new_state); message = gst_message_new_async_start (GST_OBJECT_CAST (element), new_base_time); @@ -2793,18 +2803,18 @@ invalid_return: } /* gst_iterator_fold functions for pads_activate - * Note how we don't stop the iterator when we fail an activation. This is - * probably a FIXME since when one pad activation fails, we don't want to - * continue our state change. */ + * Stop the iterator if activating one pad failed. */ static gboolean activate_pads (GstPad * pad, GValue * ret, gboolean * active) { - if (!gst_pad_set_active (pad, *active)) + gboolean cont = TRUE; + + if (!(cont = gst_pad_set_active (pad, *active))) g_value_set_boolean (ret, FALSE); /* unref the object that was reffed for us by _fold */ gst_object_unref (pad); - return TRUE; + return cont; } /* set the caps on the pad to NULL */ @@ -2816,8 +2826,7 @@ clear_caps (GstPad * pad, GValue * ret, gboolean * active) return TRUE; } -/* returns false on error or early cutout (will never happen because the fold - * function always returns TRUE, see FIXME above) of the fold, true if all +/* returns false on error or early cutout of the fold, true if all * pads in @iter were (de)activated successfully. */ static gboolean iterator_activate_fold_with_resync (GstIterator * iter, diff --git a/gst/gstelement.h b/gst/gstelement.h index 04b5ba820..74a0e2ce9 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -85,8 +85,8 @@ G_BEGIN_DECLS * cannot produce data in %GST_STATE_PAUSED. * This typically happens with live sources. * - * The possible return values from a state change function. Only - * @GST_STATE_CHANGE_FAILURE is a real failure. + * The possible return values from a state change function such as + * gst_element_set_state(). Only @GST_STATE_CHANGE_FAILURE is a real failure. */ typedef enum { GST_STATE_CHANGE_FAILURE = 0, @@ -195,17 +195,17 @@ typedef enum { * Streaming threads are started. * * - * Some elements might need to return ASYNC and complete the state change - * when they have enough information. It is a requirement for sinks to - * return ASYNC and complete the state change when they receive the first - * buffer or EOS event (preroll). Sinks also block the dataflow when in - * PAUSED. + * Some elements might need to return %GST_STATE_CHANGE_ASYNC and complete + * the state change when they have enough information. It is a requirement + * for sinks to return %GST_STATE_CHANGE_ASYNC and complete the state change + * when they receive the first buffer or %GST_EVENT_EOS (preroll). + * Sinks also block the dataflow when in PAUSED. * * * A pipeline resets the running_time to 0. * * - * Live sources return NO_PREROLL and don't generate data. + * Live sources return %GST_STATE_CHANGE_NO_PREROLL and don't generate data. * * * @GST_STATE_CHANGE_PAUSED_TO_PLAYING: state change from PAUSED to PLAYING. @@ -214,12 +214,12 @@ typedef enum { * Most elements ignore this state change. * * - * The pipeline selects a clock and distributes this to all the children + * The pipeline selects a #GstClock and distributes this to all the children * before setting them to PLAYING. This means that it is only alowed to - * synchronize on the clock in the PLAYING state. + * synchronize on the #GstClock in the PLAYING state. * * - * The pipeline uses the clock and the running_time to calculate the + * The pipeline uses the #GstClock and the running_time to calculate the * base_time. The base_time is distributed to all children when performing * the state change. * @@ -228,15 +228,15 @@ typedef enum { * rendering the data. * * - * Sinks can post the EOS message in the PLAYING state. It is not allowed to - * post EOS when not in the PLAYING state. + * Sinks can post %GST_MESSAGE_EOS in the PLAYING state. It is not allowed + * to post %GST_MESSAGE_EOS when not in the PLAYING state. * * * While streaming in PAUSED or PLAYING elements can create and remove * sometimes pads. * * - * Live sources start generating data and return SUCCESS. + * Live sources start generating data and return %GST_STATE_CHANGE_SUCCESS. * * * @GST_STATE_CHANGE_PLAYING_TO_PAUSED: state change from PLAYING to PAUSED. @@ -245,24 +245,25 @@ typedef enum { * Most elements ignore this state change. * * - * The pipeline calculates the running_time based on the last selected clock - * and the base_time. It stores this information to continue playback when - * going back to the PLAYING state. + * The pipeline calculates the running_time based on the last selected + * #GstClock and the base_time. It stores this information to continue + * playback when going back to the PLAYING state. * * - * Sinks unblock any clock wait calls. + * Sinks unblock any #GstClock wait calls. * * - * When a sink does not have a pending buffer to play, it returns ASYNC from - * this state change and completes the state change when it receives a new - * buffer or an EOS event. + * When a sink does not have a pending buffer to play, it returns + * %GST_STATE_CHANGE_ASYNC from this state change and completes the state + * change when it receives a new buffer or an %GST_EVENT_EOS. * * - * Any queued EOS messages are removed since they will be reposted when going - * back to the PLAYING state. The EOS messages are queued in GstBins. + * Any queued %GST_MESSAGE_EOS items are removed since they will be reposted + * when going back to the PLAYING state. The EOS messages are queued in + * #GstBin containers. * * - * Live sources stop generating data and return NO_PREROLL. + * Live sources stop generating data and return %GST_STATE_CHANGE_NO_PREROLL. * * * @GST_STATE_CHANGE_PAUSED_TO_READY : state change from PAUSED to READY. @@ -274,7 +275,7 @@ typedef enum { * Elements unblock any waits on devices * * - * Chain or get_range functions return WRONG_STATE. + * Chain or get_range functions return %GST_FLOW_WRONG_STATE. * * * The element pads are deactivated so that streaming becomes impossible and @@ -602,6 +603,7 @@ struct _GstElement * @get_query_types: get the supported #GstQueryType of this element * @query: perform a #GstQuery on the element * @request_new_pad_full: called when a new pad is requested. Since: 0.10.32. + * @state_changed: called immediately after a new state was set. Since: 0.10.35. * * GStreamer element class. Override the vmethods to implement the element * functionality. @@ -669,8 +671,11 @@ struct _GstElementClass GstPad* (*request_new_pad_full) (GstElement *element, GstPadTemplate *templ, const gchar* name, const GstCaps *caps); + void (*state_changed) (GstElement *element, GstState oldstate, + GstState newstate, GstState pending); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING-2]; + gpointer _gst_reserved[GST_PADDING-3]; }; /* element class pad templates */ diff --git a/gst/gstghostpad.c b/gst/gstghostpad.c index 313759d5a..4a024a26e 100644 --- a/gst/gstghostpad.c +++ b/gst/gstghostpad.c @@ -73,7 +73,6 @@ struct _GstProxyPadPrivate G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD); static GstPad *gst_proxy_pad_get_target (GstPad * pad); -static GstPad *gst_proxy_pad_get_internal (GstPad * pad); static void gst_proxy_pad_dispose (GObject * object); static void gst_proxy_pad_finalize (GObject * object); @@ -91,12 +90,26 @@ static void on_src_target_notify (GstPad * target, static GParamSpec *pspec_caps = NULL; -static const GstQueryType * -gst_proxy_pad_do_query_type (GstPad * pad) +/** + * gst_proxy_pad_query_type_default: + * @pad: a #GstPad. + * + * Invoke the default query type handler of the proxy pad. + * + * Returns: (transfer none) (array zero-terminated=1): a zero-terminated array + * of #GstQueryType. + * + * Since: 0.10.35 + */ +const GstQueryType * +gst_proxy_pad_query_type_default (GstPad * pad) { - GstPad *target = gst_proxy_pad_get_target (pad); + GstPad *target; const GstQueryType *res = NULL; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL); + + target = gst_proxy_pad_get_target (pad); if (target) { res = gst_pad_get_query_types (target); gst_object_unref (target); @@ -104,12 +117,28 @@ gst_proxy_pad_do_query_type (GstPad * pad) return res; } -static gboolean -gst_proxy_pad_do_event (GstPad * pad, GstEvent * event) +/** + * gst_proxy_pad_event_default: + * @pad: a #GstPad to push the event to. + * @event: (transfer full): the #GstEvent to send to the pad. + * + * Invoke the default event of the proxy pad. + * + * Returns: TRUE if the event was handled. + * + * Since: 0.10.35 + */ +gboolean +gst_proxy_pad_event_default (GstPad * pad, GstEvent * event) { gboolean res = FALSE; - GstPad *internal = gst_proxy_pad_get_internal (pad); + GstPad *internal; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); + g_return_val_if_fail (GST_IS_EVENT (event), FALSE); + + internal = + GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD_CAST (pad))); if (internal) { res = gst_pad_push_event (internal, event); gst_object_unref (internal); @@ -118,12 +147,27 @@ gst_proxy_pad_do_event (GstPad * pad, GstEvent * event) return res; } -static gboolean -gst_proxy_pad_do_query (GstPad * pad, GstQuery * query) +/** + * gst_proxy_pad_query_default: + * @pad: a #GstPad to invoke the default query on. + * @query: (transfer none): the #GstQuery to perform. + * + * Invoke the default query function of the proxy pad. + * + * Returns: TRUE if the query could be performed. + * + * Since: 0.10.35 + */ +gboolean +gst_proxy_pad_query_default (GstPad * pad, GstQuery * query) { gboolean res = FALSE; - GstPad *target = gst_proxy_pad_get_target (pad); + GstPad *target; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); + g_return_val_if_fail (GST_IS_QUERY (query), FALSE); + + target = gst_proxy_pad_get_target (pad); if (target) { res = gst_pad_query (target, query); gst_object_unref (target); @@ -132,28 +176,69 @@ gst_proxy_pad_do_query (GstPad * pad, GstQuery * query) return res; } -static GstIterator * -gst_proxy_pad_do_iterate_internal_links (GstPad * pad) +/** + * gst_proyx_pad_iterate_internal_links_default: + * @pad: the #GstPad to get the internal links of. + * + * Invoke the default iterate internal links function of the proxy pad. + * + * Returns: a #GstIterator of #GstPad, or NULL if @pad has no parent. Unref each + * returned pad with gst_object_unref(). + * + * Since: 0.10.35 + */ +GstIterator * +gst_proxy_pad_iterate_internal_links_default (GstPad * pad) { GstIterator *res = NULL; - GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); + GstPad *internal; + + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL); + + internal = + GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD_CAST (pad))); if (internal) { res = gst_iterator_new_single (GST_TYPE_PAD, internal, (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref); + gst_object_unref (internal); } return res; } -static GstFlowReturn -gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size, +/** + * gst_proxy_pad_bufferalloc_default: + * @pad: a source #GstPad + * @offset: the offset of the new buffer in the stream + * @size: the size of the new buffer + * @caps: the caps of the new buffer + * @buf: a newly allocated buffer + * + * Invoke the default bufferalloc function of the proxy pad. + * + * Returns: a result code indicating success of the operation. Any + * result code other than #GST_FLOW_OK is an error and @buf should + * not be used. + * An error can occur if the pad is not connected or when the downstream + * peer elements cannot provide an acceptable buffer. + * + * Since: 0.10.35 + */ +GstFlowReturn +gst_proxy_pad_bufferalloc_default (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf) { GstFlowReturn result = GST_FLOW_WRONG_STATE; - GstPad *internal = gst_proxy_pad_get_internal (pad); + GstPad *internal; + + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); + g_return_val_if_fail (caps == NULL || GST_IS_CAPS (caps), GST_FLOW_ERROR); + g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); + internal = + GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD_CAST (pad))); if (internal) { result = gst_pad_alloc_buffer (internal, offset, size, caps, buf); gst_object_unref (internal); @@ -162,58 +247,135 @@ gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size, return result; } -static GstFlowReturn -gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer) +/** + * gst_proxy_pad_chain_default: + * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not. + * @buffer: (transfer full): the #GstBuffer to send, return GST_FLOW_ERROR + * if not. + * + * Invoke the default chain function of the proxy pad. + * + * Returns: a #GstFlowReturn from the pad. + * + * Since: 0.10.35 + */ +GstFlowReturn +gst_proxy_pad_chain_default (GstPad * pad, GstBuffer * buffer) { GstFlowReturn res; - GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); + GstPad *internal; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); + g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); + + internal = GST_PROXY_PAD_INTERNAL (pad); res = gst_pad_push (internal, buffer); return res; } -static GstFlowReturn -gst_proxy_pad_do_chain_list (GstPad * pad, GstBufferList * list) +/** + * gst_proxy_pad_chain_list_default: + * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not. + * @list: (transfer full): the #GstBufferList to send, return GST_FLOW_ERROR + * if not. + * + * Invoke the default chain list function of the proxy pad. + * + * Returns: a #GstFlowReturn from the pad. + * + * Since: 0.10.35 + */ +GstFlowReturn +gst_proxy_pad_chain_list_default (GstPad * pad, GstBufferList * list) { GstFlowReturn res; - GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); + GstPad *internal; + + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); + g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR); + internal = GST_PROXY_PAD_INTERNAL (pad); res = gst_pad_push_list (internal, list); return res; } -static GstFlowReturn -gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size, +/** + * gst_proxy_pad_get_range_default: + * @pad: a src #GstPad, returns #GST_FLOW_ERROR if not. + * @offset: The start offset of the buffer + * @size: The length of the buffer + * @buffer: (out callee-allocates): a pointer to hold the #GstBuffer, + * returns #GST_FLOW_ERROR if %NULL. + * + * Invoke the default getrange function of the proxy pad. + * + * Returns: a #GstFlowReturn from the pad. + * + * Since: 0.10.35 + */ +GstFlowReturn +gst_proxy_pad_getrange_default (GstPad * pad, guint64 offset, guint size, GstBuffer ** buffer) { GstFlowReturn res; - GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); + GstPad *internal; + + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR); + g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); + internal = GST_PROXY_PAD_INTERNAL (pad); res = gst_pad_pull_range (internal, offset, size, buffer); return res; } -static gboolean -gst_proxy_pad_do_checkgetrange (GstPad * pad) +/** + * gst_proxy_pad_checkgetrange_default: + * @pad: a src #GstPad, returns #GST_FLOW_ERROR if not. + * + * Invoke the default checkgetrange function of the proxy pad. + * + * Returns: a #gboolean from the pad. + * + * Since: 0.10.35 + */ +gboolean +gst_proxy_pad_checkgetrange_default (GstPad * pad) { gboolean result; - GstPad *internal = GST_PROXY_PAD_INTERNAL (pad); + GstPad *internal; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); + + internal = GST_PROXY_PAD_INTERNAL (pad); result = gst_pad_check_pull_range (internal); return result; } -static GstCaps * -gst_proxy_pad_do_getcaps (GstPad * pad) +/** + * gst_proxy_pad_getcaps_default: + * @pad: a #GstPad to get the capabilities of. + * + * Invoke the default getcaps function of the proxy pad. + * + * Returns: (transfer full): the caps of the pad with incremented ref-count + * + * Since: 0.10.35 + */ +GstCaps * +gst_proxy_pad_getcaps_default (GstPad * pad) { - GstPad *target = gst_proxy_pad_get_target (pad); + GstPad *target; GstCaps *res; - GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad); + GstPadTemplate *templ; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL); + + templ = GST_PAD_PAD_TEMPLATE (pad); + target = gst_proxy_pad_get_target (pad); if (target) { /* if we have a real target, proxy the call */ res = gst_pad_get_caps_reffed (target); @@ -256,12 +418,27 @@ done: return res; } -static gboolean -gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps) +/** + * gst_proxy_pad_acceptcaps_default: + * @pad: a #GstPad to check + * @caps: a #GstCaps to check on the pad + * + * Invoke the default acceptcaps function of the proxy pad. + * + * Returns: TRUE if the pad can accept the caps. + * + * Since: 0.10.35 + */ +gboolean +gst_proxy_pad_acceptcaps_default (GstPad * pad, GstCaps * caps) { - GstPad *target = gst_proxy_pad_get_target (pad); + GstPad *target; gboolean res; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); + g_return_val_if_fail (caps == NULL || GST_IS_CAPS (caps), FALSE); + + target = gst_proxy_pad_get_target (pad); if (target) { res = gst_pad_accept_caps (target, caps); gst_object_unref (target); @@ -274,23 +451,52 @@ gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps) return res; } -static void -gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps) +/** + * gst_proxy_pad_fixatecaps_default: + * @pad: a #GstPad to fixate + * @caps: the #GstCaps to fixate + * + * Invoke the default fixatecaps function of the proxy pad. + * + * Since: 0.10.35 + */ +void +gst_proxy_pad_fixatecaps_default (GstPad * pad, GstCaps * caps) { - GstPad *target = gst_proxy_pad_get_target (pad); + GstPad *target; + + g_return_if_fail (GST_IS_PROXY_PAD (pad)); + g_return_if_fail (GST_IS_CAPS (caps)); + target = gst_proxy_pad_get_target (pad); if (target) { gst_pad_fixate_caps (target, caps); gst_object_unref (target); } } -static gboolean -gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps) +/** + * gst_proxy_pad_setcaps_default: + * @pad: a #GstPad to set the capabilities of. + * @caps: (transfer none): a #GstCaps to set. + * + * Invoke the default setcaps function of the proxy pad. + * + * Returns: TRUE if the caps could be set. FALSE if the caps were not fixed + * or bad parameters were provided to this function. + * + * Since: 0.10.35 + */ +gboolean +gst_proxy_pad_setcaps_default (GstPad * pad, GstCaps * caps) { - GstPad *target = gst_proxy_pad_get_target (pad); + GstPad *target; gboolean res; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); + g_return_val_if_fail (caps == NULL || GST_IS_CAPS (caps), FALSE); + + target = gst_proxy_pad_get_target (pad); if (target) { res = gst_pad_set_caps (target, caps); gst_object_unref (target); @@ -364,22 +570,46 @@ gst_proxy_pad_get_target (GstPad * pad) return target; } -static GstPad * -gst_proxy_pad_get_internal (GstPad * pad) +/** + * gst_proxy_pad_get_internal: + * @pad: the #GstProxyPad + * + * Get the internal pad of @pad. Unref target pad after usage. + * + * The internal pad of a #GstGhostPad is the internally used + * pad of opposite direction, which is used to link to the target. + * + * Returns: (transfer full): the target #GstProxyPad, can be NULL. + * Unref target pad after usage. + * + * Since: 0.10.35 + */ +GstProxyPad * +gst_proxy_pad_get_internal (GstProxyPad * pad) { GstPad *internal; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL); + GST_PROXY_LOCK (pad); internal = GST_PROXY_PAD_INTERNAL (pad); if (internal) gst_object_ref (internal); GST_PROXY_UNLOCK (pad); - return internal; + return GST_PROXY_PAD_CAST (internal); } -static void -gst_proxy_pad_do_unlink (GstPad * pad) +/** + * gst_proxy_pad_unlink_default: + * @pad: a #GstPad to unlink + * + * Invoke the default unlink function of the proxy pad. + * + * Since: 0.10.35 + */ +void +gst_proxy_pad_unlink_default (GstPad * pad) { GstPad *internal; @@ -417,20 +647,20 @@ gst_proxy_pad_class_init (GstProxyPadClass * klass) } #endif /* Register common function pointer descriptions */ - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_query_type); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_event); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_query); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_iterate_internal_links); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_getcaps); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_acceptcaps); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_fixatecaps); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_setcaps); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_unlink); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_bufferalloc); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_chain); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_chain_list); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_getrange); - GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_checkgetrange); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_query_type_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_event_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_query_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_iterate_internal_links_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_getcaps_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_acceptcaps_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_fixatecaps_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_setcaps_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_unlink_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_bufferalloc_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_list_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_getrange_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_checkgetrange_default); } static void @@ -471,17 +701,17 @@ gst_proxy_pad_init (GstProxyPad * ppad) GST_TYPE_PROXY_PAD, GstProxyPadPrivate); GST_PROXY_GET_LOCK (pad) = g_mutex_new (); - gst_pad_set_query_type_function (pad, gst_proxy_pad_do_query_type); - gst_pad_set_event_function (pad, gst_proxy_pad_do_event); - gst_pad_set_query_function (pad, gst_proxy_pad_do_query); + gst_pad_set_query_type_function (pad, gst_proxy_pad_query_type_default); + gst_pad_set_event_function (pad, gst_proxy_pad_event_default); + gst_pad_set_query_function (pad, gst_proxy_pad_query_default); gst_pad_set_iterate_internal_links_function (pad, - gst_proxy_pad_do_iterate_internal_links); + gst_proxy_pad_iterate_internal_links_default); - gst_pad_set_getcaps_function (pad, gst_proxy_pad_do_getcaps); - gst_pad_set_acceptcaps_function (pad, gst_proxy_pad_do_acceptcaps); - gst_pad_set_fixatecaps_function (pad, gst_proxy_pad_do_fixatecaps); - gst_pad_set_setcaps_function (pad, gst_proxy_pad_do_setcaps); - gst_pad_set_unlink_function (pad, gst_proxy_pad_do_unlink); + gst_pad_set_getcaps_function (pad, gst_proxy_pad_getcaps_default); + gst_pad_set_acceptcaps_function (pad, gst_proxy_pad_acceptcaps_default); + gst_pad_set_fixatecaps_function (pad, gst_proxy_pad_fixatecaps_default); + gst_pad_set_setcaps_function (pad, gst_proxy_pad_setcaps_default); + gst_pad_set_unlink_function (pad, gst_proxy_pad_unlink_default); } #if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED) @@ -558,13 +788,26 @@ G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD); static void gst_ghost_pad_dispose (GObject * object); -/* see gstghostpad design docs */ -static gboolean -gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active) +/** + * gst_ghost_pad_internal_activate_push_default: + * @pad: the #GstPad to activate or deactivate. + * @active: whether the pad should be active or not. + * + * Invoke the default activate push function of a proxy pad that is + * owned by a ghost pad. + * + * Returns: %TRUE if the operation was successful. + * + * Since: 0.10.35 + */ +gboolean +gst_ghost_pad_internal_activate_push_default (GstPad * pad, gboolean active) { gboolean ret; GstPad *other; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); + GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok", (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad)); @@ -576,12 +819,26 @@ gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active) return ret; } -static gboolean -gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active) +/** + * gst_ghost_pad_internal_activate_pull_default: + * @pad: the #GstPad to activate or deactivate. + * @active: whether the pad should be active or not. + * + * Invoke the default activate pull function of a proxy pad that is + * owned by a ghost pad. + * + * Returns: %TRUE if the operation was successful. + * + * Since: 0.10.35 + */ +gboolean +gst_ghost_pad_internal_activate_pull_default (GstPad * pad, gboolean active) { gboolean ret; GstPad *other; + g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE); + GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad)); @@ -589,7 +846,7 @@ gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active) /* we are activated in pull mode by our peer element, which is a sinkpad * that wants to operate in pull mode. This activation has to propagate * upstream throught the pipeline. We call the internal activation function, - * which will trigger gst_ghost_pad_do_activate_pull, which propagates even + * which will trigger gst_ghost_pad_activate_pull_default, which propagates even * further upstream */ GST_LOG_OBJECT (pad, "pad is src, activate internal"); other = GST_PROXY_PAD_INTERNAL (pad); @@ -609,12 +866,25 @@ gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active) return ret; } -static gboolean -gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active) +/** + * gst_ghost_pad_activate_push_default: + * @pad: the #GstPad to activate or deactivate. + * @active: whether the pad should be active or not. + * + * Invoke the default activate push function of a ghost pad. + * + * Returns: %TRUE if the operation was successful. + * + * Since: 0.10.35 + */ +gboolean +gst_ghost_pad_activate_push_default (GstPad * pad, gboolean active) { gboolean ret; GstPad *other; + g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE); + GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal", (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad)); @@ -625,12 +895,25 @@ gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active) return ret; } -static gboolean -gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active) +/** + * gst_ghost_pad_activate_pull_default: + * @pad: the #GstPad to activate or deactivate. + * @active: whether the pad should be active or not. + * + * Invoke the default activate pull function of a ghost pad. + * + * Returns: %TRUE if the operation was successful. + * + * Since: 0.10.35 + */ +gboolean +gst_ghost_pad_activate_pull_default (GstPad * pad, gboolean active) { gboolean ret; GstPad *other; + g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE); + GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad)); @@ -656,12 +939,26 @@ gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active) return ret; } -static GstPadLinkReturn -gst_ghost_pad_do_link (GstPad * pad, GstPad * peer) +/** + * gst_ghost_pad_link_default: + * @pad: the #GstPad to link. + * @peer: the #GstPad peer + * + * Invoke the default link function of a ghost pad. + * + * Returns: #GstPadLinkReturn of the operation + * + * Since: 0.10.35 + */ +GstPadLinkReturn +gst_ghost_pad_link_default (GstPad * pad, GstPad * peer) { GstPadLinkReturn ret; GstPad *internal; + g_return_val_if_fail (GST_IS_GHOST_PAD (pad), GST_PAD_LINK_REFUSED); + g_return_val_if_fail (GST_IS_PAD (peer), GST_PAD_LINK_REFUSED); + GST_DEBUG_OBJECT (pad, "linking ghostpad"); internal = GST_PROXY_PAD_INTERNAL (pad); @@ -695,11 +992,21 @@ link_failed: } } -static void -gst_ghost_pad_do_unlink (GstPad * pad) +/** + * gst_ghost_pad_unlink_default: + * @pad: the #GstPad to link. + * + * Invoke the default unlink function of a ghost pad. + * + * Since: 0.10.35 + */ +void +gst_ghost_pad_unlink_default (GstPad * pad) { GstPad *internal; + g_return_if_fail (GST_IS_GHOST_PAD (pad)); + internal = GST_PROXY_PAD_INTERNAL (pad); GST_DEBUG_OBJECT (pad, "unlinking ghostpad"); @@ -792,28 +1099,27 @@ done: gst_caps_unref (caps); } -static gboolean -gst_ghost_pad_do_setcaps (GstPad * pad, GstCaps * caps) +/** + * gst_ghost_pad_setcaps_default: + * @pad: the #GstPad to link. + * @caps: (transfer none): the #GstCaps to set + * + * Invoke the default setcaps function of a ghost pad. + * + * Returns: %TRUE if the operation was successful + * + * Since: 0.10.35 + */ +gboolean +gst_ghost_pad_setcaps_default (GstPad * pad, GstCaps * caps) { + g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE); + g_return_val_if_fail (caps == NULL || GST_IS_CAPS (caps), FALSE); + if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) return TRUE; - return gst_proxy_pad_do_setcaps (pad, caps); -} - -static GstIterator * -gst_ghost_pad_do_iterate_internal_links (GstPad * pad) -{ - GstIterator *res = NULL; - GstPad *internal = GST_PROXY_PAD_INTERNAL (GST_GHOST_PAD_CAST (pad)); - - if (internal) { - res = - gst_iterator_new_single (GST_TYPE_PAD, internal, - (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref); - } - - return res; + return gst_proxy_pad_setcaps_default (pad, caps); } static void @@ -827,10 +1133,10 @@ gst_ghost_pad_class_init (GstGhostPadClass * klass) gobject_class->dispose = gst_ghost_pad_dispose; - GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_setcaps); - GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_activate_pull); - GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_activate_push); - GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_link); + GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_setcaps_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_activate_pull_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_activate_push_default); + GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_link_default); } static void @@ -839,13 +1145,12 @@ gst_ghost_pad_init (GstGhostPad * pad) GST_GHOST_PAD_PRIVATE (pad) = G_TYPE_INSTANCE_GET_PRIVATE (pad, GST_TYPE_GHOST_PAD, GstGhostPadPrivate); - gst_pad_set_setcaps_function (GST_PAD_CAST (pad), gst_ghost_pad_do_setcaps); + gst_pad_set_setcaps_function (GST_PAD_CAST (pad), + gst_ghost_pad_setcaps_default); gst_pad_set_activatepull_function (GST_PAD_CAST (pad), - gst_ghost_pad_do_activate_pull); + gst_ghost_pad_activate_pull_default); gst_pad_set_activatepush_function (GST_PAD_CAST (pad), - gst_ghost_pad_do_activate_push); - gst_pad_set_iterate_internal_links_function (GST_PAD_CAST (pad), - gst_ghost_pad_do_iterate_internal_links); + gst_ghost_pad_activate_push_default); } static void @@ -862,7 +1167,7 @@ gst_ghost_pad_dispose (GObject * object) gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL); /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to - * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */ + * gst_ghost_pad_unlink_default when the ghost pad is in an inconsistent state */ peer = gst_pad_get_peer (pad); if (peer) { if (GST_PAD_IS_SRC (pad)) @@ -926,17 +1231,18 @@ gst_ghost_pad_construct (GstGhostPad * gpad) /* Set directional padfunctions for ghostpad */ if (dir == GST_PAD_SINK) { - gst_pad_set_bufferalloc_function (pad, gst_proxy_pad_do_bufferalloc); - gst_pad_set_chain_function (pad, gst_proxy_pad_do_chain); - gst_pad_set_chain_list_function (pad, gst_proxy_pad_do_chain_list); + gst_pad_set_bufferalloc_function (pad, gst_proxy_pad_bufferalloc_default); + gst_pad_set_chain_function (pad, gst_proxy_pad_chain_default); + gst_pad_set_chain_list_function (pad, gst_proxy_pad_chain_list_default); } else { - gst_pad_set_getrange_function (pad, gst_proxy_pad_do_getrange); - gst_pad_set_checkgetrange_function (pad, gst_proxy_pad_do_checkgetrange); + gst_pad_set_getrange_function (pad, gst_proxy_pad_getrange_default); + gst_pad_set_checkgetrange_function (pad, + gst_proxy_pad_checkgetrange_default); } /* link/unlink functions */ - gst_pad_set_link_function (pad, gst_ghost_pad_do_link); - gst_pad_set_unlink_function (pad, gst_ghost_pad_do_unlink); + gst_pad_set_link_function (pad, gst_ghost_pad_link_default); + gst_pad_set_unlink_function (pad, gst_ghost_pad_unlink_default); /* INTERNAL PAD, it always exists and is child of the ghostpad */ otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC; @@ -955,13 +1261,15 @@ gst_ghost_pad_construct (GstGhostPad * gpad) /* Set directional padfunctions for internal pad */ if (dir == GST_PAD_SRC) { - gst_pad_set_bufferalloc_function (internal, gst_proxy_pad_do_bufferalloc); - gst_pad_set_chain_function (internal, gst_proxy_pad_do_chain); - gst_pad_set_chain_list_function (internal, gst_proxy_pad_do_chain_list); + gst_pad_set_bufferalloc_function (internal, + gst_proxy_pad_bufferalloc_default); + gst_pad_set_chain_function (internal, gst_proxy_pad_chain_default); + gst_pad_set_chain_list_function (internal, + gst_proxy_pad_chain_list_default); } else { - gst_pad_set_getrange_function (internal, gst_proxy_pad_do_getrange); + gst_pad_set_getrange_function (internal, gst_proxy_pad_getrange_default); gst_pad_set_checkgetrange_function (internal, - gst_proxy_pad_do_checkgetrange); + gst_proxy_pad_checkgetrange_default); } GST_PROXY_LOCK (pad); @@ -993,9 +1301,9 @@ gst_ghost_pad_construct (GstGhostPad * gpad) /* special activation functions for the internal pad */ gst_pad_set_activatepull_function (internal, - gst_ghost_pad_internal_do_activate_pull); + gst_ghost_pad_internal_activate_pull_default); gst_pad_set_activatepush_function (internal, - gst_ghost_pad_internal_do_activate_push); + gst_ghost_pad_internal_activate_push_default); GST_PROXY_UNLOCK (pad); diff --git a/gst/gstghostpad.h b/gst/gstghostpad.h index f492a74b5..308ab70cb 100644 --- a/gst/gstghostpad.h +++ b/gst/gstghostpad.h @@ -59,6 +59,23 @@ struct _GstProxyPadClass GType gst_proxy_pad_get_type (void); +GstProxyPad* gst_proxy_pad_get_internal (GstProxyPad *pad); + + +const GstQueryType* gst_proxy_pad_query_type_default (GstPad *pad); +gboolean gst_proxy_pad_event_default (GstPad *pad, GstEvent *event); +gboolean gst_proxy_pad_query_default (GstPad *pad, GstQuery *query); +GstIterator* gst_proxy_pad_iterate_internal_links_default (GstPad *pad); +GstFlowReturn gst_proxy_pad_bufferalloc_default (GstPad *pad, guint64 offset, guint size, GstCaps *caps, GstBuffer **buf); +GstFlowReturn gst_proxy_pad_chain_default (GstPad *pad, GstBuffer *buffer); +GstFlowReturn gst_proxy_pad_chain_list_default (GstPad *pad, GstBufferList *list); +GstFlowReturn gst_proxy_pad_getrange_default (GstPad *pad, guint64 offset, guint size, GstBuffer **buffer); +gboolean gst_proxy_pad_checkgetrange_default (GstPad *pad); +GstCaps* gst_proxy_pad_getcaps_default (GstPad *pad); +gboolean gst_proxy_pad_acceptcaps_default (GstPad *pad, GstCaps *caps); +void gst_proxy_pad_fixatecaps_default (GstPad *pad, GstCaps *caps); +gboolean gst_proxy_pad_setcaps_default (GstPad *pad, GstCaps *caps); +void gst_proxy_pad_unlink_default (GstPad * pad); #define GST_TYPE_GHOST_PAD (gst_ghost_pad_get_type ()) #define GST_IS_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GHOST_PAD)) @@ -106,6 +123,15 @@ gboolean gst_ghost_pad_set_target (GstGhostPad *gpad, GstPad *newtarget); gboolean gst_ghost_pad_construct (GstGhostPad *gpad); +gboolean gst_ghost_pad_setcaps_default (GstPad * pad, GstCaps * caps); +void gst_ghost_pad_unlink_default (GstPad * pad); +GstPadLinkReturn gst_ghost_pad_link_default (GstPad * pad, GstPad * peer); +gboolean gst_ghost_pad_activate_pull_default (GstPad * pad, gboolean active); +gboolean gst_ghost_pad_activate_push_default (GstPad * pad, gboolean active); + +gboolean gst_ghost_pad_internal_activate_push_default (GstPad * pad, gboolean active); +gboolean gst_ghost_pad_internal_activate_pull_default (GstPad * pad, gboolean active); + G_END_DECLS #endif /* __GST_GHOST_PAD_H__ */ diff --git a/gst/gstmessage.h b/gst/gstmessage.h index 0eafac52d..757b1d5be 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -74,11 +74,11 @@ typedef struct _GstMessageClass GstMessageClass; * @GST_MESSAGE_SEGMENT_START posted a GST_MESSAGE_SEGMENT_DONE message. * @GST_MESSAGE_DURATION: The duration of a pipeline changed. The application * can get the new duration with a duration query. - * @GST_MESSAGE_ASYNC_START: Posted by elements when they start an ASYNC state - * change. This message is not forwarded to the application but is used + * @GST_MESSAGE_ASYNC_START: Posted by elements when they start an ASYNC + * #GstStateChange. This message is not forwarded to the application but is used * internally. Since: 0.10.13. - * @GST_MESSAGE_ASYNC_DONE: Posted by elements when they complete an ASYNC state - * change. The application will only receive this message from the toplevel + * @GST_MESSAGE_ASYNC_DONE: Posted by elements when they complete an ASYNC + * #GstStateChange. The application will only receive this message from the toplevel * pipeline. Since: 0.10.13 * @GST_MESSAGE_LATENCY: Posted by elements when their latency changes. The * application should recalculate and distribute a new latency. Since: 0.10.12 diff --git a/gst/gstminiobject.c b/gst/gstminiobject.c index 4b46d2929..3993e02a7 100644 --- a/gst/gstminiobject.c +++ b/gst/gstminiobject.c @@ -46,6 +46,24 @@ static GstAllocTrace *_gst_mini_object_trace; #define GST_MINI_OBJECT_GET_CLASS_UNCHECKED(obj) \ ((GstMiniObjectClass *) (((GTypeInstance*)(obj))->g_class)) +/* Structure used for storing weak references */ +typedef struct +{ + GstMiniObject *object; + guint n_weak_refs; + struct + { + GstMiniObjectWeakNotify notify; + gpointer data; + } weak_refs[1]; /* flexible array */ +} WeakRefStack; + +/* Structure for storing a mini object's private data */ +struct _GstMiniObjectPrivate +{ + WeakRefStack *wstack; +}; + #if 0 static void gst_mini_object_base_init (gpointer g_class); static void gst_mini_object_base_finalize (gpointer g_class); @@ -55,6 +73,7 @@ static void gst_mini_object_init (GTypeInstance * instance, gpointer klass); static void gst_value_mini_object_init (GValue * value); static void gst_value_mini_object_free (GValue * value); +static void weak_refs_notify (WeakRefStack * data); static void gst_value_mini_object_copy (const GValue * src_value, GValue * dest_value); static gpointer gst_value_mini_object_peek_pointer (const GValue * value); @@ -66,6 +85,9 @@ static gchar *gst_value_mini_object_lcopy (const GValue * value, static GstMiniObject *gst_mini_object_copy_default (const GstMiniObject * obj); static void gst_mini_object_finalize (GstMiniObject * obj); +/* Mutex used for weak referencing */ +G_LOCK_DEFINE_STATIC (weak_refs_mutex); + GType gst_mini_object_get_type (void) { @@ -138,6 +160,9 @@ gst_mini_object_class_init (gpointer g_class, gpointer class_data) mo_class->copy = gst_mini_object_copy_default; mo_class->finalize = gst_mini_object_finalize; + + /* Set the instance data type */ + g_type_class_add_private (g_class, sizeof (GstMiniObjectPrivate)); } static void @@ -146,6 +171,9 @@ gst_mini_object_init (GTypeInstance * instance, gpointer klass) GstMiniObject *mini_object = GST_MINI_OBJECT_CAST (instance); mini_object->refcount = 1; + + /* we delay initialising the mini object's private data until it's actually + * needed for now (mini_object->priv automatically inited to NULL) */ } static GstMiniObject * @@ -320,6 +348,16 @@ gst_mini_object_ref (GstMiniObject * mini_object) return mini_object; } +static void +weak_refs_notify (WeakRefStack * wstack) +{ + guint i; + + for (i = 0; i < wstack->n_weak_refs; i++) + wstack->weak_refs[i].notify (wstack->weak_refs[i].data, wstack->object); + g_free (wstack); +} + static void gst_mini_object_free (GstMiniObject * mini_object) { @@ -340,6 +378,10 @@ gst_mini_object_free (GstMiniObject * mini_object) /* decrement the refcount again, if the subclass recycled the object we don't * want to free the instance anymore */ if (G_LIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) { + /* The weak reference stack is freed in the notification function */ + if (mini_object->priv != NULL && mini_object->priv->wstack != NULL) + weak_refs_notify (mini_object->priv->wstack); + #ifndef GST_DISABLE_TRACE gst_alloc_trace_free (_gst_mini_object_trace, mini_object); #endif @@ -370,6 +412,109 @@ gst_mini_object_unref (GstMiniObject * mini_object) } } +/** + * gst_mini_object_weak_ref: (skip) + * @object: #GstMiniObject to reference weakly + * @notify: callback to invoke before the mini object is freed + * @data: extra data to pass to notify + * + * Adds a weak reference callback to a mini object. Weak references are + * used for notification when a mini object is finalized. They are called + * "weak references" because they allow you to safely hold a pointer + * to the mini object without calling gst_mini_object_ref() + * (gst_mini_object_ref() adds a strong reference, that is, forces the object + * to stay alive). + * + * Since: 0.10.35 + */ +void +gst_mini_object_weak_ref (GstMiniObject * object, + GstMiniObjectWeakNotify notify, gpointer data) +{ + guint i; + + g_return_if_fail (GST_IS_MINI_OBJECT (object)); + g_return_if_fail (notify != NULL); + g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1); + + G_LOCK (weak_refs_mutex); + + if (object->priv == NULL) { + object->priv = G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_MINI_OBJECT, + GstMiniObjectPrivate); + + /* object->priv->wstack will have been inited to NULL automatically */ + } + + if (object->priv->wstack) { + /* Don't add the weak reference if it already exists. */ + for (i = 0; i < object->priv->wstack->n_weak_refs; i++) { + if (object->priv->wstack->weak_refs[i].notify == notify && + object->priv->wstack->weak_refs[i].data == data) { + g_warning ("%s: Attempt to re-add existing weak ref %p(%p) failed.", + G_STRFUNC, notify, data); + goto found; + } + } + + i = object->priv->wstack->n_weak_refs++; + object->priv->wstack = + g_realloc (object->priv->wstack, sizeof (*(object->priv->wstack)) + + sizeof (object->priv->wstack->weak_refs[0]) * i); + } else { + object->priv->wstack = g_renew (WeakRefStack, NULL, 1); + object->priv->wstack->object = object; + object->priv->wstack->n_weak_refs = 1; + i = 0; + } + object->priv->wstack->weak_refs[i].notify = notify; + object->priv->wstack->weak_refs[i].data = data; +found: + G_UNLOCK (weak_refs_mutex); +} + +/** + * gst_mini_object_weak_unref: (skip) + * @object: #GstMiniObject to remove a weak reference from + * @notify: callback to search for + * @data: data to search for + * + * Removes a weak reference callback to a mini object. + * + * Since: 0.10.35 + */ +void +gst_mini_object_weak_unref (GstMiniObject * object, + GstMiniObjectWeakNotify notify, gpointer data) +{ + gboolean found_one = FALSE; + + g_return_if_fail (GST_IS_MINI_OBJECT (object)); + g_return_if_fail (notify != NULL); + + G_LOCK (weak_refs_mutex); + + if (object->priv != NULL && object->priv->wstack != NULL) { + guint i; + + for (i = 0; i < object->priv->wstack->n_weak_refs; i++) + if (object->priv->wstack->weak_refs[i].notify == notify && + object->priv->wstack->weak_refs[i].data == data) { + found_one = TRUE; + object->priv->wstack->n_weak_refs -= 1; + if (i != object->priv->wstack->n_weak_refs) + object->priv->wstack->weak_refs[i] = + object->priv->wstack->weak_refs[object->priv->wstack-> + n_weak_refs]; + + break; + } + } + G_UNLOCK (weak_refs_mutex); + if (!found_one) + g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data); +} + /** * gst_mini_object_replace: * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to @@ -427,8 +572,8 @@ gst_value_mini_object_copy (const GValue * src_value, GValue * dest_value) { if (src_value->data[0].v_pointer) { dest_value->data[0].v_pointer = - gst_mini_object_ref (GST_MINI_OBJECT_CAST (src_value-> - data[0].v_pointer)); + gst_mini_object_ref (GST_MINI_OBJECT_CAST (src_value->data[0]. + v_pointer)); } else { dest_value->data[0].v_pointer = NULL; } @@ -556,8 +701,8 @@ gst_value_dup_mini_object (const GValue * value) { g_return_val_if_fail (GST_VALUE_HOLDS_MINI_OBJECT (value), NULL); - return value->data[0].v_pointer ? gst_mini_object_ref (value->data[0]. - v_pointer) : NULL; + return value->data[0].v_pointer ? gst_mini_object_ref (value-> + data[0].v_pointer) : NULL; } diff --git a/gst/gstminiobject.h b/gst/gstminiobject.h index 1005dc544..024d1e211 100644 --- a/gst/gstminiobject.h +++ b/gst/gstminiobject.h @@ -135,6 +135,25 @@ typedef enum */ #define GST_MINI_OBJECT_REFCOUNT_VALUE(obj) (g_atomic_int_get (&(GST_MINI_OBJECT_CAST(obj))->refcount)) +/** + * GstMiniObjectWeakNotify: + * @data: data that was provided when the weak reference was established + * @where_the_mini_object_was: the mini object being finalized + * + * A #GstMiniObjectWeakNotify function can be added to a mini object as a + * callback that gets triggered when the mini object is finalized. Since the + * mini object is already being finalized when the #GstMiniObjectWeakNotify is + * called, there's not much you could do with the object, apart from e.g. using + * its adress as hash-index or the like. + * + * Since: 0.10.35 + * + */ +typedef void (*GstMiniObjectWeakNotify) (gpointer data, + GstMiniObject * where_the_mini_object_was); + +typedef struct _GstMiniObjectPrivate GstMiniObjectPrivate; + /** * GstMiniObject: * @instance: type instance @@ -154,7 +173,7 @@ struct _GstMiniObject { guint flags; /*< private >*/ - gpointer _gst_reserved; + GstMiniObjectPrivate *priv; }; struct _GstMiniObjectClass { @@ -177,6 +196,12 @@ GstMiniObject* gst_mini_object_make_writable (GstMiniObject *mini_object); /* refcounting */ GstMiniObject* gst_mini_object_ref (GstMiniObject *mini_object); void gst_mini_object_unref (GstMiniObject *mini_object); +void gst_mini_object_weak_ref (GstMiniObject *object, + GstMiniObjectWeakNotify notify, + gpointer data); +void gst_mini_object_weak_unref (GstMiniObject *object, + GstMiniObjectWeakNotify notify, + gpointer data); void gst_mini_object_replace (GstMiniObject **olddata, GstMiniObject *newdata); /* GParamSpec */ diff --git a/gst/gstpad.c b/gst/gstpad.c index c18448540..14c97863e 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -1132,7 +1132,7 @@ had_right_state: * take an indeterminate amount of time. * You can pass NULL as the callback to make this call block. Be careful with * this blocking call as it might not return for reasons stated above. - * + * * * Pad block handlers are only called for source pads in push mode * and sink pads in pull mode. @@ -2022,7 +2022,7 @@ no_format: * @sinkpad: the sink #GstPad. * * Checks if the source pad and the sink pad are compatible so they can be - * linked. + * linked. * * Returns: TRUE if the pads can be linked. */ @@ -3287,7 +3287,7 @@ gst_pad_iterate_internal_links_default (GstPad * pad) * two concurrent iterators were used and the last iterator would still be * thread-unsafe. Just don't use this method anymore. */ data = g_slice_new (IntLinkIterData); - data->list = GST_PAD_INTLINKFUNC (pad) (pad); + data->list = ((GstPadIntLinkFunction) GST_PAD_INTLINKFUNC (pad)) (pad); data->cookie = 0; GST_WARNING_OBJECT (pad, "Making unsafe iterator"); @@ -3398,7 +3398,7 @@ add_unref_pad_to_list (GstPad * pad, GList ** list) * Deprecated: This function does not ref the pads in the list so that they * could become invalid by the time the application accesses them. It's also * possible that the list changes while handling the pads, which the caller of - * this function is unable to know. Use the thread-safe + * this function is unable to know. Use the thread-safe * gst_pad_iterate_internal_links_default() instead. */ #ifndef GST_REMOVE_DEPRECATED @@ -3490,11 +3490,11 @@ no_parent: * * Returns: (transfer full) (element-type Gst.Pad): a newly allocated #GList * of pads, free with g_list_free(). - * + * * Deprecated: This function does not ref the pads in the list so that they * could become invalid by the time the application accesses them. It's also * possible that the list changes while handling the pads, which the caller of - * this function is unable to know. Use the thread-safe + * this function is unable to know. Use the thread-safe * gst_pad_iterate_internal_links() instead. */ #ifndef GST_REMOVE_DEPRECATED @@ -3511,7 +3511,7 @@ gst_pad_get_internal_links (GstPad * pad) GST_WARNING_OBJECT (pad, "Calling unsafe internal links"); if (GST_PAD_INTLINKFUNC (pad)) - res = GST_PAD_INTLINKFUNC (pad) (pad); + res = ((GstPadIntLinkFunction) GST_PAD_INTLINKFUNC (pad)) (pad); return res; } @@ -3570,8 +3570,9 @@ gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event) gst_object_unref (item); break; case GST_ITERATOR_RESYNC: - /* FIXME, if we want to reset the result value we need to remember which - * pads pushed with which result */ + /* We don't reset the result here because we don't push the event + * again on pads that got the event already and because we need + * to consider the result of the previous pushes */ gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: diff --git a/gst/gstpad.h b/gst/gstpad.h index 19834c41d..5317dee41 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -192,7 +192,7 @@ GQuark gst_flow_to_quark (GstFlowReturn ret); * @GST_PAD_LINK_CHECK_NOTHING: Don't check hierarchy or caps compatibility. * @GST_PAD_LINK_CHECK_HIERARCHY: Check the pads have same parents/grandparents. * Could be omitted if it is already known that the two elements that own the - * pads are in the same bin. + * pads are in the same bin. * @GST_PAD_LINK_CHECK_TEMPLATE_CAPS: Check if the pads are compatible by using * their template caps. This is much faster than @GST_PAD_LINK_CHECK_CAPS, but * would be unsafe e.g. if one pad has %GST_CAPS_ANY. @@ -223,7 +223,7 @@ typedef enum { /** * GST_PAD_LINK_CHECK_DEFAULT: * - * The default checks done when linking pads (i.e. the ones used by + * The default checks done when linking pads (i.e. the ones used by * gst_pad_link()). * * Since: 0.10.30 @@ -405,7 +405,10 @@ typedef gboolean (*GstPadCheckGetRangeFunction) (GstPad *pad); * * Deprecated: use the threadsafe #GstPadIterIntLinkFunction instead. */ +#ifndef GST_DISABLE_DEPRECATED typedef GList* (*GstPadIntLinkFunction) (GstPad *pad); +#endif + /** * GstPadIterIntLinkFunction: @@ -708,7 +711,13 @@ struct _GstPad { GstPadQueryFunction queryfunc; /* internal links */ +#ifndef GST_DISABLE_DEPRECATED GstPadIntLinkFunction intlinkfunc; +#else +#ifndef __GTK_DOC_IGNORE__ + gpointer intlinkfunc; +#endif +#endif GstPadBufferAllocFunction bufferallocfunc; diff --git a/gst/gstpluginfeature.c b/gst/gstpluginfeature.c index 3c62b1b08..c72a1f778 100644 --- a/gst/gstpluginfeature.c +++ b/gst/gstpluginfeature.c @@ -65,7 +65,6 @@ gst_plugin_feature_finalize (GObject * object) GST_DEBUG ("finalizing feature %p: '%s'", feature, GST_PLUGIN_FEATURE_NAME (feature)); - g_free (feature->name); if (feature->plugin != NULL) { g_object_remove_weak_pointer ((GObject *) feature->plugin, @@ -85,7 +84,7 @@ gst_plugin_feature_finalize (GObject * object) * Normally this function is used like this: * |[ * GstPluginFeature *loaded_feature; - * + * * loaded_feature = gst_plugin_feature_load (feature); * // presumably, we're no longer interested in the potentially-unloaded feature * gst_object_unref (feature); @@ -184,12 +183,12 @@ gst_plugin_feature_set_name (GstPluginFeature * feature, const gchar * name) g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature)); g_return_if_fail (name != NULL); - if (feature->name) { + if (G_UNLIKELY (feature->name)) { g_return_if_fail (strcmp (feature->name, name) == 0); } else { - feature->name = g_strdup (name); + gst_object_set_name (GST_OBJECT (feature), name); + feature->name = GST_OBJECT_NAME (GST_OBJECT (feature)); } - gst_object_set_name (GST_OBJECT_CAST (feature), feature->name); } /** diff --git a/gst/gstpluginfeature.h b/gst/gstpluginfeature.h index 177c8bd3a..baf592c8a 100644 --- a/gst/gstpluginfeature.h +++ b/gst/gstpluginfeature.h @@ -81,7 +81,7 @@ struct _GstPluginFeature { /*< private >*/ gboolean loaded; - gchar *name; + gchar *name; /* FIXME-0.11: remove variable, we use GstObject:name */ guint rank; const gchar *plugin_name; diff --git a/gst/gstpreset.c b/gst/gstpreset.c index d56606573..811e4d186 100644 --- a/gst/gstpreset.c +++ b/gst/gstpreset.c @@ -86,6 +86,8 @@ #include "gst_private.h" #include "gstpreset.h" +#include "gstinfo.h" +#include "gstvalue.h" #ifdef HAVE_UNISTD_H #include @@ -253,12 +255,13 @@ wrong_name: static guint64 preset_parse_version (const gchar * str_version) { - gint major, minor, micro, nano, num; + guint major, minor, micro, nano; + gint num; major = minor = micro = nano = 0; /* parse version (e.g. 0.10.15.1) to guint64 */ - num = sscanf (str_version, "%d.%d.%d.%d", &major, &minor, µ, &nano); + num = sscanf (str_version, "%u.%u.%u.%u", &major, &minor, µ, &nano); /* make sure we have atleast "major.minor" */ if (num > 1) { guint64 version; diff --git a/gst/gstpreset.h b/gst/gstpreset.h index 73816326b..ccf1366f6 100644 --- a/gst/gstpreset.h +++ b/gst/gstpreset.h @@ -23,7 +23,6 @@ #define __GST_PRESET_H__ #include -#include G_BEGIN_DECLS diff --git a/gst/gstregistry.c b/gst/gstregistry.c index 5b6df92f3..0955ae162 100644 --- a/gst/gstregistry.c +++ b/gst/gstregistry.c @@ -46,7 +46,7 @@ * means of doing so is to load every plugin and look at the resulting * information that is gathered in the default registry. Clearly, this is a time * consuming process, so we cache information in the registry file. The format - * and location of the cache file is internal to gstreamer. + * and location of the cache file is internal to gstreamer. * * On startup, plugins are searched for in the plugin search path. The following * locations are checked in this order: @@ -280,7 +280,7 @@ gst_registry_finalize (GObject * object) if (feature) { GST_LOG_OBJECT (registry, "removing feature %p (%s)", feature, gst_plugin_feature_get_name (feature)); - gst_object_unref (feature); + gst_object_unparent (GST_OBJECT_CAST (feature)); } f = g_list_next (f); } @@ -485,7 +485,7 @@ gst_registry_remove_features_for_plugin_unlocked (GstRegistry * registry, registry->features = g_list_delete_link (registry->features, f); g_hash_table_remove (registry->feature_hash, feature->name); - gst_object_unref (feature); + gst_object_unparent (GST_OBJECT_CAST (feature)); } f = next; } @@ -561,10 +561,10 @@ gst_registry_add_feature (GstRegistry * registry, GstPluginFeature * feature) if (G_UNLIKELY (existing_feature)) { /* We unref now. No need to remove the feature name from the hash table, it * got replaced by the new feature */ - gst_object_unref (existing_feature); + gst_object_unparent (GST_OBJECT_CAST (existing_feature)); } - gst_object_ref_sink (feature); + gst_object_set_parent (GST_OBJECT_CAST (feature), GST_OBJECT_CAST (registry)); registry->priv->cookie++; GST_OBJECT_UNLOCK (registry); @@ -598,7 +598,8 @@ gst_registry_remove_feature (GstRegistry * registry, GstPluginFeature * feature) g_hash_table_remove (registry->feature_hash, feature->name); registry->priv->cookie++; GST_OBJECT_UNLOCK (registry); - gst_object_unref (feature); + + gst_object_unparent ((GstObject *) feature); } /** diff --git a/gst/gstregistrybinary.h b/gst/gstregistrybinary.h index a367f4100..aa2c6d31f 100644 --- a/gst/gstregistrybinary.h +++ b/gst/gstregistrybinary.h @@ -55,12 +55,12 @@ G_BEGIN_DECLS * This _must_ be updated whenever the registry format changes, * we currently use the core version where this change happened. */ -#define GST_MAGIC_BINARY_VERSION_STR ("0.10.30.1") +#define GST_MAGIC_BINARY_VERSION_STR "0.10.30.1" /* * GST_MAGIC_BINARY_VERSION_LEN: * - * length of the version string. + * Maximum length of the version string in the header. */ #define GST_MAGIC_BINARY_VERSION_LEN (64) diff --git a/gst/gstregistrychunks.c b/gst/gstregistrychunks.c index d30d4004b..684a18153 100644 --- a/gst/gstregistrychunks.c +++ b/gst/gstregistrychunks.c @@ -532,8 +532,9 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in, GstRegistryChunkPluginFeature *pf = NULL; GstPluginFeature *feature = NULL; const gchar *const_str, *type_name; + const gchar *feature_name; const gchar *plugin_name; - gchar *str, *feature_name; + gchar *str; GType type; guint i; @@ -548,7 +549,7 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in, } /* unpack more plugin feature strings */ - unpack_string (*in, feature_name, end, fail); + unpack_string_nocopy (*in, feature_name, end, fail); GST_DEBUG ("Plugin '%s' feature '%s' typename : '%s'", plugin_name, feature_name, type_name); @@ -556,16 +557,13 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in, if (G_UNLIKELY (!(type = g_type_from_name (type_name)))) { GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name, plugin_name); - g_free (feature_name); return FALSE; } if (G_UNLIKELY ((feature = g_object_newv (type, 0, NULL)) == NULL)) { GST_ERROR ("Can't create feature from type"); - g_free (feature_name); return FALSE; } - - feature->name = feature_name; + gst_plugin_feature_set_name (feature, feature_name); if (G_UNLIKELY (!GST_IS_PLUGIN_FEATURE (feature))) { GST_ERROR ("typename : '%s' is not a plugin feature", type_name); diff --git a/gst/gststructure.c b/gst/gststructure.c index f0ff914fe..3b2c2e412 100644 --- a/gst/gststructure.c +++ b/gst/gststructure.c @@ -565,12 +565,7 @@ gst_structure_set_valist_internal (GstStructure * structure, g_warning ("Don't use G_TYPE_DATE, use GST_TYPE_DATE instead\n"); type = GST_TYPE_DATE; } -#if GLIB_CHECK_VERSION(2,23,3) G_VALUE_COLLECT_INIT (&field.value, type, varargs, 0, &err); -#else - g_value_init (&field.value, type); - G_VALUE_COLLECT (&field.value, varargs, 0, &err); -#endif if (G_UNLIKELY (err)) { g_critical ("%s", err); return; @@ -2916,3 +2911,262 @@ gst_structure_id_get (const GstStructure * structure, GQuark first_field_id, return ret; } + +static gboolean +gst_structure_is_equal_foreach (GQuark field_id, const GValue * val2, + gpointer data) +{ + const GstStructure *struct1 = (const GstStructure *) data; + const GValue *val1 = gst_structure_id_get_value (struct1, field_id); + + if (G_UNLIKELY (val1 == NULL)) + return FALSE; + if (gst_value_compare (val1, val2) == GST_VALUE_EQUAL) { + return TRUE; + } + + return FALSE; +} + +/** + * gst_structure_is_equal: + * @structure1: a #GstStructure. + * @structure2: a #GstStructure. + * + * Tests if the two #GstStructure are equal. + * + * Returns: TRUE if the two structures have the same name and field. + * + * Since: 0.10.35 + **/ +gboolean +gst_structure_is_equal (const GstStructure * structure1, + const GstStructure * structure2) +{ + g_return_val_if_fail (GST_IS_STRUCTURE (structure1), FALSE); + g_return_val_if_fail (GST_IS_STRUCTURE (structure2), FALSE); + + if (structure1->name != structure2->name) { + return FALSE; + } + if (structure1->fields->len != structure2->fields->len) { + return FALSE; + } + + return gst_structure_foreach (structure1, gst_structure_is_equal_foreach, + (gpointer) structure2); +} + + +typedef struct +{ + GstStructure *dest; + const GstStructure *intersect; +} +IntersectData; + +static gboolean +gst_structure_intersect_field1 (GQuark id, const GValue * val1, gpointer data) +{ + IntersectData *idata = (IntersectData *) data; + const GValue *val2 = gst_structure_id_get_value (idata->intersect, id); + + if (G_UNLIKELY (val2 == NULL)) { + gst_structure_id_set_value (idata->dest, id, val1); + } else { + GValue dest_value = { 0 }; + if (gst_value_intersect (&dest_value, val1, val2)) { + gst_structure_id_set_value (idata->dest, id, &dest_value); + g_value_unset (&dest_value); + } else { + return FALSE; + } + } + return TRUE; +} + +static gboolean +gst_structure_intersect_field2 (GQuark id, const GValue * val1, gpointer data) +{ + IntersectData *idata = (IntersectData *) data; + const GValue *val2 = gst_structure_id_get_value (idata->intersect, id); + + if (G_UNLIKELY (val2 == NULL)) { + gst_structure_id_set_value (idata->dest, id, val1); + } + return TRUE; +} + +/** + * gst_structure_intersect: + * @struct1: a #GstStructure + * @struct2: a #GstStructure + * + * Interesects @struct1 and @struct2 and returns the intersection. + * + * Returns: Intersection of @struct1 and @struct2 + * + * Since: 0.10.35 + */ +GstStructure * +gst_structure_intersect (const GstStructure * struct1, + const GstStructure * struct2) +{ + IntersectData data; + + g_assert (struct1 != NULL); + g_assert (struct2 != NULL); + + if (G_UNLIKELY (struct1->name != struct2->name)) + return NULL; + + /* copy fields from struct1 which we have not in struct2 to target + * intersect if we have the field in both */ + data.dest = gst_structure_id_empty_new (struct1->name); + data.intersect = struct2; + if (G_UNLIKELY (!gst_structure_foreach ((GstStructure *) struct1, + gst_structure_intersect_field1, &data))) + goto error; + + /* copy fields from struct2 which we have not in struct1 to target */ + data.intersect = struct1; + if (G_UNLIKELY (!gst_structure_foreach ((GstStructure *) struct2, + gst_structure_intersect_field2, &data))) + goto error; + + return data.dest; + +error: + gst_structure_free (data.dest); + return NULL; +} + +static gboolean +gst_caps_structure_can_intersect_field (GQuark id, const GValue * val1, + gpointer data) +{ + GstStructure *other = (GstStructure *) data; + const GValue *val2 = gst_structure_id_get_value (other, id); + + if (G_LIKELY (val2)) { + if (!gst_value_can_intersect (val1, val2)) { + return FALSE; + } else { + gint eq = gst_value_compare (val1, val2); + + if (eq == GST_VALUE_UNORDERED) { + /* we need to try interseting */ + GValue dest_value = { 0 }; + if (gst_value_intersect (&dest_value, val1, val2)) { + g_value_unset (&dest_value); + } else { + return FALSE; + } + } else if (eq != GST_VALUE_EQUAL) { + return FALSE; + } + } + } + return TRUE; +} + +/** + * gst_structure_can_intersect: + * @struct1: a #GstStructure + * @struct2: a #GstStructure + * + * Tries interesecting @struct1 and @struct2 and reports whether the result + * would not be empty. + * + * Returns: %TRUE if intersection would not be empty + * + * Since: 0.10.35 + */ +gboolean +gst_structure_can_intersect (const GstStructure * struct1, + const GstStructure * struct2) +{ + g_return_val_if_fail (GST_IS_STRUCTURE (struct1), FALSE); + g_return_val_if_fail (GST_IS_STRUCTURE (struct2), FALSE); + + if (G_UNLIKELY (struct1->name != struct2->name)) + return FALSE; + + /* tries to intersect if we have the field in both */ + if (G_UNLIKELY (!gst_structure_foreach ((GstStructure *) struct1, + gst_caps_structure_can_intersect_field, (gpointer) struct2))) + return FALSE; + + return TRUE; +} + +static gboolean +gst_caps_structure_is_subset_field (GQuark field_id, const GValue * value, + gpointer user_data) +{ + GstStructure *superset = user_data; + GValue subtraction = { 0, }; + const GValue *other; + + if (!(other = gst_structure_id_get_value (superset, field_id))) + /* field is missing in the superset => is subset */ + return TRUE; + + /* equal values are subset */ + if (gst_value_compare (other, value) == GST_VALUE_EQUAL) + return TRUE; + + /* + * 1 - [1,2] = empty + * -> !subset + * + * [1,2] - 1 = 2 + * -> 1 - [1,2] = empty + * -> subset + * + * [1,3] - [1,2] = 3 + * -> [1,2] - [1,3] = empty + * -> subset + * + * {1,2} - {1,3} = 2 + * -> {1,3} - {1,2} = 3 + * -> !subset + * + * First caps subtraction needs to return a non-empty set, second + * subtractions needs to give en empty set. + */ + if (gst_value_subtract (&subtraction, other, value)) { + g_value_unset (&subtraction); + /* !empty result, swapping must be empty */ + if (!gst_value_subtract (&subtraction, value, other)) + return TRUE; + + g_value_unset (&subtraction); + } + return FALSE; +} + +/** + * gst_structure_is_subset: + * @subset: a #GstStructure + * @superset: a potentially greater #GstStructure + * + * Checks if @subset is a subset of @superset, i.e. has the same + * structure name and for all fields that are existing in @superset, + * @subset has a value that is a subset of the value in @superset. + * + * Returns: %TRUE if @subset is a subset of @superset + * + * Since: 0.10.35 + */ +gboolean +gst_structure_is_subset (const GstStructure * subset, + const GstStructure * superset) +{ + if ((superset->name != subset->name) || + (gst_structure_n_fields (superset) > gst_structure_n_fields (subset))) + return FALSE; + + return gst_structure_foreach ((GstStructure *) subset, + gst_caps_structure_is_subset_field, (gpointer) superset); +} diff --git a/gst/gststructure.h b/gst/gststructure.h index 57e34c0f7..6e020fce3 100644 --- a/gst/gststructure.h +++ b/gst/gststructure.h @@ -248,6 +248,15 @@ gboolean gst_structure_fixate_field_nearest_fraction (GstStructu const gint target_numerator, const gint target_denominator); +gboolean gst_structure_is_equal(const GstStructure *structure1, + const GstStructure *structure2); +gboolean gst_structure_is_subset(const GstStructure *subset, + const GstStructure *superset); +gboolean gst_structure_can_intersect(const GstStructure *struct1, + const GstStructure *struct2); +GstStructure* gst_structure_intersect (const GstStructure *struct1, + const GstStructure *struct2); + G_END_DECLS #endif diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c index 7ada0c952..938704e54 100644 --- a/gst/gstsystemclock.c +++ b/gst/gstsystemclock.c @@ -328,9 +328,16 @@ gst_system_clock_add_wakeup (GstSystemClock * sysclock) if (sysclock->priv->wakeup_count == 0) { GST_CAT_DEBUG (GST_CAT_CLOCK, "writing control"); while (!gst_poll_write_control (sysclock->priv->timer)) { - g_warning - ("gstsystemclock: write control failed in wakeup_async, trying again : %d:%s\n", - errno, g_strerror (errno)); + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + g_warning + ("gstsystemclock: write control failed in wakeup_async, trying again: %d:%s\n", + errno, g_strerror (errno)); + } else { + g_critical + ("gstsystemclock: write control failed in wakeup_async: %d:%s\n", + errno, g_strerror (errno)); + return; + } } } sysclock->priv->wakeup_count++; diff --git a/gst/gsttaglist.c b/gst/gsttaglist.c index 7022b26ab..385e3b019 100644 --- a/gst/gsttaglist.c +++ b/gst/gsttaglist.c @@ -1011,12 +1011,7 @@ gst_tag_list_add_valist (GstTagList * list, GstTagMergeMode mode, g_warning ("unknown tag '%s'", tag); return; } -#if GLIB_CHECK_VERSION(2,23,3) G_VALUE_COLLECT_INIT (&value, info->type, var_args, 0, &error); -#else - g_value_init (&value, info->type); - G_VALUE_COLLECT (&value, var_args, 0, &error); -#endif if (error) { g_warning ("%s: %s", G_STRLOC, error); g_free (error); diff --git a/gst/gstvalue.c b/gst/gstvalue.c index 8baf1e615..381716094 100644 --- a/gst/gstvalue.c +++ b/gst/gstvalue.c @@ -3394,10 +3394,28 @@ gint gst_value_compare (const GValue * value1, const GValue * value2) { GstValueCompareFunc compare; + GType ltype; g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN); g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN); + /* Special case: lists and scalar values + * "{ 1 }" and "1" are equal */ + ltype = gst_value_list_get_type (); + if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype) + && gst_value_list_get_size (value1) == 1) { + const GValue *elt; + + elt = gst_value_list_get_value (value1, 0); + return gst_value_compare (elt, value2); + } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype) + && gst_value_list_get_size (value2) == 1) { + const GValue *elt; + + elt = gst_value_list_get_value (value2, 0); + return gst_value_compare (elt, value1); + } + if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) return GST_VALUE_UNORDERED; diff --git a/gst/parse/Makefile.am b/gst/parse/Makefile.am index 7e834048f..30abeb371 100644 --- a/gst/parse/Makefile.am +++ b/gst/parse/Makefile.am @@ -45,6 +45,8 @@ lex._gst_parse_yy.c: parse.l grammar.tab.h echo '#ifdef HAVE_CONFIG_H' > lex._gst_parse_yy_tmp2.c && \ echo '#include ' >> lex._gst_parse_yy_tmp2.c && \ echo '#endif' >> lex._gst_parse_yy_tmp2.c && \ + echo 'static inline int _gst_parse_yyget_column (void * yyscanner);' >> lex._gst_parse_yy_tmp2.c && \ + echo 'static inline void _gst_parse_yyset_column (int column_no , void * yyscanner);' >> lex._gst_parse_yy_tmp2.c && \ cat lex._gst_parse_yy_tmp.c >> lex._gst_parse_yy_tmp2.c && \ rm lex._gst_parse_yy_tmp.c && \ mv lex._gst_parse_yy_tmp2.c lex._gst_parse_yy.c diff --git a/gst/parse/types.h b/gst/parse/types.h index 7e8b99445..db1f58564 100644 --- a/gst/parse/types.h +++ b/gst/parse/types.h @@ -69,17 +69,24 @@ static inline void gst_parse_unescape (gchar *str) { gchar *walk; + gboolean in_quotes; g_return_if_fail (str != NULL); walk = str; + in_quotes = FALSE; while (*walk) { - if (*walk == '\\') { + if (*walk == '\\' && !in_quotes) { walk++; /* make sure we don't read beyond the end of the string */ if (*walk == '\0') break; + } else if (*walk == '"' && (!in_quotes || (in_quotes + && (*(walk - 1) != '\\')))) { + /* don't unescape inside quotes and don't switch + * state with escaped quoted inside quotes */ + in_quotes = !in_quotes; } *str = *walk; str++; diff --git a/libs/gst/base/gstbaseparse.c b/libs/gst/base/gstbaseparse.c index e80c8f4ba..e0158ce11 100644 --- a/libs/gst/base/gstbaseparse.c +++ b/libs/gst/base/gstbaseparse.c @@ -82,7 +82,11 @@ * contain a valid frame, this call must return FALSE and optionally * set the @skipsize value to inform base class that how many bytes * it needs to skip in order to find a valid frame. @framesize can always - * indicate a new minimum for current frame parsing. The passed buffer + * indicate a new minimum for current frame parsing. Indicating G_MAXUINT + * for requested amount means subclass simply needs best available + * subsequent data. In push mode this amounts to an additional input buffer + * (thus minimal additional latency), in pull mode this amounts to some + * arbitrary reasonable buffer size increase. The passed buffer * is read-only. Note that @check_valid_frame might receive any small * amount of input data when leftover data is being drained (e.g. at EOS). * @@ -237,6 +241,7 @@ struct _GstBaseParsePrivate guint bitrate; guint lead_in, lead_out; GstClockTime lead_in_ts, lead_out_ts; + GstClockTime min_latency, max_latency; gboolean discont; gboolean flushing; @@ -306,6 +311,9 @@ struct _GstBaseParsePrivate /* Segment event that closes the running segment prior to SEEK */ GstEvent *close_segment; + + /* push mode helper frame */ + GstBaseParseFrame frame; }; typedef struct _GstBaseParseSeek @@ -566,8 +574,11 @@ gst_base_parse_frame_free (GstBaseParseFrame * frame) frame->buffer = NULL; } - if (!(frame->_private_flags & GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC)) + if (!(frame->_private_flags & GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC)) { g_slice_free (GstBaseParseFrame, frame); + } else { + memset (frame, 0, sizeof (*frame)); + } } GType @@ -720,6 +731,11 @@ gst_base_parse_reset (GstBaseParse * parse) g_slist_foreach (parse->priv->pending_seeks, (GFunc) g_free, NULL); g_slist_free (parse->priv->pending_seeks); parse->priv->pending_seeks = NULL; + + /* we know it is not alloc'ed, but maybe other stuff to free, some day ... */ + parse->priv->frame._private_flags |= + GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC; + gst_base_parse_frame_free (&parse->priv->frame); GST_OBJECT_UNLOCK (parse); } @@ -1023,6 +1039,9 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) parse->priv->flushing = FALSE; parse->priv->discont = TRUE; parse->priv->last_ts = GST_CLOCK_TIME_NONE; + parse->priv->frame._private_flags |= + GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC; + gst_base_parse_frame_free (&parse->priv->frame); break; case GST_EVENT_EOS: @@ -2157,19 +2176,17 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) const guint8 *data; guint old_min_size = 0, min_size, av; GstClockTime timestamp; - GstBaseParseFrame _frame; GstBaseParseFrame *frame; parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad)); bclass = GST_BASE_PARSE_GET_CLASS (parse); - frame = &_frame; - - gst_base_parse_frame_init (frame); + frame = &parse->priv->frame; if (G_LIKELY (buffer)) { GST_LOG_OBJECT (parse, "buffer size: %d, offset = %" G_GINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer)); if (G_UNLIKELY (parse->priv->passthrough)) { + gst_base_parse_frame_init (frame); frame->buffer = gst_buffer_make_metadata_writable (buffer); return gst_base_parse_push_frame (parse, frame); } @@ -2186,16 +2203,29 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) gst_adapter_push (parse->priv->adapter, buffer); } + if (G_UNLIKELY (buffer && + GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) { + frame->_private_flags |= GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC; + gst_base_parse_frame_free (frame); + } + /* Parse and push as many frames as possible */ /* Stop either when adapter is empty or we are flushing */ while (!parse->priv->flushing) { gboolean res; + /* maintain frame state for a single frame parsing round across _chain calls, + * so only init when needed */ + if (!frame->_private_flags) + gst_base_parse_frame_init (frame); + tmpbuf = gst_buffer_new (); old_min_size = 0; /* Synchronization loop */ for (;;) { + /* note: if subclass indicates MAX fsize, + * this will not likely be available anyway ... */ min_size = MAX (parse->priv->min_frame_size, fsize); av = gst_adapter_available (parse->priv->adapter); @@ -2224,7 +2254,7 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) /* always pass all available data */ data = gst_adapter_peek (parse->priv->adapter, av); GST_BUFFER_DATA (tmpbuf) = (guint8 *) data; - GST_BUFFER_SIZE (tmpbuf) = min_size; + GST_BUFFER_SIZE (tmpbuf) = av; GST_BUFFER_OFFSET (tmpbuf) = parse->priv->offset; GST_BUFFER_FLAG_SET (tmpbuf, GST_MINI_OBJECT_FLAG_READONLY); @@ -2497,6 +2527,12 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, GST_LOG_OBJECT (parse, "scanning for frame at offset %" G_GUINT64_FORMAT " (%#" G_GINT64_MODIFIER "x)", parse->priv->offset, parse->priv->offset); + /* let's make this efficient for all subclass once and for all; + * maybe it does not need this much, but in the latter case, we know we are + * in pull mode here and might as well try to read and supply more anyway + * (so does the buffer caching mechanism) */ + fsize = 64 * 1024; + while (TRUE) { gboolean res; @@ -2547,7 +2583,9 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, if (!parse->priv->discont) parse->priv->sync_offset = parse->priv->offset; parse->priv->discont = TRUE; - /* something changed least; nullify loop check */ + /* something changed at least; nullify loop check */ + if (fsize == G_MAXUINT) + fsize = old_min_size + 64 * 1024; old_min_size = 0; } /* skip == 0 should imply subclass set min_size to need more data; @@ -3018,6 +3056,31 @@ gst_base_parse_set_passthrough (GstBaseParse * parse, gboolean passthrough) GST_INFO_OBJECT (parse, "passthrough: %s", (passthrough) ? "yes" : "no"); } +/** + * gst_base_parse_set_latency: + * @parse: a #GstBaseParse + * @min_latency: minimum parse latency + * @max_latency: maximum parse latency + * + * Sets the minimum and maximum (which may likely be equal) latency introduced + * by the parsing process. If there is such a latency, which depends on the + * particular parsing of the format, it typically corresponds to 1 frame duration. + * + * Since: 0.10.34 + */ +void +gst_base_parse_set_latency (GstBaseParse * parse, GstClockTime min_latency, + GstClockTime max_latency) +{ + GST_OBJECT_LOCK (parse); + parse->priv->min_latency = min_latency; + parse->priv->max_latency = max_latency; + GST_OBJECT_UNLOCK (parse); + GST_INFO_OBJECT (parse, "min/max latency %" GST_TIME_FORMAT ", %" + GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), + GST_TIME_ARGS (max_latency)); +} + static gboolean gst_base_parse_get_duration (GstBaseParse * parse, GstFormat format, GstClockTime * duration) @@ -3178,6 +3241,29 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) } break; } + case GST_QUERY_LATENCY: + { + if ((res = gst_pad_peer_query (parse->sinkpad, query))) { + gboolean live; + GstClockTime min_latency, max_latency; + + gst_query_parse_latency (query, &live, &min_latency, &max_latency); + GST_DEBUG_OBJECT (parse, "Peer latency: live %d, min %" + GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live, + GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); + + GST_OBJECT_LOCK (parse); + /* add our latency */ + if (min_latency != -1) + min_latency += parse->priv->min_latency; + if (max_latency != -1) + max_latency += parse->priv->max_latency; + GST_OBJECT_UNLOCK (parse); + + gst_query_set_latency (query, live, min_latency, max_latency); + } + break; + } default: res = gst_pad_query_default (pad, query); break; diff --git a/libs/gst/base/gstbaseparse.h b/libs/gst/base/gstbaseparse.h index 74eaa97b8..655ad0e4a 100644 --- a/libs/gst/base/gstbaseparse.h +++ b/libs/gst/base/gstbaseparse.h @@ -297,6 +297,10 @@ void gst_base_parse_set_frame_rate (GstBaseParse * parse, guint lead_in, guint lead_out); +void gst_base_parse_set_latency (GstBaseParse * parse, + GstClockTime min_latency, + GstClockTime max_latency); + gboolean gst_base_parse_convert_default (GstBaseParse * parse, GstFormat src_format, gint64 src_value, diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 7740a77e9..d60ba6fdf 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -2186,14 +2186,21 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time, time += base_time; /* Re-use existing clockid if available */ - if (G_LIKELY (sink->priv->cached_clock_id != NULL)) { + /* FIXME: Casting to GstClockEntry only works because the types + * are the same */ + if (G_LIKELY (sink->priv->cached_clock_id != NULL + && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink-> + priv->cached_clock_id) == clock)) { if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id, time)) { gst_clock_id_unref (sink->priv->cached_clock_id); sink->priv->cached_clock_id = gst_clock_new_single_shot_id (clock, time); } - } else + } else { + if (sink->priv->cached_clock_id != NULL) + gst_clock_id_unref (sink->priv->cached_clock_id); sink->priv->cached_clock_id = gst_clock_new_single_shot_id (clock, time); + } GST_OBJECT_UNLOCK (sink); /* A blocking wait is performed on the clock. We save the ClockID @@ -3229,7 +3236,7 @@ stopping: * * Queue an object for rendering. * The first prerollable object queued will complete the preroll. If the - * preroll queue if filled, we render all the objects in the queue. + * preroll queue is filled, we render all the objects in the queue. * * This function takes ownership of the object. */ diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index 59319e256..947562c7a 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -234,6 +234,7 @@ struct _GstBaseSrcPrivate GstClockTimeDiff ts_offset; gboolean do_timestamp; + volatile gint dynamic_size; /* stream sequence number */ guint32 seqnum; @@ -323,6 +324,8 @@ static GstFlowReturn gst_base_src_pad_get_range (GstPad * pad, guint64 offset, static GstFlowReturn gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length, GstBuffer ** buf); static gboolean gst_base_src_seekable (GstBaseSrc * src); +static gboolean gst_base_src_update_length (GstBaseSrc * src, guint64 offset, + guint * length); static void gst_base_src_base_init (gpointer g_class) @@ -584,6 +587,25 @@ gst_base_src_set_format (GstBaseSrc * src, GstFormat format) GST_OBJECT_UNLOCK (src); } +/** + * gst_base_src_set_dynamic_size: + * @src: base source instance + * @dynamic: new dynamic size mode + * + * If not @dynamic, size is only updated when needed, such as when trying to + * read past current tracked size. Otherwise, size is checked for upon each + * read. + * + * Since: 0.10.35 + */ +void +gst_base_src_set_dynamic_size (GstBaseSrc * src, gboolean dynamic) +{ + g_return_if_fail (GST_IS_BASE_SRC (src)); + + g_atomic_int_set (&src->priv->dynamic_size, dynamic); +} + /** * gst_base_src_query_latency: * @src: the source @@ -932,9 +954,14 @@ gst_base_src_default_query (GstBaseSrc * src, GstQuery * query) { gint64 duration; GstFormat seg_format; + guint length = 0; + + /* may have to refresh duration */ + if (g_atomic_int_get (&src->priv->dynamic_size)) + gst_base_src_update_length (src, 0, &length); - GST_OBJECT_LOCK (src); /* this is the duration as configured by the subclass. */ + GST_OBJECT_LOCK (src); duration = src->segment.duration; seg_format = src->segment.format; GST_OBJECT_UNLOCK (src); @@ -2028,6 +2055,7 @@ gst_base_src_update_length (GstBaseSrc * src, guint64 offset, guint * length) GstBaseSrcClass *bclass; GstFormat format; gint64 stop; + gboolean dynamic; bclass = GST_BASE_SRC_GET_CLASS (src); @@ -2052,11 +2080,14 @@ gst_base_src_update_length (GstBaseSrc * src, guint64 offset, guint * length) ", segment.stop %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT, offset, *length, size, stop, maxsize); + dynamic = g_atomic_int_get (&src->priv->dynamic_size); + GST_DEBUG_OBJECT (src, "dynamic size: %d", dynamic); + /* check size if we have one */ if (maxsize != -1) { /* if we run past the end, check if the file became bigger and * retry. */ - if (G_UNLIKELY (offset + *length >= maxsize)) { + if (G_UNLIKELY (offset + *length >= maxsize || dynamic)) { /* see if length of the file changed */ if (bclass->get_size) if (!bclass->get_size (src, &size)) diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h index 2a3caecdb..87e1c06f4 100644 --- a/libs/gst/base/gstbasesrc.h +++ b/libs/gst/base/gstbasesrc.h @@ -245,6 +245,8 @@ gboolean gst_base_src_is_live (GstBaseSrc *src); void gst_base_src_set_format (GstBaseSrc *src, GstFormat format); +void gst_base_src_set_dynamic_size (GstBaseSrc * src, gboolean dynamic); + gboolean gst_base_src_query_latency (GstBaseSrc *src, gboolean * live, GstClockTime * min_latency, GstClockTime * max_latency); diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index ccf0802c2..a46642ea2 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -654,26 +654,25 @@ gst_base_transform_getcaps (GstPad * pad) { GstBaseTransform *trans; GstPad *otherpad; - GstCaps *caps; + GstCaps *peercaps, *caps; trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad)); otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad; /* we can do what the peer can */ - caps = gst_pad_peer_get_caps_reffed (otherpad); - if (caps) { + peercaps = gst_pad_peer_get_caps_reffed (otherpad); + if (peercaps) { GstCaps *temp; const GstCaps *templ; - GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps); + GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, peercaps); /* filtered against our padtemplate on the other side */ templ = gst_pad_get_pad_template_caps (otherpad); GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ); - temp = gst_caps_intersect (caps, templ); + temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST); GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp); - gst_caps_unref (caps); /* then see what we can transform this to */ caps = gst_base_transform_transform_caps (trans, @@ -690,8 +689,16 @@ gst_base_transform_getcaps (GstPad * pad) temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST); GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp); gst_caps_unref (caps); - /* this is what we can do */ caps = temp; + + /* Now try if we can put the untransformed downstream caps first */ + temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST); + if (!gst_caps_is_empty (temp)) { + gst_caps_merge (temp, caps); + caps = temp; + } else { + gst_caps_unref (temp); + } } else { /* no peer or the peer can do anything, our padtemplate is enough then */ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); @@ -700,6 +707,9 @@ gst_base_transform_getcaps (GstPad * pad) done: GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps); + if (peercaps) + gst_caps_unref (peercaps); + gst_object_unref (trans); return caps; @@ -853,7 +863,9 @@ gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad, GST_DEBUG_OBJECT (trans, "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps); - intersect = gst_caps_intersect (othercaps, templ_caps); + intersect = + gst_caps_intersect_full (othercaps, templ_caps, + GST_CAPS_INTERSECT_FIRST); gst_caps_unref (othercaps); othercaps = intersect; @@ -1787,7 +1799,9 @@ gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size, if (peercaps) { GstCaps *intersect; - intersect = gst_caps_intersect (peercaps, sink_suggest); + intersect = + gst_caps_intersect_full (sink_suggest, peercaps, + GST_CAPS_INTERSECT_FIRST); gst_caps_unref (peercaps); gst_caps_unref (sink_suggest); sink_suggest = intersect; @@ -1802,7 +1816,9 @@ gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size, GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible " "with the non-fixed caps suggestion"); - intersect = gst_caps_intersect (sink_suggest, caps); + intersect = + gst_caps_intersect_full (sink_suggest, caps, + GST_CAPS_INTERSECT_FIRST); if (!gst_caps_is_empty (intersect)) { GST_DEBUG_OBJECT (trans, "It is, using it"); gst_caps_replace (&sink_suggest, caps); diff --git a/libs/gst/check/gstcheck.h b/libs/gst/check/gstcheck.h index b74637172..004eb7457 100644 --- a/libs/gst/check/gstcheck.h +++ b/libs/gst/check/gstcheck.h @@ -146,6 +146,34 @@ G_STMT_START { \ */ #define assert_equals_int(a, b) fail_unless_equals_int(a, b) +/** + * fail_unless_equals_int64: + * @a: a #gint64 value or expression + * @b: a #gint64 value or expression + * + * This macro checks that @a and @b are equal and aborts if this is not the + * case, printing both expressions and the values they evaluated to. This + * macro is for use in unit tests. + */ +#define fail_unless_equals_int64(a, b) \ +G_STMT_START { \ + gint64 first = a; \ + gint64 second = b; \ + fail_unless(first == second, \ + "'" #a "' (%" G_GINT64_FORMAT") is not equal to '" #b"' (%" \ + G_GINT64_FORMAT")", first, second); \ +} G_STMT_END; +/** + * assert_equals_int64: + * @a: a #gint64 value or expression + * @b: a #gint64 value or expression + * + * This macro checks that @a and @b are equal and aborts if this is not the + * case, printing both expressions and the values they evaluated to. This + * macro is for use in unit tests. + */ +#define assert_equals_int64(a, b) fail_unless_equals_int64(a, b) + /** * fail_unless_equals_uint64: * @a: a #guint64 value or expression diff --git a/plugins/elements/gstfdsrc.c b/plugins/elements/gstfdsrc.c index 6d7f0f9ce..3d38c6c59 100644 --- a/plugins/elements/gstfdsrc.c +++ b/plugins/elements/gstfdsrc.c @@ -275,6 +275,8 @@ gst_fd_src_update_fd (GstFdSrc * src, guint64 size) GST_INFO_OBJECT (src, "marking fd %d as seekable", src->fd); src->seekable_fd = TRUE; + + gst_base_src_set_dynamic_size (GST_BASE_SRC (src), TRUE); } return; @@ -282,6 +284,7 @@ not_seekable: { GST_INFO_OBJECT (src, "marking fd %d as NOT seekable", src->fd); src->seekable_fd = FALSE; + gst_base_src_set_dynamic_size (GST_BASE_SRC (src), FALSE); } } diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index cc07a72a0..f8dbfe2c4 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -1019,6 +1019,8 @@ gst_file_src_start (GstBaseSrc * basesrc) * don't know their length, so seeking isn't useful/meaningful */ src->seekable = src->seekable && src->is_regular; + gst_base_src_set_dynamic_size (basesrc, src->seekable); + return TRUE; /* ERROR */ diff --git a/plugins/elements/gstinputselector.c b/plugins/elements/gstinputselector.c index 32a4aa9a0..f62a488c6 100644 --- a/plugins/elements/gstinputselector.c +++ b/plugins/elements/gstinputselector.c @@ -95,9 +95,12 @@ enum { PROP_0, PROP_N_PADS, - PROP_ACTIVE_PAD + PROP_ACTIVE_PAD, + PROP_SYNC_STREAMS }; +#define DEFAULT_SYNC_STREAMS FALSE + #define DEFAULT_PAD_ALWAYS_OK TRUE enum @@ -624,6 +627,105 @@ gst_input_selector_wait (GstInputSelector * self, GstSelectorPad * pad) return self->flushing; } +/* must be called with the SELECTOR_LOCK, will block until the running time + * of the active pad is after this pad or return TRUE when flushing */ +static gboolean +gst_input_selector_wait_running_time (GstInputSelector * sel, + GstSelectorPad * pad, GstBuffer * buf) +{ + GstPad *active_sinkpad; + GstSelectorPad *active_selpad; + GstSegment *seg, *active_seg; + GstClockTime running_time, active_running_time = -1; + + seg = &pad->segment; + + active_sinkpad = + gst_input_selector_activate_sinkpad (sel, GST_PAD_CAST (pad)); + active_selpad = GST_SELECTOR_PAD_CAST (active_sinkpad); + active_seg = &active_selpad->segment; + + /* We can only sync if the segments are in time format or + * if the active pad had no newsegment event yet */ + if (seg->format != GST_FORMAT_TIME || + (active_seg->format != GST_FORMAT_TIME + && active_seg->format != GST_FORMAT_UNDEFINED)) + return FALSE; + + /* If we have no valid timestamp we can't sync this buffer */ + if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) + return FALSE; + + running_time = GST_BUFFER_TIMESTAMP (buf); + /* If possible try to get the running time at the end of the buffer */ + if (GST_BUFFER_DURATION_IS_VALID (buf)) + running_time += GST_BUFFER_DURATION (buf); + if (running_time > seg->stop) + running_time = seg->stop; + running_time = + gst_segment_to_running_time (seg, GST_FORMAT_TIME, running_time); + /* If this is outside the segment don't sync */ + if (running_time == -1) + return FALSE; + + /* Get active pad's running time, if no configured segment yet keep at -1 */ + if (active_seg->format == GST_FORMAT_TIME) + active_running_time = + gst_segment_to_running_time (active_seg, GST_FORMAT_TIME, + active_seg->last_stop); + + /* Wait until + * a) this is the active pad + * b) the pad or the selector is flushing + * c) the selector is not blocked + * d) the active pad has no running time or the active + * pad's running time is before this running time + * e) the active pad has a non-time segment + */ + while (pad != active_selpad && !sel->flushing && !pad->flushing && + (sel->blocked || active_running_time == -1 + || running_time >= active_running_time)) { + if (!sel->blocked) + GST_DEBUG_OBJECT (pad, + "Waiting for active streams to advance. %" GST_TIME_FORMAT " >= %" + GST_TIME_FORMAT, GST_TIME_ARGS (running_time), + GST_TIME_ARGS (active_running_time)); + + GST_INPUT_SELECTOR_WAIT (sel); + + /* Get new active pad, it might have changed */ + active_sinkpad = + gst_input_selector_activate_sinkpad (sel, GST_PAD_CAST (pad)); + active_selpad = GST_SELECTOR_PAD_CAST (active_sinkpad); + active_seg = &active_selpad->segment; + + /* If the active segment is configured but not to time format + * we can't do any syncing at all */ + if (active_seg->format != GST_FORMAT_TIME + && active_seg->format != GST_FORMAT_UNDEFINED) + break; + + /* Get the new active pad running time */ + if (active_seg->format == GST_FORMAT_TIME) + active_running_time = + gst_segment_to_running_time (active_seg, GST_FORMAT_TIME, + active_seg->last_stop); + else + active_running_time = -1; + + if (!sel->blocked) + GST_DEBUG_OBJECT (pad, + "Waited for active streams to advance. %" GST_TIME_FORMAT " >= %" + GST_TIME_FORMAT, GST_TIME_ARGS (running_time), + GST_TIME_ARGS (active_running_time)); + + } + + /* Return TRUE if the selector or the pad is flushing */ + return (sel->flushing || pad->flushing); +} + + static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf) { @@ -651,6 +753,16 @@ gst_selector_pad_chain (GstPad * pad, GstBuffer * buf) prev_active_sinkpad = sel->active_sinkpad; active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + /* In sync mode wait until the active pad has advanced + * after the running time of the current buffer */ + if (sel->sync_streams && active_sinkpad != pad) { + if (gst_input_selector_wait_running_time (sel, selpad, buf)) + goto flushing; + } + + /* Might have changed while waiting */ + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + /* update the segment on the srcpad */ start_time = GST_BUFFER_TIMESTAMP (buf); if (GST_CLOCK_TIME_IS_VALID (start_time)) { @@ -669,6 +781,10 @@ gst_selector_pad_chain (GstPad * pad, GstBuffer * buf) if (pad != active_sinkpad) goto ignore; + /* Tell all non-active pads that we advanced the running time */ + if (sel->sync_streams) + GST_INPUT_SELECTOR_BROADCAST (sel); + if (G_UNLIKELY (sel->pending_close)) { GstSegment *cseg = &sel->segment; @@ -899,6 +1015,21 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) "The currently active sink pad", GST_TYPE_PAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstInputSelector:sync-streams + * + * If set to %TRUE all inactive streams will be synced to the + * running time of the active stream. This makes sure that no + * buffers are dropped by input-selector that might be needed + * when switching the active pad. + * + * Since: 0.10.35 + */ + g_object_class_install_property (gobject_class, PROP_SYNC_STREAMS, + g_param_spec_boolean ("sync-streams", "Sync Streams", + "Synchronize inactive streams to the running time of the active stream", + DEFAULT_SYNC_STREAMS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstInputSelector::block: * @inputselector: the #GstInputSelector @@ -991,6 +1122,7 @@ gst_input_selector_init (GstInputSelector * sel, sel->active_sinkpad = NULL; sel->padcount = 0; gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED); + sel->sync_streams = DEFAULT_SYNC_STREAMS; sel->lock = g_mutex_new (); sel->cond = g_cond_new (); @@ -1105,6 +1237,12 @@ gst_input_selector_set_active_pad (GstInputSelector * self, active_pad_p = &self->active_sinkpad; gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad)); + + /* Wake up all non-active pads in sync mode, they might be + * the active pad now */ + if (self->sync_streams) + GST_INPUT_SELECTOR_BROADCAST (self); + GST_DEBUG_OBJECT (self, "New active pad is %" GST_PTR_FORMAT, self->active_sinkpad); @@ -1130,6 +1268,13 @@ gst_input_selector_set_property (GObject * object, guint prop_id, GST_INPUT_SELECTOR_UNLOCK (sel); break; } + case PROP_SYNC_STREAMS: + { + GST_INPUT_SELECTOR_LOCK (sel); + sel->sync_streams = g_value_get_boolean (value); + GST_INPUT_SELECTOR_UNLOCK (sel); + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1153,6 +1298,11 @@ gst_input_selector_get_property (GObject * object, guint prop_id, g_value_set_object (value, sel->active_sinkpad); GST_INPUT_SELECTOR_UNLOCK (object); break; + case PROP_SYNC_STREAMS: + GST_INPUT_SELECTOR_LOCK (object); + g_value_set_boolean (value, sel->sync_streams); + GST_INPUT_SELECTOR_UNLOCK (object); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/plugins/elements/gstinputselector.h b/plugins/elements/gstinputselector.h index 0ed7a4b3c..f37099968 100644 --- a/plugins/elements/gstinputselector.h +++ b/plugins/elements/gstinputselector.h @@ -56,6 +56,7 @@ struct _GstInputSelector { GstPad *active_sinkpad; guint n_pads; guint padcount; + gboolean sync_streams; GstSegment segment; /* the output segment */ gboolean pending_close; /* if we should push a close first */ diff --git a/plugins/elements/gstmultiqueue.c b/plugins/elements/gstmultiqueue.c index 541e04235..9f39155af 100644 --- a/plugins/elements/gstmultiqueue.c +++ b/plugins/elements/gstmultiqueue.c @@ -157,6 +157,8 @@ struct _GstSingleQueue guint32 nextid; /* ID of the next object waiting to be pushed */ guint32 oldid; /* ID of the last object pushed (last in a series) */ guint32 last_oldid; /* Previously observed old_id, reset to MAXUINT32 on flush */ + GstClockTime next_time; /* End running time of next buffer to be pushed */ + GstClockTime last_time; /* Start running time of last pushed buffer */ GCond *turn; /* SingleQueue turn waiting conditional */ }; @@ -180,6 +182,7 @@ static void gst_single_queue_free (GstSingleQueue * squeue); static void wake_up_next_non_linked (GstMultiQueue * mq); static void compute_high_id (GstMultiQueue * mq); +static void compute_high_time (GstMultiQueue * mq); static void single_queue_overrun_cb (GstDataQueue * dq, GstSingleQueue * sq); static void single_queue_underrun_cb (GstDataQueue * dq, GstSingleQueue * sq); @@ -225,6 +228,7 @@ enum #define DEFAULT_USE_BUFFERING FALSE #define DEFAULT_LOW_PERCENT 10 #define DEFAULT_HIGH_PERCENT 99 +#define DEFAULT_SYNC_BY_RUNNING_TIME FALSE enum { @@ -238,6 +242,7 @@ enum PROP_USE_BUFFERING, PROP_LOW_PERCENT, PROP_HIGH_PERCENT, + PROP_SYNC_BY_RUNNING_TIME, PROP_LAST }; @@ -397,6 +402,22 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass) "High threshold for buffering to finish", 0, 100, DEFAULT_HIGH_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstMultiQueue:sync-by-running-time + * + * If enabled multiqueue will synchronize deactivated or not-linked streams + * to the activated and linked streams by taking the running time. + * Otherwise multiqueue will synchronize the deactivated or not-linked + * streams by keeping the order in which buffers and events arrived compared + * to active and linked streams. + * + * Since: 0.10.35 + */ + g_object_class_install_property (gobject_class, PROP_SYNC_BY_RUNNING_TIME, + g_param_spec_boolean ("sync-by-running-time", "Sync By Running Time", + "Synchronize deactivated or not-linked streams by running time", + DEFAULT_SYNC_BY_RUNNING_TIME, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gobject_class->finalize = gst_multi_queue_finalize; @@ -426,8 +447,11 @@ gst_multi_queue_init (GstMultiQueue * mqueue, GstMultiQueueClass * klass) mqueue->low_percent = DEFAULT_LOW_PERCENT; mqueue->high_percent = DEFAULT_HIGH_PERCENT; + mqueue->sync_by_running_time = DEFAULT_SYNC_BY_RUNNING_TIME; + mqueue->counter = 1; mqueue->highid = -1; + mqueue->high_time = GST_CLOCK_TIME_NONE; mqueue->qlock = g_mutex_new (); } @@ -500,6 +524,9 @@ gst_multi_queue_set_property (GObject * object, guint prop_id, case PROP_HIGH_PERCENT: mq->high_percent = g_value_get_int (value); break; + case PROP_SYNC_BY_RUNNING_TIME: + mq->sync_by_running_time = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -542,6 +569,9 @@ gst_multi_queue_get_property (GObject * object, guint prop_id, case PROP_HIGH_PERCENT: g_value_set_int (value, mq->high_percent); break; + case PROP_SYNC_BY_RUNNING_TIME: + g_value_set_boolean (value, mq->sync_by_running_time); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -741,8 +771,15 @@ gst_single_queue_flush (GstMultiQueue * mq, GstSingleQueue * sq, gboolean flush) sq->nextid = 0; sq->oldid = 0; sq->last_oldid = G_MAXUINT32; + sq->next_time = GST_CLOCK_TIME_NONE; + sq->last_time = GST_CLOCK_TIME_NONE; gst_data_queue_set_flushing (sq->queue, FALSE); + /* Reset high time to be recomputed next */ + GST_MULTI_QUEUE_MUTEX_LOCK (mq); + mq->high_time = GST_CLOCK_TIME_NONE; + GST_MULTI_QUEUE_MUTEX_UNLOCK (mq); + sq->flushing = FALSE; GST_LOG_OBJECT (mq, "SingleQueue %d : starting task", sq->id); @@ -947,6 +984,71 @@ apply_buffer (GstMultiQueue * mq, GstSingleQueue * sq, GstClockTime timestamp, GST_MULTI_QUEUE_MUTEX_UNLOCK (mq); } +static GstClockTime +get_running_time (GstSegment * segment, GstMiniObject * object, gboolean end) +{ + GstClockTime time = GST_CLOCK_TIME_NONE; + + if (GST_IS_BUFFER (object)) { + GstBuffer *buf = GST_BUFFER_CAST (object); + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + time = GST_BUFFER_TIMESTAMP (buf); + if (end && GST_BUFFER_DURATION_IS_VALID (buf)) + time += GST_BUFFER_DURATION (buf); + if (time > segment->stop) + time = segment->stop; + time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, time); + } + } else if (GST_IS_BUFFER_LIST (object)) { + GstBufferList *list = GST_BUFFER_LIST_CAST (object); + GstBufferListIterator *it = gst_buffer_list_iterate (list); + GstBuffer *buf; + + do { + while ((buf = gst_buffer_list_iterator_next (it))) { + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + time = GST_BUFFER_TIMESTAMP (buf); + if (end && GST_BUFFER_DURATION_IS_VALID (buf)) + time += GST_BUFFER_DURATION (buf); + if (time > segment->stop) + time = segment->stop; + time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, time); + if (!end) + goto done; + } else if (!end) { + goto done; + } + } + } while (gst_buffer_list_iterator_next_group (it)); + } else if (GST_IS_EVENT (object)) { + GstEvent *event = GST_EVENT_CAST (object); + + /* For newsegment events return the running time of the start position */ + if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) { + GstSegment new_segment = *segment; + gboolean update; + gdouble rate, applied_rate; + GstFormat format; + gint64 start, stop, position; + + gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, + &format, &start, &stop, &position); + if (format == GST_FORMAT_TIME) { + gst_segment_set_newsegment_full (&new_segment, update, rate, + applied_rate, format, start, stop, position); + + time = + gst_segment_to_running_time (&new_segment, GST_FORMAT_TIME, + new_segment.start); + } + } + } + +done: + return time; +} + static GstFlowReturn gst_single_queue_push_one (GstMultiQueue * mq, GstSingleQueue * sq, GstMiniObject * object) @@ -1079,6 +1181,7 @@ gst_multi_queue_loop (GstPad * pad) GstMiniObject *object = NULL; guint32 newid; GstFlowReturn result; + GstClockTime next_time; sq = (GstSingleQueue *) gst_pad_get_element_private (pad); mq = sq->mqueue; @@ -1100,6 +1203,9 @@ gst_multi_queue_loop (GstPad * pad) object = gst_multi_queue_item_steal_object (item); gst_multi_queue_item_destroy (item); + /* Get running time of the item. Events will have GST_CLOCK_TIME_NONE */ + next_time = get_running_time (&sq->src_segment, object, TRUE); + GST_LOG_OBJECT (mq, "SingleQueue %d : newid:%d , oldid:%d", sq->id, newid, sq->last_oldid); @@ -1108,9 +1214,9 @@ gst_multi_queue_loop (GstPad * pad) * or it's the first loop, or we just passed the previous highid, * we might need to wake some sleeping pad up, so there's extra work * there too */ - if (sq->srcresult == GST_FLOW_NOT_LINKED || - (sq->last_oldid == G_MAXUINT32) || (newid != (sq->last_oldid + 1)) || - sq->last_oldid > mq->highid) { + if (sq->srcresult == GST_FLOW_NOT_LINKED + || (sq->last_oldid == G_MAXUINT32) || (newid != (sq->last_oldid + 1)) + || sq->last_oldid > mq->highid) { GST_LOG_OBJECT (mq, "CHECKING sq->srcresult: %s", gst_flow_get_name (sq->srcresult)); @@ -1125,6 +1231,7 @@ gst_multi_queue_loop (GstPad * pad) /* Update the nextid so other threads know when to wake us up */ sq->nextid = newid; + sq->next_time = next_time; /* Update the oldid (the last ID we output) for highid tracking */ if (sq->last_oldid != G_MAXUINT32) @@ -1135,10 +1242,20 @@ gst_multi_queue_loop (GstPad * pad) /* Recompute the highid */ compute_high_id (mq); - while (newid > mq->highid && sq->srcresult == GST_FLOW_NOT_LINKED) { - GST_DEBUG_OBJECT (mq, "queue %d sleeping for not-linked wakeup with " - "newid %u and highid %u", sq->id, newid, mq->highid); + /* Recompute the high time */ + compute_high_time (mq); + while (((mq->sync_by_running_time && next_time != GST_CLOCK_TIME_NONE && + (mq->high_time == GST_CLOCK_TIME_NONE + || next_time >= mq->high_time)) + || (!mq->sync_by_running_time && newid > mq->highid)) + && sq->srcresult == GST_FLOW_NOT_LINKED) { + + GST_DEBUG_OBJECT (mq, + "queue %d sleeping for not-linked wakeup with " + "newid %u, highid %u, next_time %" GST_TIME_FORMAT + ", high_time %" GST_TIME_FORMAT, sq->id, newid, mq->highid, + GST_TIME_ARGS (next_time), GST_TIME_ARGS (mq->high_time)); /* Wake up all non-linked pads before we sleep */ wake_up_next_non_linked (mq); @@ -1152,8 +1269,13 @@ gst_multi_queue_loop (GstPad * pad) goto out_flushing; } + /* Recompute the high time */ + compute_high_time (mq); + GST_DEBUG_OBJECT (mq, "queue %d woken from sleeping for not-linked " - "wakeup with newid %u and highid %u", sq->id, newid, mq->highid); + "wakeup with newid %u, highid %u, next_time %" GST_TIME_FORMAT + ", high_time %" GST_TIME_FORMAT, sq->id, newid, mq->highid, + GST_TIME_ARGS (next_time), GST_TIME_ARGS (mq->high_time)); } /* Re-compute the high_id in case someone else pushed */ @@ -1163,8 +1285,9 @@ gst_multi_queue_loop (GstPad * pad) /* Wake up all non-linked pads */ wake_up_next_non_linked (mq); } - /* We're done waiting, we can clear the nextid */ + /* We're done waiting, we can clear the nextid and nexttime */ sq->nextid = 0; + sq->next_time = GST_CLOCK_TIME_NONE; GST_MULTI_QUEUE_MUTEX_UNLOCK (mq); } @@ -1175,6 +1298,18 @@ gst_multi_queue_loop (GstPad * pad) GST_LOG_OBJECT (mq, "BEFORE PUSHING sq->srcresult: %s", gst_flow_get_name (sq->srcresult)); + /* Update time stats */ + next_time = get_running_time (&sq->src_segment, object, FALSE); + if (next_time != GST_CLOCK_TIME_NONE) { + if (sq->last_time == GST_CLOCK_TIME_NONE || sq->last_time < next_time) + sq->last_time = next_time; + if (mq->high_time == GST_CLOCK_TIME_NONE || mq->high_time <= next_time) { + /* Wake up all non-linked pads now that we advanceed the high time */ + mq->high_time = next_time; + wake_up_next_non_linked (mq); + } + } + /* Try to push out the new object */ result = gst_single_queue_push_one (mq, sq, object); sq->srcresult = result; @@ -1188,6 +1323,7 @@ gst_multi_queue_loop (GstPad * pad) gst_flow_get_name (sq->srcresult)); sq->last_oldid = newid; + return; out_flushing: @@ -1517,7 +1653,10 @@ wake_up_next_non_linked (GstMultiQueue * mq) GstSingleQueue *sq = (GstSingleQueue *) tmp->data; if (sq->srcresult == GST_FLOW_NOT_LINKED) { - if (sq->nextid != 0 && sq->nextid <= mq->highid) { + if ((mq->sync_by_running_time && mq->high_time != GST_CLOCK_TIME_NONE + && sq->next_time != GST_CLOCK_TIME_NONE + && sq->next_time >= mq->high_time) + || (sq->nextid != 0 && sq->nextid <= mq->highid)) { GST_LOG_OBJECT (mq, "Waking up singlequeue %d", sq->id); g_cond_signal (sq->turn); } @@ -1568,6 +1707,49 @@ compute_high_id (GstMultiQueue * mq) lowest); } +/* WITH LOCK TAKEN */ +static void +compute_high_time (GstMultiQueue * mq) +{ + /* The high-id is either the highest id among the linked pads, or if all + * pads are not-linked, it's the lowest not-linked pad */ + GList *tmp; + GstClockTime highest = GST_CLOCK_TIME_NONE; + GstClockTime lowest = GST_CLOCK_TIME_NONE; + + for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) { + GstSingleQueue *sq = (GstSingleQueue *) tmp->data; + + GST_LOG_OBJECT (mq, + "inspecting sq:%d , next_time:%" GST_TIME_FORMAT ", last_time:%" + GST_TIME_FORMAT ", srcresult:%s", sq->id, GST_TIME_ARGS (sq->next_time), + GST_TIME_ARGS (sq->last_time), gst_flow_get_name (sq->srcresult)); + + if (sq->srcresult == GST_FLOW_NOT_LINKED) { + /* No need to consider queues which are not waiting */ + if (sq->next_time == GST_CLOCK_TIME_NONE) { + GST_LOG_OBJECT (mq, "sq:%d is not waiting - ignoring", sq->id); + continue; + } + + if (lowest == GST_CLOCK_TIME_NONE || sq->next_time < lowest) + lowest = sq->next_time; + } else if (sq->srcresult != GST_FLOW_UNEXPECTED) { + /* If we don't have a global highid, or the global highid is lower than + * this single queue's last outputted id, store the queue's one, + * unless the singlequeue is at EOS (srcresult = UNEXPECTED) */ + if (highest == GST_CLOCK_TIME_NONE || sq->last_time > highest) + highest = sq->last_time; + } + } + + mq->high_time = highest; + + GST_LOG_OBJECT (mq, + "High time is now : %" GST_TIME_FORMAT ", lowest non-linked %" + GST_TIME_FORMAT, GST_TIME_ARGS (mq->high_time), GST_TIME_ARGS (lowest)); +} + #define IS_FILLED(q, format, value) (((q)->max_size.format) != 0 && \ ((q)->max_size.format) <= (value)) @@ -1771,6 +1953,8 @@ gst_single_queue_new (GstMultiQueue * mqueue, gint id) sq->nextid = 0; sq->oldid = 0; + sq->next_time = GST_CLOCK_TIME_NONE; + sq->last_time = GST_CLOCK_TIME_NONE; sq->turn = g_cond_new (); sq->sinktime = GST_CLOCK_TIME_NONE; diff --git a/plugins/elements/gstmultiqueue.h b/plugins/elements/gstmultiqueue.h index b9c28cd44..bb3d84042 100644 --- a/plugins/elements/gstmultiqueue.h +++ b/plugins/elements/gstmultiqueue.h @@ -50,6 +50,8 @@ typedef struct _GstMultiQueueClass GstMultiQueueClass; struct _GstMultiQueue { GstElement element; + gboolean sync_by_running_time; + /* number of queues */ guint nbqueues; @@ -65,6 +67,7 @@ struct _GstMultiQueue { guint32 counter; /* incoming object counter, use atomic accesses */ guint32 highid; /* contains highest id of last outputted object */ + GstClockTime high_time; /* highest start running time */ GMutex * qlock; /* Global queue lock (vs object lock or individual */ /* queues lock). Protects nbqueues, queues, global */ diff --git a/plugins/elements/gstoutputselector.c b/plugins/elements/gstoutputselector.c index f3ce6e295..300721983 100644 --- a/plugins/elements/gstoutputselector.c +++ b/plugins/elements/gstoutputselector.c @@ -371,7 +371,6 @@ gst_output_selector_buffer_alloc (GstPad * pad, guint64 offset, guint size, sel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad)); if (G_UNLIKELY (sel == NULL)) return GST_FLOW_WRONG_STATE; - res = GST_FLOW_NOT_LINKED; GST_OBJECT_LOCK (sel); allocpad = sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad; diff --git a/plugins/elements/gstqueue2.c b/plugins/elements/gstqueue2.c index 436323c0b..f1dce4b0c 100644 --- a/plugins/elements/gstqueue2.c +++ b/plugins/elements/gstqueue2.c @@ -898,6 +898,7 @@ reset_rate_timer (GstQueue2 * queue) queue->bytes_in = 0; queue->bytes_out = 0; queue->byte_in_rate = 0.0; + queue->byte_in_period = 0; queue->byte_out_rate = 0.0; queue->last_in_elapsed = 0.0; queue->last_out_elapsed = 0.0; @@ -910,8 +911,11 @@ reset_rate_timer (GstQueue2 * queue) /* Tuning for rate estimation. We use a large window for the input rate because * it should be stable when connected to a network. The output rate is less * stable (the elements preroll, queues behind a demuxer fill, ...) and should - * therefore adapt more quickly. */ -#define AVG_IN(avg,val) ((avg) * 15.0 + (val)) / 16.0 + * therefore adapt more quickly. + * However, initial input rate may be subject to a burst, and should therefore + * initially also adapt more quickly to changes, and only later on give higher + * weight to previous values. */ +#define AVG_IN(avg,val,w1,w2) ((avg) * (w1) + (val) * (w2)) / ((w1) + (w2)) #define AVG_OUT(avg,val) ((avg) * 3.0 + (val)) / 4.0 static void @@ -933,14 +937,20 @@ update_in_rates (GstQueue2 * queue) period = elapsed - queue->last_in_elapsed; GST_DEBUG_OBJECT (queue, - "rates: period %f, in %" G_GUINT64_FORMAT, period, queue->bytes_in); + "rates: period %f, in %" G_GUINT64_FORMAT ", global period %f", + period, queue->bytes_in, queue->byte_in_period); byte_in_rate = queue->bytes_in / period; if (queue->byte_in_rate == 0.0) queue->byte_in_rate = byte_in_rate; else - queue->byte_in_rate = AVG_IN (queue->byte_in_rate, byte_in_rate); + queue->byte_in_rate = AVG_IN (queue->byte_in_rate, byte_in_rate, + (double) queue->byte_in_period, period); + + /* another data point, cap at 16 for long time running average */ + if (queue->byte_in_period < 16 * RATE_INTERVAL) + queue->byte_in_period += period; /* reset the values to calculate rate over the next interval */ queue->last_in_elapsed = elapsed; diff --git a/plugins/elements/gstqueue2.h b/plugins/elements/gstqueue2.h index 358b43a47..ccbead6a1 100644 --- a/plugins/elements/gstqueue2.h +++ b/plugins/elements/gstqueue2.h @@ -116,6 +116,7 @@ struct _GstQueue2 gdouble last_in_elapsed; guint64 bytes_in; gdouble byte_in_rate; + gdouble byte_in_period; GTimer *out_timer; gboolean out_timer_started; diff --git a/po/af.po b/po/af.po index a181e82b6..dfd93b85b 100644 --- a/po/af.po +++ b/po/af.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.9.7\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2005-12-05 11:45+0200\n" "Last-Translator: Petri Jooste \n" "Language-Team: Afrikaans \n" @@ -1128,6 +1128,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Pyplyn word gestel na NULL ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "geen element \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Wys etikette (ook bekend as metadata)" diff --git a/po/az.po b/po/az.po index 4ce2582aa..c022a6be8 100644 --- a/po/az.po +++ b/po/az.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer-0.8.0\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2004-03-19 18:40+0200\n" "Last-Translator: Metin Amiroff \n" "Language-Team: Azerbaijani \n" @@ -1075,6 +1075,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, c-format +msgid "Missing element: %s\n" +msgstr "" + msgid "Output tags (also known as metadata)" msgstr "" diff --git a/po/be.po b/po/be.po index dbd76abf8..6da856d2b 100644 --- a/po/be.po +++ b/po/be.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.9.7\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2006-01-18 22:26+0200\n" "Last-Translator: Ales Nyakhaychyk \n" "Language-Team: Belarusian \n" @@ -1084,6 +1084,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, c-format +msgid "Missing element: %s\n" +msgstr "" + msgid "Output tags (also known as metadata)" msgstr "" diff --git a/po/bg.po b/po/bg.po index 4c9489d06..29d96ef67 100644 --- a/po/bg.po +++ b/po/bg.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.32.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-04-26 22:40+0300\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" @@ -1126,6 +1126,10 @@ msgstr "Задаване на състоянието на %s по заявка msgid "Interrupt: Stopping pipeline ...\n" msgstr "Прекъсване: Конвейерът се спира…\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "елементът „%s“ липсва" + msgid "Output tags (also known as metadata)" msgstr "Изходни съобщения за етикетите (метаданните)" diff --git a/po/ca.po b/po/ca.po index 0edb1bfb9..bebce39be 100644 --- a/po/ca.po +++ b/po/ca.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-11-04 19:41+0100\n" "Last-Translator: Jordi Mallach \n" "Language-Team: Catalan \n" @@ -1132,6 +1132,10 @@ msgstr "S'està establint l'estat a %s a petició de %s…\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interrupció: S'està aturant el conducte…\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "no hi ha cap element «%s»" + msgid "Output tags (also known as metadata)" msgstr "Mostra els marcadors (també coneguts com metadades)" diff --git a/po/cs.po b/po/cs.po index 4e42da628..19176b455 100644 --- a/po/cs.po +++ b/po/cs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.20.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2008-10-12 12:12+0200\n" "Last-Translator: Miloslav Trmac \n" "Language-Team: Czech \n" @@ -1140,6 +1140,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "PřeruÅ¡ení: Zastavuji rouru ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "element \"%s\" neexistuje" + msgid "Output tags (also known as metadata)" msgstr "Vypsat tagy (také známé jako metadata)" diff --git a/po/da.po b/po/da.po index 813661a6d..f9bdaf843 100644 --- a/po/da.po +++ b/po/da.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-11-06 22:52+0100\n" "Last-Translator: Mogens Jaeger \n" "Language-Team: Danish \n" @@ -1127,6 +1127,10 @@ msgstr "Sætter tilstand til %s som krævet af %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Afbrydelse: Stopper rørledning...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "intet element \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Uddatamærkater (ogsÃ¥ kendt som metadata)" diff --git a/po/de.po b/po/de.po index cc8741a0c..36f8ae413 100644 --- a/po/de.po +++ b/po/de.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.32.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-04-27 23:44+0200\n" "Last-Translator: Christian Kirbach \n" "Language-Team: German \n" @@ -1149,6 +1149,10 @@ msgstr "Status wird auf %s gesetzt wie von %s gewünscht...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interrupt: Leitung wird gestoppt ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "Kein Element »%s«" + msgid "Output tags (also known as metadata)" msgstr "Kennzeichen (auch bekannt als Metadaten) ausgeben" diff --git a/po/el.po b/po/el.po index c4409ca7b..f2585be49 100644 --- a/po/el.po +++ b/po/el.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer-0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-11-29 11:14+0200\n" "Last-Translator: Michael Kotsarinis \n" "Language-Team: Greek \n" @@ -1142,6 +1142,10 @@ msgstr "Ορισμός κατάστασης σε %s όπως ζητήθηκε α msgid "Interrupt: Stopping pipeline ...\n" msgstr "Διακοπή: Τερματισμός διασωλήνωσης…\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "δεν υπάρχει στοιχείο «%s»" + msgid "Output tags (also known as metadata)" msgstr "Ετικέτες εξόδου (επίσης γνωστές ως μεταδεδομένα)" diff --git a/po/en_GB.po b/po/en_GB.po index f77ab2985..fd70295d3 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.8.1\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2004-04-26 10:36-0400\n" "Last-Translator: Gareth Owen \n" "Language-Team: English (British) \n" @@ -1132,6 +1132,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "no element \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Output tags (also known as metadata)" diff --git a/po/es.po b/po/es.po index c579819a8..84e17719b 100644 --- a/po/es.po +++ b/po/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-11-01 18:11+0100\n" "Last-Translator: Jorge González González \n" "Language-Team: Spanish \n" @@ -1138,6 +1138,10 @@ msgstr "Estableciendo el estado a %s según lo solicitó %s…\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interrumpir: parando el conducto …\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "no hay un elemento «%s»" + msgid "Output tags (also known as metadata)" msgstr "Etiquetas de salida (también conocidos como metadatos)" diff --git a/po/eu.po b/po/eu.po index 529077fb5..ddd431a7b 100644 --- a/po/eu.po +++ b/po/eu.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer-0.10.26.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-03-25 13:10+0100\n" "Last-Translator: Mikel Olasagasti Uranga \n" "Language-Team: Basque \n" @@ -1134,6 +1134,10 @@ msgstr "Egoera %s(e)ra ezartzen %s(e)k eskatu bezala...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Eten: Kanalizazioa gelditzen... \n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "ez dago \"%s\" elementua" + msgid "Output tags (also known as metadata)" msgstr "Erakutsi etiketak (metadatu gisa ere ezagutzen direnak)" diff --git a/po/fi.po b/po/fi.po index 1add3ba93..0f77f4d01 100644 --- a/po/fi.po +++ b/po/fi.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-11-17 23:10+0200\n" "Last-Translator: Tommi Vainikainen \n" "Language-Team: Finnish \n" @@ -1125,6 +1125,10 @@ msgstr "Asetetaan tilaan %s kuten %s pyysi...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Keskeytys: Pysäytetään liukuhihna ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "ei elementtiä ”%s”" + msgid "Output tags (also known as metadata)" msgstr "Tulostemerkinnät (tunnetaan myös metadatana)" diff --git a/po/fr.po b/po/fr.po index 9641e7779..b4adae0ba 100644 --- a/po/fr.po +++ b/po/fr.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.32.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-04-28 09:34+0200\n" "Last-Translator: Claude Paroz \n" "Language-Team: French \n" @@ -1133,6 +1133,10 @@ msgstr "Définition de l'état à %s comme demandé par %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interruption : arrêt du pipeline...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "pas d'élément « %s »" + msgid "Output tags (also known as metadata)" msgstr "Affiche les balises (aussi connues sous le nom de métadonnées)" diff --git a/po/gl.po b/po/gl.po index a58aec8ac..f456f8f48 100644 --- a/po/gl.po +++ b/po/gl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.31.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-04-13 05:19+0000\n" "Last-Translator: Francisco Diéguez \n" "Language-Team: Galician \n" @@ -1126,6 +1126,10 @@ msgstr "Estabelecendo o estado a %s segundo foi solicitado por %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interromper: parando a canalización …\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "non hai un elemento «%s»" + msgid "Output tags (also known as metadata)" msgstr "Etiquetas de saída (tamén coñecido como metadatos)" diff --git a/po/hu.po b/po/hu.po index 74b2fd76f..ebe852157 100644 --- a/po/hu.po +++ b/po/hu.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-11-01 13:39+0100\n" "Last-Translator: Gabor Kelemen \n" "Language-Team: Hungarian \n" @@ -1117,6 +1117,10 @@ msgstr "Állapot beállítása erre: %s, %s kérésének megfelelően…\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Megszakítás: Adatcsatorna leállítása…\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "nincs „%s” elem" + msgid "Output tags (also known as metadata)" msgstr "Kimeneti címkék (metaadatok)" diff --git a/po/id.po b/po/id.po index ea40ed133..9b88775bd 100644 --- a/po/id.po +++ b/po/id.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.29.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-06-29 21:55+0700\n" "Last-Translator: Andhika Padmawan \n" "Language-Team: Indonesian \n" @@ -1124,6 +1124,10 @@ msgstr "Mengatur tingkat ke %s seperti diminta oleh %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interupsi: Menghentikan baris pipa ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "tak ada elemen \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Tag keluaran (juga dikenal sebagai metadata)" diff --git a/po/it.po b/po/it.po index c48f6706f..f26d74054 100644 --- a/po/it.po +++ b/po/it.po @@ -106,7 +106,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-10-25 10:03+0200\n" "Last-Translator: Luca Ferretti \n" "Language-Team: Italian \n" @@ -1294,6 +1294,10 @@ msgstr "Impostazione dello stato a %s come richiesto da %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interrotto: arresto della pipeline ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "nessun elemento «%s»" + # -t, --tags msgid "Output tags (also known as metadata)" msgstr "Stampa i tag (anche noti come metadati)" diff --git a/po/ja.po b/po/ja.po index dc0d8c55b..6cab73a70 100644 --- a/po/ja.po +++ b/po/ja.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.20.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2008-10-16 19:57+0900\n" "Last-Translator: Makoto Kato \n" "Language-Team: Japanese \n" @@ -1102,6 +1102,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "割り込み: パイプラインを停止しています...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "エレメント \"%s\" がありません" + msgid "Output tags (also known as metadata)" msgstr "タグ (メタデータ) を出力する" diff --git a/po/lt.po b/po/lt.po index 119cf67ef..0ea69f547 100644 --- a/po/lt.po +++ b/po/lt.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.29.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-07-16 00:50+0300\n" "Last-Translator: Žygimantas Beručka \n" "Language-Team: Lithuanian \n" @@ -1128,6 +1128,10 @@ msgstr "Nustatoma bÅ«sena į %s, kaip prašė %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Pertraukimas: stabdomas konvejeris...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "nėra elemento „%s“" + msgid "Output tags (also known as metadata)" msgstr "IÅ¡vesti žymas (dar žinomas kaip metaduomenys)" diff --git a/po/nb.po b/po/nb.po index 0fd1f5bb3..c9d96c98f 100644 --- a/po/nb.po +++ b/po/nb.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-10-24 21:36+0200\n" "Last-Translator: Kjartan Maraas \n" "Language-Team: Norwegian Bokmaal \n" @@ -1087,6 +1087,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "ingen element «%s»" + msgid "Output tags (also known as metadata)" msgstr "" diff --git a/po/nl.po b/po/nl.po index 65965491e..03852216c 100644 --- a/po/nl.po +++ b/po/nl.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.32.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-04-26 23:10+0200\n" "Last-Translator: Freek de Kruijf \n" "Language-Team: Dutch \n" @@ -1134,6 +1134,10 @@ msgstr "Stel de status in op %s zoals verzocht door %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interrupt: Pijplijn ingesteld op gestopt ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "geen element \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Tags (ook bekend als metadata) weergeven" diff --git a/po/pl.po b/po/pl.po index aa1e2db30..f49bb2237 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.32.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-04-26 17:54+0200\n" "Last-Translator: Jakub Bogusz \n" "Language-Team: Polish \n" @@ -1128,6 +1128,10 @@ msgstr "Ustawianie stanu na %s zgodnie z wymaganiem %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Przerwanie: Zatrzymywanie potoku...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "brak elementu \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Wypisanie znaczników (znanych także jako metadane)" diff --git a/po/pt_BR.po b/po/pt_BR.po index d14475992..4a59558b9 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -17,7 +17,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer-0.10.31.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-01-08 01:36-0300\n" "Last-Translator: Fabrício Godoy \n" "Language-Team: Brazilian Portuguese \n" @@ -1144,6 +1144,10 @@ msgstr "Definindo estado de %s como requerido por %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Interrupção: Parando a fila de processamento...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "nenhum elemento \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Exibir etiquetas (metadados)" diff --git a/po/ro.po b/po/ro.po index e7e7e3f96..ab39aac88 100644 --- a/po/ro.po +++ b/po/ro.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.29.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-08-16 01:10+0300\n" "Last-Translator: Lucian Adrian Grijincu \n" "Language-Team: Romanian \n" @@ -1150,6 +1150,10 @@ msgstr "Se definește starea la %s după cum a fost cerut de %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Întrerupere: Se oprește linia de asamblare ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "niciun element „%s”" + msgid "Output tags (also known as metadata)" msgstr "Marcaje de ieșire (cunoscute și ca „metadata”)" diff --git a/po/ru.po b/po/ru.po index 230090045..0144f7cbd 100644 --- a/po/ru.po +++ b/po/ru.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer-0.10.32.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-04-26 20:25+0400\n" "Last-Translator: Yuri Kozlov \n" "Language-Team: Russian \n" @@ -1128,6 +1128,10 @@ msgstr "Устанавливается состояние %s, запрошенн msgid "Interrupt: Stopping pipeline ...\n" msgstr "Прерывание: Остановка конвейера...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "элемент «%s» не найден" + msgid "Output tags (also known as metadata)" msgstr "Выводить теги (метаданные)" diff --git a/po/rw.po b/po/rw.po index 6200b2fcf..7178bad14 100644 --- a/po/rw.po +++ b/po/rw.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.8.8\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2005-04-04 10:55-0700\n" "Last-Translator: Steven Michael Murphy \n" "Language-Team: Kinyarwanda \n" @@ -1303,6 +1303,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "Oya Ikigize:" + #, fuzzy msgid "Output tags (also known as metadata)" msgstr "Nka" diff --git a/po/sk.po b/po/sk.po index 7c266a1fb..f818a54e5 100644 --- a/po/sk.po +++ b/po/sk.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.30.3\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-11-08 16:13+0100\n" "Last-Translator: Peter Tuhársky \n" "Language-Team: Slovak \n" @@ -1140,6 +1140,10 @@ msgstr "Nastavujem stav na %s ako požaduje %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "PreruÅ¡enie: Zastavujem rúru ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "prvok \"%s\" neexistuje" + msgid "Output tags (also known as metadata)" msgstr "VypísaÅ¥ značky (známe tiež ako metadáta)" diff --git a/po/sl.po b/po/sl.po index 20996f530..7f1fe7f44 100644 --- a/po/sl.po +++ b/po/sl.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.29.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-09-18 20:21+0100\n" "Last-Translator: Matej Urbančič \n" "Language-Team: Slovenian \n" @@ -1124,6 +1124,10 @@ msgstr "Nastavljanje stanja na %s, kot to zahteva %s ...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Prekinitev: zaustavljanje predvajanja vsebine cevovoda ... \n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "ni predmeta \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "" diff --git a/po/sq.po b/po/sq.po index 2b35a2341..dbc2ffa75 100644 --- a/po/sq.po +++ b/po/sq.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.8.4\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2004-08-07 23:46+0200\n" "Last-Translator: Laurent Dhima \n" "Language-Team: Albanian \n" @@ -1138,6 +1138,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "asnjë element \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Tags e output (njohur gjithashtu si metadata)" diff --git a/po/sr.po b/po/sr.po index 272ed70be..82810fb59 100644 --- a/po/sr.po +++ b/po/sr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.8.8\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2005-01-27 16:58+0100\n" "Last-Translator: Danilo Segan \n" "Language-Team: Serbian \n" @@ -1152,6 +1152,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "нема елемента „%s“" + msgid "Output tags (also known as metadata)" msgstr "Излазне ознаке (такође познато и као метаподаци)" diff --git a/po/sv.po b/po/sv.po index adbde5621..d27e68696 100644 --- a/po/sv.po +++ b/po/sv.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.31.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2011-01-09 19:46+0100\n" "Last-Translator: Daniel Nylander \n" "Language-Team: Swedish \n" @@ -1135,6 +1135,10 @@ msgstr "Ställer in tillstÃ¥ndet till %s enligt begäran frÃ¥n %s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Avbrott: Stoppar rörledningen ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "inget \"%s\"-element" + msgid "Output tags (also known as metadata)" msgstr "Utmatningstaggar (även känt som metadata)" diff --git a/po/tr.po b/po/tr.po index a4c2a40c8..d973ac9ba 100644 --- a/po/tr.po +++ b/po/tr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.8.0\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2004-04-03 03:14+0300\n" "Last-Translator: Baris Cicek \n" "Language-Team: Turkish \n" @@ -1138,6 +1138,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "\"%s\" öğesi yok" + msgid "Output tags (also known as metadata)" msgstr "Çıktı etiketleri (metadata olarak da bilinir)" diff --git a/po/uk.po b/po/uk.po index 50b36d9c7..70d9a32b5 100644 --- a/po/uk.po +++ b/po/uk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.14\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2007-09-07 11:16+0300\n" "Last-Translator: Maxim V. Dziumanenko \n" "Language-Team: Ukrainian \n" @@ -1131,6 +1131,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Переривання: Канал переводиться у стан ПРИЗУПИНЕНО ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "немає елементу \"%s\"" + msgid "Output tags (also known as metadata)" msgstr "Вивести теги (також відомі як метадані)" diff --git a/po/vi.po b/po/vi.po index d95c7a04c..6dafb70c7 100644 --- a/po/vi.po +++ b/po/vi.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.29.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-10-03 19:09+1030\n" "Last-Translator: Clytie Siddall \n" "Language-Team: Vietnamese \n" @@ -1125,6 +1125,10 @@ msgstr "Đang đặt tình trạng thành %s nhÆ° yêu cầu bởi %s....\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "Ngắt: đang ngừng chạy đường ống ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "không có yếu tố « %s »" + msgid "Output tags (also known as metadata)" msgstr "Thể xuất (cÅ©ng được biết là siêu dữ liệu)" diff --git a/po/zh_CN.po b/po/zh_CN.po index daaf2027b..92a1d9e41 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.10.25.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2010-02-02 18:58+0800\n" "Last-Translator: Ji ZhengYu \n" "Language-Team: Chinese (simplified) \n" @@ -1096,6 +1096,10 @@ msgstr "%2$s 发起请求时状态设置为 %1$s...\n" msgid "Interrupt: Stopping pipeline ...\n" msgstr "中断: 中止管道 ...\n" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "无组件“%s”" + msgid "Output tags (also known as metadata)" msgstr "输出标识(也可认为是元数据)" diff --git a/po/zh_TW.po b/po/zh_TW.po index 4a83e2121..7bb8fee21 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer 0.8.8\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2011-05-10 08:32+0100\n" +"POT-Creation-Date: 2011-06-04 13:33+0100\n" "PO-Revision-Date: 2005-04-27 14:55+0800\n" "Last-Translator: Abel Cheung \n" "Language-Team: Chinese (traditional) \n" @@ -1115,6 +1115,10 @@ msgstr "" msgid "Interrupt: Stopping pipeline ...\n" msgstr "" +#, fuzzy, c-format +msgid "Missing element: %s\n" +msgstr "“%s” 元件不存在" + msgid "Output tags (also known as metadata)" msgstr "" diff --git a/tests/check/gst/gstcaps.c b/tests/check/gst/gstcaps.c index fa160d91d..cd8b9d0b3 100644 --- a/tests/check/gst/gstcaps.c +++ b/tests/check/gst/gstcaps.c @@ -348,6 +348,46 @@ GST_START_TEST (test_truncate) GST_END_TEST; +GST_START_TEST (test_subset) +{ + GstCaps *c1, *c2; + + c1 = gst_caps_from_string ("video/x-raw-yuv; video/x-raw-rgb"); + c2 = gst_caps_from_string ("video/x-raw-yuv, format=(fourcc)YUY2"); + fail_unless (gst_caps_is_subset (c2, c1)); + fail_if (gst_caps_is_subset (c1, c2)); + gst_caps_unref (c1); + gst_caps_unref (c2); + + c1 = gst_caps_from_string + ("audio/x-raw-int, channels=(int)[ 1, 2 ], rate=(int)44100"); + c2 = gst_caps_from_string + ("audio/x-raw-int, channels=(int)1, rate=(int)44100"); + fail_unless (gst_caps_is_subset (c2, c1)); + fail_if (gst_caps_is_subset (c1, c2)); + gst_caps_unref (c1); + gst_caps_unref (c2); + + c1 = gst_caps_from_string ("audio/x-raw-int, channels=(int) {1}"); + c2 = gst_caps_from_string ("audio/x-raw-int, channels=(int)1"); + fail_unless (gst_caps_is_subset (c2, c1)); + fail_unless (gst_caps_is_subset (c1, c2)); + fail_unless (gst_caps_is_equal (c1, c2)); + gst_caps_unref (c1); + gst_caps_unref (c2); + + c1 = gst_caps_from_string + ("audio/x-raw-int, rate=(int)44100, channels=(int)3, endianness=(int)1234, width=(int)16, depth=(int)16, signed=(boolean)false"); + c2 = gst_caps_from_string + ("audio/x-raw-int, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], endianness=(int){ 1234, 4321 }, width=(int)16, depth=(int)[ 1, 16 ], signed=(boolean){ true, false }"); + fail_unless (gst_caps_is_subset (c1, c2)); + fail_if (gst_caps_is_subset (c2, c1)); + gst_caps_unref (c1); + gst_caps_unref (c2); +} + +GST_END_TEST; + GST_START_TEST (test_merge_fundamental) { GstCaps *c1, *c2; @@ -573,6 +613,26 @@ GST_START_TEST (test_merge_subset) fail_unless (gst_caps_is_subset (test, c2)); gst_caps_unref (test); gst_caps_unref (c2); + + c2 = gst_caps_from_string ("audio/x-raw-int"); + c1 = gst_caps_from_string ("audio/x-raw-int,channels=1"); + gst_caps_merge (c2, c1); + GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2); + fail_unless (gst_caps_get_size (c2) == 1, NULL); + test = gst_caps_from_string ("audio/x-raw-int"); + fail_unless (gst_caps_is_equal (c2, test)); + gst_caps_unref (c2); + gst_caps_unref (test); + + c2 = gst_caps_from_string ("audio/x-raw-int,channels=1"); + c1 = gst_caps_from_string ("audio/x-raw-int"); + gst_caps_merge (c2, c1); + GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2); + fail_unless (gst_caps_get_size (c2) == 2, NULL); + test = gst_caps_from_string ("audio/x-raw-int,channels=1; audio/x-raw-int"); + fail_unless (gst_caps_is_equal (c2, test)); + gst_caps_unref (c2); + gst_caps_unref (test); } GST_END_TEST; @@ -811,6 +871,24 @@ GST_START_TEST (test_intersect_first2) GST_END_TEST; +GST_START_TEST (test_intersect_duplication) +{ + GstCaps *c1, *c2, *test; + + c1 = gst_caps_from_string + ("audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2 ]"); + c2 = gst_caps_from_string + ("audio/x-raw-int, width=(int)16, depth=(int)16, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2 ], endianness=(int){ 1234, 4321 }, signed=(boolean){ true, false }; audio/x-raw-int, width=(int)16, depth=(int)16, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 11 ], endianness=(int){ 1234, 4321 }, signed=(boolean){ true, false }; audio/x-raw-int, width=(int)16, depth=(int)[ 1, 16 ], rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 11 ], endianness=(int){ 1234, 4321 }, signed=(boolean){ true, false }"); + + test = gst_caps_intersect_full (c1, c2, GST_CAPS_INTERSECT_FIRST); + fail_unless_equals_int (gst_caps_get_size (test), 1); + fail_unless (gst_caps_is_equal (c1, test)); + gst_caps_unref (c1); + gst_caps_unref (c2); + gst_caps_unref (test); +} + +GST_END_TEST; static gboolean _caps_is_fixed_foreach (GQuark field_id, const GValue * value, gpointer unused) @@ -913,6 +991,7 @@ gst_caps_suite (void) tcase_add_test (tc_chain, test_static_caps); tcase_add_test (tc_chain, test_simplify); tcase_add_test (tc_chain, test_truncate); + tcase_add_test (tc_chain, test_subset); tcase_add_test (tc_chain, test_merge_fundamental); tcase_add_test (tc_chain, test_merge_same); tcase_add_test (tc_chain, test_merge_subset); @@ -921,6 +1000,7 @@ gst_caps_suite (void) tcase_add_test (tc_chain, test_intersect_zigzag); tcase_add_test (tc_chain, test_intersect_first); tcase_add_test (tc_chain, test_intersect_first2); + tcase_add_test (tc_chain, test_intersect_duplication); tcase_add_test (tc_chain, test_normalize); tcase_add_test (tc_chain, test_broken); diff --git a/tests/check/gst/gstghostpad.c b/tests/check/gst/gstghostpad.c index b78538aaa..332f6540a 100644 --- a/tests/check/gst/gstghostpad.c +++ b/tests/check/gst/gstghostpad.c @@ -255,7 +255,7 @@ GST_END_TEST; GST_START_TEST (test_link) { GstElement *b1, *b2, *src, *sink; - GstPad *srcpad, *sinkpad, *gpad; + GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp; GstPadLinkReturn ret; b1 = gst_element_factory_make ("pipeline", NULL); @@ -278,6 +278,14 @@ GST_START_TEST (test_link) /* now setup a ghostpad */ gpad = gst_ghost_pad_new ("sink", sinkpad); + + /* Check if the internal pads are set correctly */ + ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad))); + fail_unless (ppad == GST_PAD_PEER (sinkpad)); + tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad))); + fail_unless (tmp == gpad); + gst_object_unref (tmp); + gst_object_unref (ppad); gst_object_unref (sinkpad); /* need to ref as _add_pad takes ownership */ gst_object_ref (gpad); diff --git a/tests/check/gst/gstminiobject.c b/tests/check/gst/gstminiobject.c index 9b9c1cde9..0a7a7313b 100644 --- a/tests/check/gst/gstminiobject.c +++ b/tests/check/gst/gstminiobject.c @@ -175,6 +175,33 @@ GST_START_TEST (test_unref_threaded) GST_END_TEST; +/* ======== weak ref test ======== */ + +static gboolean weak_ref_notify_succeeded = FALSE; + +static void +on_weak_ref_notify (gpointer data, GstMiniObject * where_object_was) +{ + weak_ref_notify_succeeded = TRUE; +} + +GST_START_TEST (test_weak_ref) +{ + GstBuffer *buffer; + + buffer = gst_buffer_new_and_alloc (4); + + gst_mini_object_weak_ref (GST_MINI_OBJECT (buffer), on_weak_ref_notify, + &buffer); + + gst_buffer_unref (buffer); + + fail_unless (weak_ref_notify_succeeded, + "No weak reference notification took place."); +} + +GST_END_TEST; + /* ======== recycle test ======== */ static gint recycle_buffer_count = 10; @@ -479,6 +506,7 @@ gst_mini_object_suite (void) tcase_add_test (tc_chain, test_make_writable); tcase_add_test (tc_chain, test_ref_threaded); tcase_add_test (tc_chain, test_unref_threaded); + tcase_add_test (tc_chain, test_weak_ref); tcase_add_test (tc_chain, test_recycle_threaded); tcase_add_test (tc_chain, test_value_collection); tcase_add_test (tc_chain, test_dup_null_mini_object); diff --git a/tests/check/gst/struct_arm.h b/tests/check/gst/struct_arm.h index 533674f39..23ac70ed8 100644 --- a/tests/check/gst/struct_arm.h +++ b/tests/check/gst/struct_arm.h @@ -67,7 +67,9 @@ GstCheckABIStruct list[] = { {"GstTypeFindFactoryClass", sizeof (GstTypeFindFactoryClass), 152}, {"GstURIHandlerInterface", sizeof (GstURIHandlerInterface), 44}, {"GstValueTable", sizeof (GstValueTable), 32}, +#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_DISABLE_DEPRECATED) && !defined(GST_REMOVE_DEPRECATED) {"GstXML", sizeof (GstXML), 64}, {"GstXMLClass", sizeof (GstXMLClass), 144}, +#endif {NULL, 0, 0} }; diff --git a/tests/check/pipelines/parse-launch.c b/tests/check/pipelines/parse-launch.c index 3c7fdf9f6..072ef7495 100644 --- a/tests/check/pipelines/parse-launch.c +++ b/tests/check/pipelines/parse-launch.c @@ -145,6 +145,8 @@ GST_END_TEST; #define PIPELINE11 "fakesink silent=true name = sink identity silent=true name=id ( fakesrc num-buffers=\"4\" ! id. ) id. ! sink." #define PIPELINE12 "file:///tmp/test.file ! fakesink silent=true" #define PIPELINE13 "fakesrc ! file:///tmp/test.file" +#define PIPELINE14 "capsfilter caps=application/x-rtp,sprop-parameter-sets=(string)\"x\\,x\"" +#define PIPELINE15 "capsfilter caps=application/x-rtp,sprop-parameter-sets=(string)\"x\\\"x\\,x\"" GST_START_TEST (test_launch_lines2) { @@ -285,6 +287,19 @@ GST_START_TEST (test_launch_lines2) * This should warn, but ignore the error and carry on */ cur = setup_pipeline ("( filesrc blocksize=4 location=/dev/null @ )"); gst_object_unref (cur); + + /** + * Checks if characters inside quotes are not escaped. + */ + cur = setup_pipeline (PIPELINE14); + gst_object_unref (cur); + + /** + * Checks if escaped quotes inside quotes are not treated as end string quotes. + * This would make the rest of characters to be escaped incorrectly. + */ + cur = setup_pipeline (PIPELINE15); + gst_object_unref (cur); } GST_END_TEST; diff --git a/tests/examples/manual/Makefile.am b/tests/examples/manual/Makefile.am index 8d52ba6d4..d06e0d6a6 100644 --- a/tests/examples/manual/Makefile.am +++ b/tests/examples/manual/Makefile.am @@ -18,8 +18,6 @@ TESTS_ENVIRONMENT = \ GST_PLUGIN_SYSTEM_PATH= \ GST_PLUGIN_PATH=$(top_builddir)/plugins -CLEANFILES = core core.* test-registry.* *.gcno *.gcda - EXTRA_DIST = extract.pl EXAMPLES = \ @@ -42,53 +40,53 @@ EXAMPLES = \ decodebin \ $(GST_LOADSAVE_SRC) +BUILT_SOURCES = \ + elementmake.c elementcreate.c elementget.c elementlink.c elementfactory.c \ + bin.c \ + pad.c ghostpad.c \ + gnome.c \ + helloworld.c \ + init.c \ + query.c \ + typefind.c dynamic.c \ + fakesrc.c \ + playbin.c decodebin.c + +CLEANFILES = core core.* test-registry.* *.gcno *.gcda $(BUILT_SOURCES) + AM_CFLAGS = $(GST_OBJ_CFLAGS) LDADD = $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \ $(GST_OBJ_LIBS) elementmake.c elementcreate.c elementget.c elementlink.c elementfactory.c: $(top_srcdir)/docs/manual/basics-elements.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/basics-elements.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< bin.c : $(top_srcdir)/docs/manual/basics-bins.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/basics-bins.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< pad.c ghostpad.c: $(top_srcdir)/docs/manual/basics-pads.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/basics-pads.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< gnome.c: $(top_srcdir)/docs/manual/appendix-integration.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/appendix-integration.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< helloworld.c: $(top_srcdir)/docs/manual/basics-helloworld.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/basics-helloworld.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< init.c: $(top_srcdir)/docs/manual/basics-init.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/basics-init.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< query.c: $(top_srcdir)/docs/manual/advanced-position.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/advanced-position.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< typefind.c dynamic.c: $(top_srcdir)/docs/manual/advanced-autoplugging.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/advanced-autoplugging.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< fakesrc.c: $(top_srcdir)/docs/manual/advanced-dataaccess.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/advanced-dataaccess.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< playbin.c decodebin.c: $(top_srcdir)/docs/manual/highlevel-components.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/highlevel-components.xml - -xml-mp3.c: $(top_srcdir)/docs/manual/highlevel-xml.xml - $(PERL_PATH) $(srcdir)/extract.pl $@ \ - $(top_srcdir)/docs/manual/highlevel-xml.xml + $(PERL_PATH) $(srcdir)/extract.pl $@ $< TESTS = bin \ elementcreate elementfactory elementget elementlink elementmake \ diff --git a/tools/gst-inspect.c b/tools/gst-inspect.c index c86285e68..c8f51e5dd 100644 --- a/tools/gst-inspect.c +++ b/tools/gst-inspect.c @@ -306,7 +306,7 @@ flags_to_string (GFlagsValue * vals, guint flags) --i; if (vals[i].value != 0 && (flags_left & vals[i].value) == vals[i].value) { if (s->len > 0) - g_string_append (s, " | "); + g_string_append_c (s, '+'); g_string_append (s, vals[i].value_nick); flags_left -= vals[i].value; if (flags_left == 0) diff --git a/tools/gst-launch.c b/tools/gst-launch.c index 2b0d86245..ea99b8f6d 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -403,6 +403,24 @@ print_index_stats (GPtrArray * index_stats) } } +/* Kids, use the functions from libgstpbutils in gst-plugins-base in your + * own code (we can't do that here because it would introduce a circular + * dependency) */ +static gboolean +gst_is_missing_plugin_message (GstMessage * msg) +{ + if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || msg->structure == NULL) + return FALSE; + + return gst_structure_has_name (msg->structure, "missing-plugin"); +} + +static const gchar * +gst_missing_plugin_message_get_description (GstMessage * msg) +{ + return gst_structure_get_string (msg->structure, "name"); +} + static void print_error_message (GstMessage * msg) { @@ -821,6 +839,16 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state) res = ELR_INTERRUPT; goto exit; } + break; + } + case GST_MESSAGE_ELEMENT:{ + if (gst_is_missing_plugin_message (message)) { + const gchar *desc; + + desc = gst_missing_plugin_message_get_description (message); + PRINT (_("Missing element: %s\n"), desc ? desc : "(no description)"); + } + break; } default: /* just be quiet by default */ diff --git a/win32/common/config.h b/win32/common/config.h index 28185bbcf..af2c8e5d1 100644 --- a/win32/common/config.h +++ b/win32/common/config.h @@ -59,13 +59,13 @@ #define GST_MAJORMINOR "0.10" /* package name in plugins */ -#define GST_PACKAGE_NAME "GStreamer source release" +#define GST_PACKAGE_NAME "GStreamer git" /* package origin */ #define GST_PACKAGE_ORIGIN "Unknown package origin" /* GStreamer package release date/time for plugins as YYYY-MM-DD */ -#define GST_PACKAGE_RELEASE_DATETIME "2011-06-15" +#define GST_PACKAGE_RELEASE_DATETIME "2011-06-18T12:45Z" /* location of the installed gst-plugin-scanner */ #define GST_PLUGIN_SCANNER_INSTALLED LIBDIR "\\gst-plugin-scanner" @@ -340,7 +340,7 @@ #define PACKAGE_NAME "GStreamer" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "GStreamer 0.10.35" +#define PACKAGE_STRING "GStreamer 0.10.35.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "gstreamer" @@ -349,7 +349,7 @@ #undef PACKAGE_URL /* Define to the version of this package. */ -#define PACKAGE_VERSION "0.10.35" +#define PACKAGE_VERSION "0.10.35.1" /* directory where plugins are located */ #ifdef _DEBUG @@ -380,7 +380,7 @@ #undef USE_POISONING /* Version number of package */ -#define VERSION "0.10.35" +#define VERSION "0.10.35.1" /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ diff --git a/win32/common/gstversion.h b/win32/common/gstversion.h index 53d56ec77..044b1815e 100644 --- a/win32/common/gstversion.h +++ b/win32/common/gstversion.h @@ -64,7 +64,7 @@ G_BEGIN_DECLS * The nano version of GStreamer at compile time: * Actual releases have 0, GIT versions have 1, prerelease versions have 2-... */ -#define GST_VERSION_NANO (0) +#define GST_VERSION_NANO (1) /** * GST_CHECK_VERSION: diff --git a/win32/common/libgstbase.def b/win32/common/libgstbase.def index ac43d8b5d..b2e831d08 100644 --- a/win32/common/libgstbase.def +++ b/win32/common/libgstbase.def @@ -26,6 +26,7 @@ EXPORTS gst_base_parse_set_duration gst_base_parse_set_frame_rate gst_base_parse_set_has_timing_info + gst_base_parse_set_latency gst_base_parse_set_min_frame_size gst_base_parse_set_passthrough gst_base_parse_set_syncable @@ -63,6 +64,7 @@ EXPORTS gst_base_src_query_latency gst_base_src_set_blocksize gst_base_src_set_do_timestamp + gst_base_src_set_dynamic_size gst_base_src_set_format gst_base_src_set_live gst_base_src_wait_playing diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index ca4154d98..a15e0e9ce 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -172,6 +172,7 @@ EXPORTS gst_caps_is_equal_fixed gst_caps_is_fixed gst_caps_is_subset + gst_caps_is_subset_structure gst_caps_load_thyself gst_caps_make_writable gst_caps_merge @@ -444,14 +445,21 @@ EXPORTS gst_fraction_get_type gst_fraction_range_get_type gst_g_error_get_type + gst_ghost_pad_activate_pull_default + gst_ghost_pad_activate_push_default gst_ghost_pad_construct gst_ghost_pad_get_target gst_ghost_pad_get_type + gst_ghost_pad_internal_activate_pull_default + gst_ghost_pad_internal_activate_push_default + gst_ghost_pad_link_default gst_ghost_pad_new gst_ghost_pad_new_from_template gst_ghost_pad_new_no_target gst_ghost_pad_new_no_target_from_template gst_ghost_pad_set_target + gst_ghost_pad_setcaps_default + gst_ghost_pad_unlink_default gst_implements_interface_cast gst_implements_interface_check gst_implements_interface_get_type @@ -601,6 +609,8 @@ EXPORTS gst_mini_object_ref gst_mini_object_replace gst_mini_object_unref + gst_mini_object_weak_ref + gst_mini_object_weak_unref gst_object_check_uniqueness gst_object_default_deep_notify gst_object_default_error @@ -832,7 +842,22 @@ EXPORTS gst_print_element_args gst_print_pad_caps gst_progress_type_get_type + gst_proxy_pad_acceptcaps_default + gst_proxy_pad_bufferalloc_default + gst_proxy_pad_chain_default + gst_proxy_pad_chain_list_default + gst_proxy_pad_checkgetrange_default + gst_proxy_pad_event_default + gst_proxy_pad_fixatecaps_default + gst_proxy_pad_get_internal gst_proxy_pad_get_type + gst_proxy_pad_getcaps_default + gst_proxy_pad_getrange_default + gst_proxy_pad_iterate_internal_links_default + gst_proxy_pad_query_default + gst_proxy_pad_query_type_default + gst_proxy_pad_setcaps_default + gst_proxy_pad_unlink_default gst_qos_type_get_type gst_query_add_buffering_range gst_query_get_n_buffering_ranges @@ -940,6 +965,7 @@ EXPORTS gst_stream_error_get_type gst_stream_error_quark gst_stream_status_type_get_type + gst_structure_can_intersect gst_structure_change_type_get_type gst_structure_copy gst_structure_empty_new @@ -983,6 +1009,9 @@ EXPORTS gst_structure_id_set_valist gst_structure_id_set_value gst_structure_id_take_value + gst_structure_intersect + gst_structure_is_equal + gst_structure_is_subset gst_structure_map_in_place gst_structure_n_fields gst_structure_new