summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@gnome.org>2003-11-24 02:09:23 +0000
committerBenjamin Otte <otte@gnome.org>2003-11-24 02:09:23 +0000
commit385b9ee5c46e7984f83c0be97abca57ad2af2ad3 (patch)
treed470c380699ce6c91dad34a431d312f57c0beace
parentb4f14a29f6d1fc0eea19171c61cab109ceda9d81 (diff)
merge in tagging
Original commit message from CVS: merge in tagging Includes: - gsttag.[ch] - The definition of GstTagList and tag registering/querying - gsttaginterface.[ch] - Interface for elements that can handle setting of tags - updates and merges to gststructure.[ch] and gstvalue.[ch] - testsuite/tags - some tests for tagging - bugfixes - updates to make make distcheck work - updates the version number to 0.7.2.1 Does not include: - including tagging stuff in docs - extensive tests
-rw-r--r--configure.ac7
-rw-r--r--docs/.gitignore1
-rw-r--r--docs/Makefile.am2
-rw-r--r--docs/gst/.gitignore1
-rw-r--r--docs/gst/tmpl/gstautoplug.sgml16
-rw-r--r--docs/gst/tmpl/gstbin.sgml56
-rw-r--r--docs/gst/tmpl/gstbuffer.sgml1
-rw-r--r--docs/gst/tmpl/gstcaps.sgml18
-rw-r--r--docs/gst/tmpl/gstclock.sgml20
-rw-r--r--docs/gst/tmpl/gstconfig.sgml7
-rw-r--r--docs/gst/tmpl/gstelement.sgml103
-rw-r--r--docs/gst/tmpl/gstelementfactory.sgml71
-rw-r--r--docs/gst/tmpl/gstevent.sgml1
-rw-r--r--docs/gst/tmpl/gstindex.sgml26
-rw-r--r--docs/gst/tmpl/gstinfo.sgml15
-rw-r--r--docs/gst/tmpl/gstobject.sgml82
-rw-r--r--docs/gst/tmpl/gstpadtemplate.sgml18
-rw-r--r--docs/gst/tmpl/gstplugin.sgml77
-rw-r--r--docs/gst/tmpl/gstreamer-unused.sgml202
-rw-r--r--docs/gst/tmpl/gstthread.sgml18
-rw-r--r--docs/gst/tmpl/gsttypefind.sgml14
-rw-r--r--docs/gst/tmpl/gstxml.sgml22
-rw-r--r--docs/libs/.gitignore13
-rw-r--r--examples/Makefile.am42
-rw-r--r--examples/retag/.gitignore2
-rw-r--r--examples/retag/Makefile.am7
-rw-r--r--examples/retag/retag.c103
-rw-r--r--examples/retag/transcode.c106
-rw-r--r--gst/Makefile.am14
-rw-r--r--gst/gst.c1
-rw-r--r--gst/gst.h38
-rw-r--r--gst/gstbuffer.c23
-rw-r--r--gst/gstbuffer.h5
-rw-r--r--gst/gstelement.c82
-rw-r--r--gst/gstelement.h12
-rw-r--r--gst/gstelementfactory.c31
-rw-r--r--gst/gstevent.c10
-rw-r--r--gst/gstevent.h3
-rw-r--r--gst/gstinfo.c10
-rw-r--r--gst/gstinfo.h4
-rw-r--r--gst/gststructure.c125
-rw-r--r--gst/gststructure.h36
-rw-r--r--gst/gsttag.c831
-rw-r--r--gst/gsttag.h232
-rw-r--r--gst/gsttaginterface.c214
-rw-r--r--gst/gsttaginterface.h70
-rw-r--r--gst/gsttaglist.c831
-rw-r--r--gst/gsttaglist.h232
-rw-r--r--gst/gsttagsetter.c214
-rw-r--r--gst/gsttagsetter.h70
-rw-r--r--gst/gstvalue.c318
-rw-r--r--gst/gstvalue.h37
-rw-r--r--gst/registries/gstxmlregistry.c31
-rw-r--r--libs/gst/Makefile.am4
-rw-r--r--pkgconfig/Makefile.am16
-rw-r--r--po/.gitignore6
-rw-r--r--tests/old/examples/Makefile.am42
-rw-r--r--tests/old/examples/retag/.gitignore2
-rw-r--r--tests/old/examples/retag/Makefile.am7
-rw-r--r--tests/old/examples/retag/retag.c103
-rw-r--r--tests/old/examples/retag/transcode.c106
-rw-r--r--tests/old/testsuite/Makefile.am4
-rw-r--r--tests/old/testsuite/threads/queue.c2
-rw-r--r--testsuite/Makefile.am4
-rw-r--r--testsuite/threads/queue.c2
-rw-r--r--tools/gst-launch.c36
66 files changed, 4298 insertions, 561 deletions
diff --git a/configure.ac b/configure.ac
index baa2046e0..d8d65de4d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ AC_CANONICAL_TARGET([])
dnl when going to/from release please set the nano (fourth number) right !
dnl releases only do Wall, cvs and prerelease does Werror too
-AS_VERSION(gstreamer, GST_VERSION, 0, 7, 1, 1, GST_CVS="no", GST_CVS="yes")
+AS_VERSION(gstreamer, GST_VERSION, 0, 7, 2, 1, GST_CVS="no", GST_CVS="yes")
if test x$program_suffix = xNONE ; then
program_suffix=-$GST_VERSION_MAJOR.$GST_VERSION_MINOR
@@ -615,6 +615,7 @@ testsuite/indexers/Makefile
testsuite/parse/Makefile
testsuite/plugin/Makefile
testsuite/refcounting/Makefile
+testsuite/tags/Makefile
testsuite/threads/Makefile
examples/Makefile
examples/autoplug/Makefile
@@ -630,15 +631,19 @@ examples/queue/Makefile
examples/queue2/Makefile
examples/queue3/Makefile
examples/queue4/Makefile
+examples/retag/Makefile
examples/thread/Makefile
examples/typefind/Makefile
examples/xml/Makefile
tools/Makefile
docs/Makefile
+docs/faq/Makefile
docs/gst/Makefile
docs/libs/Makefile
+docs/manual/Makefile
docs/plugins/Makefile
docs/plugins/gstreamer-plugins.types
+docs/pwg/Makefile
docs/xsl/Makefile
docs/version.entities
pkgconfig/Makefile
diff --git a/docs/.gitignore b/docs/.gitignore
index 08f5ed37d..2cd23a371 100644
--- a/docs/.gitignore
+++ b/docs/.gitignore
@@ -5,3 +5,4 @@ Makefile.in
*.la
.deps
.libs
+version.entities
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 9ff008437..892624abe 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -6,7 +6,7 @@ SUBDIRS_PLUGINS =
endif
if BUILD_DOCS
-SUBDIRS_DOCS = gst libs
+SUBDIRS_DOCS = faq manual pwg gst libs
else
SUBDIRS_DOCS =
endif
diff --git a/docs/gst/.gitignore b/docs/gst/.gitignore
index f6923174c..d785f3444 100644
--- a/docs/gst/.gitignore
+++ b/docs/gst/.gitignore
@@ -12,6 +12,7 @@ gstreamer-unused.txt
gstreamer-undocumented.txt
gstreamer-decl-list.txt
gstreamer-decl.txt
+gstreamer-presed-scan.c
gstreamer-scan.c
gstreamer-scan
gstreamer.args
diff --git a/docs/gst/tmpl/gstautoplug.sgml b/docs/gst/tmpl/gstautoplug.sgml
index 6c5bd633a..3acf7c221 100644
--- a/docs/gst/tmpl/gstautoplug.sgml
+++ b/docs/gst/tmpl/gstautoplug.sgml
@@ -99,6 +99,14 @@ The autoplug object
</para>
+<!-- ##### SIGNAL GstAutoplug::new-object ##### -->
+<para>
+
+</para>
+
+@gstautoplug: the object which received the signal.
+@arg1:
+
<!-- ##### ENUM GstAutoplugFlags ##### -->
<para>
The type of the autoplugger.
@@ -141,11 +149,3 @@ The type of the autoplugger.
@Returns:
-<!-- ##### SIGNAL GstAutoplug::new-object ##### -->
-<para>
-
-</para>
-
-@gstautoplug: the object which received the signal.
-@arg1:
-
diff --git a/docs/gst/tmpl/gstbin.sgml b/docs/gst/tmpl/gstbin.sgml
index 68c62da4b..8a0038e0b 100644
--- a/docs/gst/tmpl/gstbin.sgml
+++ b/docs/gst/tmpl/gstbin.sgml
@@ -72,6 +72,34 @@ The GstBin object
</para>
+<!-- ##### SIGNAL GstBin::element-added ##### -->
+<para>
+
+</para>
+
+@gstbin: the object which received the signal.
+@arg1: the element that was added to the bin
+
+<!-- ##### SIGNAL GstBin::element-removed ##### -->
+<para>
+
+</para>
+
+@gstbin: the object which received the signal.
+@arg1: the element that was removed from the bin
+
+<!-- ##### SIGNAL GstBin::iterate ##### -->
+<para>
+This signal is emitted when a bin iterates, either automatically or
+due to a #gst_bin_iterate() call. The return value is used to
+determine if the object method handler processed any data.
+In most normal cases, a user-provided signal handler should return
+FALSE.
+</para>
+
+@gstbin: the object which received the signal.
+@Returns: TRUE if the state of the bin was advanced.
+
<!-- ##### USER_FUNCTION GstBinPrePostIterateFunction ##### -->
<para>
The signature of the callback for the post and pre iterate function as set with
@@ -224,31 +252,3 @@ gst_bin_set_pre_iterate_function() and gst_bin_set_post_iterate_function().
@clock:
-<!-- ##### SIGNAL GstBin::element-added ##### -->
-<para>
-
-</para>
-
-@gstbin: the object which received the signal.
-@arg1: the element that was added to the bin
-
-<!-- ##### SIGNAL GstBin::element-removed ##### -->
-<para>
-
-</para>
-
-@gstbin: the object which received the signal.
-@arg1: the element that was removed from the bin
-
-<!-- ##### SIGNAL GstBin::iterate ##### -->
-<para>
-This signal is emitted when a bin iterates, either automatically or
-due to a #gst_bin_iterate() call. The return value is used to
-determine if the object method handler processed any data.
-In most normal cases, a user-provided signal handler should return
-FALSE.
-</para>
-
-@gstbin: the object which received the signal.
-@Returns: TRUE if the state of the bin was advanced.
-
diff --git a/docs/gst/tmpl/gstbuffer.sgml b/docs/gst/tmpl/gstbuffer.sgml
index 824c1e5b1..c9474ec5a 100644
--- a/docs/gst/tmpl/gstbuffer.sgml
+++ b/docs/gst/tmpl/gstbuffer.sgml
@@ -262,6 +262,7 @@ The basic structure of a buffer.
@timestamp:
@duration:
@offset:
+@offset_end:
@pool:
@pool_private:
diff --git a/docs/gst/tmpl/gstcaps.sgml b/docs/gst/tmpl/gstcaps.sgml
index 65f1399c4..8cb1606a5 100644
--- a/docs/gst/tmpl/gstcaps.sgml
+++ b/docs/gst/tmpl/gstcaps.sgml
@@ -406,24 +406,6 @@ The name used for tracing
@Returns:
-<!-- ##### FUNCTION gst_caps_set_type_id ##### -->
-<para>
-
-</para>
-
-@caps:
-@type_id:
-
-
-<!-- ##### FUNCTION gst_caps_get_type_id ##### -->
-<para>
-
-</para>
-
-@caps:
-@Returns:
-
-
<!-- ##### FUNCTION gst_caps_set_mime ##### -->
<para>
diff --git a/docs/gst/tmpl/gstclock.sgml b/docs/gst/tmpl/gstclock.sgml
index da3b74816..ae2cf0de7 100644
--- a/docs/gst/tmpl/gstclock.sgml
+++ b/docs/gst/tmpl/gstclock.sgml
@@ -235,6 +235,16 @@ The GstClock object
</para>
+<!-- ##### ARG GstClock:max-diff ##### -->
+<para>
+Maximum allowed diff for clock sync requests against the real time.
+</para>
+
+<!-- ##### ARG GstClock:stats ##### -->
+<para>
+Boolean property to activate stat generation on the clock.
+</para>
+
<!-- ##### FUNCTION gst_clock_set_speed ##### -->
<para>
@@ -402,13 +412,3 @@ The GstClock object
@id:
-<!-- ##### ARG GstClock:max-diff ##### -->
-<para>
-Maximum allowed diff for clock sync requests against the real time.
-</para>
-
-<!-- ##### ARG GstClock:stats ##### -->
-<para>
-Boolean property to activate stat generation on the clock.
-</para>
-
diff --git a/docs/gst/tmpl/gstconfig.sgml b/docs/gst/tmpl/gstconfig.sgml
index 26c2e3386..99b80335d 100644
--- a/docs/gst/tmpl/gstconfig.sgml
+++ b/docs/gst/tmpl/gstconfig.sgml
@@ -108,13 +108,6 @@ If this is defined, the <link linkend="gstreamer-gstinfo">debugging subsystem
-<!-- ##### MACRO GST_DISABLE_TYPEFIND ##### -->
-<para>
-
-</para>
-
-
-
<!-- ##### MACRO GST_DISABLE_URI ##### -->
<para>
diff --git a/docs/gst/tmpl/gstelement.sgml b/docs/gst/tmpl/gstelement.sgml
index c06cdbd90..4ce8a7bea 100644
--- a/docs/gst/tmpl/gstelement.sgml
+++ b/docs/gst/tmpl/gstelement.sgml
@@ -71,6 +71,58 @@ The element object
</para>
+<!-- ##### SIGNAL GstElement::eos ##### -->
+<para>
+Signal emited when the element goes to PAUSED due to an end-of-stream
+condition.
+</para>
+
+@gstelement: the object which received the signal.
+
+<!-- ##### SIGNAL GstElement::error ##### -->
+<para>
+Is triggered whenever an error occured.
+
+</para>
+
+@gstelement: the object which received the signal.
+@arg1: the error message
+@arg2:
+
+<!-- ##### SIGNAL GstElement::found-tag ##### -->
+<para>
+
+</para>
+
+@gstelement: the object which received the signal.
+@arg1:
+@arg2:
+
+<!-- ##### SIGNAL GstElement::new-pad ##### -->
+<para>
+Is triggered whenever a new pad is added to an element.
+</para>
+
+@gstelement: the object which received the signal.
+@arg1: the new pad that was added
+
+<!-- ##### SIGNAL GstElement::pad-removed ##### -->
+<para>
+Is triggered whenever a pad has been removed from the element.
+</para>
+
+@gstelement: the object which received the signal.
+@arg1: The pad that was removed.
+
+<!-- ##### SIGNAL GstElement::state-change ##### -->
+<para>
+Is triggered whenever the state of an element changes.
+</para>
+
+@gstelement: the object which received the signal.
+@arg1: the new state of the object
+@arg2:
+
<!-- ##### MACRO gst_element_get_name ##### -->
<para>
Gets the name of the element.
@@ -880,14 +932,6 @@ Queries if the Element is decoupled.
@obj: a #GstElement to query
-<!-- ##### MACRO GST_ELEMENT_IS_EOS ##### -->
-<para>
-Query wether this element is in the End Of Stream state.
-</para>
-
-@obj: a #GstElement to query
-
-
<!-- ##### MACRO GST_ELEMENT_IS_EVENT_AWARE ##### -->
<para>
Query wether this element can handle events.
@@ -971,46 +1015,3 @@ Helper macro to create query type functions
@...: list of query types.
-<!-- ##### SIGNAL GstElement::eos ##### -->
-<para>
-Signal emited when the element goes to PAUSED due to an end-of-stream
-condition.
-</para>
-
-@gstelement: the object which received the signal.
-
-<!-- ##### SIGNAL GstElement::error ##### -->
-<para>
-Is triggered whenever an error occured.
-
-</para>
-
-@gstelement: the object which received the signal.
-@arg1: the error message
-@arg2:
-
-<!-- ##### SIGNAL GstElement::new-pad ##### -->
-<para>
-Is triggered whenever a new pad is added to an element.
-</para>
-
-@gstelement: the object which received the signal.
-@arg1: the new pad that was added
-
-<!-- ##### SIGNAL GstElement::pad-removed ##### -->
-<para>
-Is triggered whenever a pad has been removed from the element.
-</para>
-
-@gstelement: the object which received the signal.
-@arg1: The pad that was removed.
-
-<!-- ##### SIGNAL GstElement::state-change ##### -->
-<para>
-Is triggered whenever the state of an element changes.
-</para>
-
-@gstelement: the object which received the signal.
-@arg1: the new state of the object
-@arg2:
-
diff --git a/docs/gst/tmpl/gstelementfactory.sgml b/docs/gst/tmpl/gstelementfactory.sgml
index eddebe8f0..6e6cfe15c 100644
--- a/docs/gst/tmpl/gstelementfactory.sgml
+++ b/docs/gst/tmpl/gstelementfactory.sgml
@@ -62,22 +62,8 @@ describes the element, mostly for the benefit of editors.
@longname:
@klass:
-@license:
@description:
-@version:
@author:
-@copyright:
-
-<!-- ##### FUNCTION gst_element_factory_new ##### -->
-<para>
-
-</para>
-
-@name:
-@type:
-@details:
-@Returns:
-
<!-- ##### FUNCTION gst_element_factory_find ##### -->
<para>
@@ -88,15 +74,6 @@ describes the element, mostly for the benefit of editors.
@Returns:
-<!-- ##### FUNCTION gst_element_factory_add_pad_template ##### -->
-<para>
-
-</para>
-
-@elementfactory:
-@templ:
-
-
<!-- ##### FUNCTION gst_element_factory_can_src_caps ##### -->
<para>
@@ -137,51 +114,3 @@ describes the element, mostly for the benefit of editors.
@Returns:
-<!-- ##### FUNCTION gst_element_factory_make_or_warn ##### -->
-<para>
-
-</para>
-
-@factoryname:
-@name:
-@Returns:
-
-
-<!-- ##### MACRO gst_element_factory_set_rank ##### -->
-<para>
-
-</para>
-
-@factory:
-@rank:
-
-
-<!-- ##### MACRO GST_ELEMENT_RANK_MARGINAL ##### -->
-<para>
-The element is only marginally usefull for autoplugging
-</para>
-
-
-
-<!-- ##### MACRO GST_ELEMENT_RANK_NONE ##### -->
-<para>
-The plugin may not be used in autoplugging
-</para>
-
-
-
-<!-- ##### MACRO GST_ELEMENT_RANK_PRIMARY ##### -->
-<para>
-The plugin is well suited for autoplugging
-</para>
-
-
-
-<!-- ##### MACRO GST_ELEMENT_RANK_SECONDARY ##### -->
-<para>
-The plugin is suited for autoplugging but only as a second
-candidate.
-</para>
-
-
-
diff --git a/docs/gst/tmpl/gstevent.sgml b/docs/gst/tmpl/gstevent.sgml
index a32604f5c..11467fecd 100644
--- a/docs/gst/tmpl/gstevent.sgml
+++ b/docs/gst/tmpl/gstevent.sgml
@@ -48,6 +48,7 @@ The different major types of events.
@GST_EVENT_INTERRUPT: mainly used by _get based elements when they were interrupted
while waiting for a buffer.
@GST_EVENT_NAVIGATION:
+@GST_EVENT_TAG:
<!-- ##### MACRO GST_EVENT_TYPE ##### -->
<para>
diff --git a/docs/gst/tmpl/gstindex.sgml b/docs/gst/tmpl/gstindex.sgml
index d828fa311..cdc3cfa10 100644
--- a/docs/gst/tmpl/gstindex.sgml
+++ b/docs/gst/tmpl/gstindex.sgml
@@ -209,6 +209,19 @@ The GstIndex object
</para>
+<!-- ##### SIGNAL GstIndex::entry-added ##### -->
+<para>
+Is emited when a new entry is added to the index.
+</para>
+
+@gstindex: the object which received the signal.
+@arg1: The entry added to the index.
+
+<!-- ##### ARG GstIndex:resolver ##### -->
+<para>
+
+</para>
+
<!-- ##### FUNCTION gst_index_new ##### -->
<para>
@@ -401,16 +414,3 @@ The GstIndex object
@id:
-<!-- ##### SIGNAL GstIndex::entry-added ##### -->
-<para>
-Is emited when a new entry is added to the index.
-</para>
-
-@gstindex: the object which received the signal.
-@arg1: The entry added to the index.
-
-<!-- ##### ARG GstIndex:resolver ##### -->
-<para>
-
-</para>
-
diff --git a/docs/gst/tmpl/gstinfo.sgml b/docs/gst/tmpl/gstinfo.sgml
index e2650f43c..3ae7489d6 100644
--- a/docs/gst/tmpl/gstinfo.sgml
+++ b/docs/gst/tmpl/gstinfo.sgml
@@ -233,21 +233,6 @@ default. If you want to define a default category, do it like this:
@Varargs:
-<!-- ##### FUNCTION gst_debug_logv ##### -->
-<para>
-
-</para>
-
-@category:
-@level:
-@file:
-@function:
-@line:
-@object:
-@format:
-@args:
-
-
<!-- ##### FUNCTION gst_debug_log_default ##### -->
<para>
diff --git a/docs/gst/tmpl/gstobject.sgml b/docs/gst/tmpl/gstobject.sgml
index 52616a221..cf69ab93e 100644
--- a/docs/gst/tmpl/gstobject.sgml
+++ b/docs/gst/tmpl/gstobject.sgml
@@ -40,6 +40,47 @@ The GstObject
</para>
+<!-- ##### SIGNAL GstObject::deep-notify ##### -->
+<para>
+The deep notify signal is used to be notified of property changes.
+it is typically attached to the toplevel bin to receive notifications
+from all the elements contained in that bin.
+</para>
+
+@gstobject: the object which received the signal.
+@arg1: the object that originated the signal
+@arg2: the property that changed
+
+<!-- ##### SIGNAL GstObject::object-saved ##### -->
+<para>
+Is trigered whenever a new object is saved to XML. You can connect to
+this signal to insert custom XML tags into the core XML.
+</para>
+
+@gstobject: the object which received the signal.
+@arg1: the xmlNodePtr of the parent node
+
+<!-- ##### SIGNAL GstObject::parent-set ##### -->
+<para>
+Is emitted when the parent of an object is set.
+</para>
+
+@gstobject: the object which received the signal.
+@arg1: the new parent
+
+<!-- ##### SIGNAL GstObject::parent-unset ##### -->
+<para>
+Is emitted when the parent of an object is unset.
+</para>
+
+@gstobject: the object which received the signal.
+@arg1: the old parent
+
+<!-- ##### ARG GstObject:name ##### -->
+<para>
+The name of the object
+</para>
+
<!-- ##### MACRO GST_FLAGS ##### -->
<para>
This macro returns the entire set of flags for the object.
@@ -290,44 +331,3 @@ Check if the object has been destroyed.
@Returns:
-<!-- ##### SIGNAL GstObject::deep-notify ##### -->
-<para>
-The deep notify signal is used to be notified of property changes.
-it is typically attached to the toplevel bin to receive notifications
-from all the elements contained in that bin.
-</para>
-
-@gstobject: the object which received the signal.
-@arg1: the object that originated the signal
-@arg2: the property that changed
-
-<!-- ##### SIGNAL GstObject::object-saved ##### -->
-<para>
-Is trigered whenever a new object is saved to XML. You can connect to
-this signal to insert custom XML tags into the core XML.
-</para>
-
-@gstobject: the object which received the signal.
-@arg1: the xmlNodePtr of the parent node
-
-<!-- ##### SIGNAL GstObject::parent-set ##### -->
-<para>
-Is emitted when the parent of an object is set.
-</para>
-
-@gstobject: the object which received the signal.
-@arg1: the new parent
-
-<!-- ##### SIGNAL GstObject::parent-unset ##### -->
-<para>
-Is emitted when the parent of an object is unset.
-</para>
-
-@gstobject: the object which received the signal.
-@arg1: the old parent
-
-<!-- ##### ARG GstObject:name ##### -->
-<para>
-The name of the object
-</para>
-
diff --git a/docs/gst/tmpl/gstpadtemplate.sgml b/docs/gst/tmpl/gstpadtemplate.sgml
index f26e9c5f1..0396557ef 100644
--- a/docs/gst/tmpl/gstpadtemplate.sgml
+++ b/docs/gst/tmpl/gstpadtemplate.sgml
@@ -87,6 +87,15 @@ The padtemplate object.
</para>
+<!-- ##### SIGNAL GstPadTemplate::pad-created ##### -->
+<para>
+This signal is fired when an element creates a pad from this
+template.
+</para>
+
+@gstpadtemplate: the object which received the signal.
+@arg1: The pad that was created.
+
<!-- ##### ENUM GstPadTemplateFlags ##### -->
<para>
Flags for the padtemplate
@@ -199,12 +208,3 @@ Check if the properties of the padtemplate are fixed
@Returns:
-<!-- ##### SIGNAL GstPadTemplate::pad-created ##### -->
-<para>
-This signal is fired when an element creates a pad from this
-template.
-</para>
-
-@gstpadtemplate: the object which received the signal.
-@arg1: The pad that was created.
-
diff --git a/docs/gst/tmpl/gstplugin.sgml b/docs/gst/tmpl/gstplugin.sgml
index bd8e9ba32..30dc50fc7 100644
--- a/docs/gst/tmpl/gstplugin.sgml
+++ b/docs/gst/tmpl/gstplugin.sgml
@@ -56,20 +56,19 @@ The plugin loading errors
@GST_PLUGIN_ERROR_MODULE: The plugin could not be loaded
@GST_PLUGIN_ERROR_DEPENDENCIES: The plugin has unresolved dependencies
+@GST_PLUGIN_ERROR_NAME_MISMATCH:
<!-- ##### STRUCT GstPlugin ##### -->
<para>
The plugin object
</para>
-@name:
-@longname:
+@desc:
@filename:
@features:
@numfeatures:
@manager:
@module:
-@init_called:
<!-- ##### USER_FUNCTION GstPluginInitFunc ##### -->
<para>
@@ -77,9 +76,10 @@ A plugin should provide a pointer to a function of this type in the plugin_desc
It will be called by the loader at statup.
</para>
-@module: The <classname>GModule</classname> it was loaded from
@plugin: The plugin object that can be used to register stuff for this plugin.
@Returns: A boolean indicating success or failure.
+<!-- # Unused Parameters # -->
+@module: The <classname>GModule</classname> it was loaded from
<!-- ##### STRUCT GstPluginDesc ##### -->
@@ -91,50 +91,14 @@ loaded will use this variable to initialize the plugin.
@major_version: The minor version of the gstreamer library this plugin was created with
@minor_version: The minor version of the gstreamer library this plugin was created with
@name: The name of the plugin
+@description:
@plugin_init: The init function of this plugin.
-
-<!-- ##### MACRO GST_PLUGIN_DESC ##### -->
-<para>
-A handy macro to define a plugin description. This macro handles with all the issues
-involved with the different linking methods for this plugin.
-</para>
-
-@major: The major version of GStreamer this plugin was compiled against.
-@minor: The minor version of GStreamer this plugin was compiled against.
-@name: The name of the plugin.
-@init: The init function of this plugin.
-
-
-<!-- ##### MACRO GST_PLUGIN_DESC_DYNAMIC ##### -->
-<para>
-The macro used to define dynamically loaded plugins.
-</para>
-
-@major: The major version of GStreamer this plugin was compiled against.
-@minor: The minor version of GStreamer this plugin was compiled against.
-@name: The name of the plugin.
-@init: The init function of this plugin.
-
-
-<!-- ##### MACRO GST_PLUGIN_DESC_STATIC ##### -->
-<para>
-A macro used to define a statically linked plugin.
-</para>
-
-@major: The major version of GStreamer this plugin was compiled against.
-@minor: The minor version of GStreamer this plugin was compiled against.
-@name: The name of the plugin.
-@init: The init function of this plugin.
-
-
-<!-- ##### FUNCTION gst_plugin_new ##### -->
-<para>
-
-</para>
-
-@filename:
-@Returns:
-
+@plugin_exit:
+@version:
+@license:
+@copyright:
+@package:
+@origin:
<!-- ##### FUNCTION gst_plugin_set_name ##### -->
<para>
@@ -163,15 +127,6 @@ A macro used to define a statically linked plugin.
@Returns:
-<!-- ##### FUNCTION gst_plugin_set_longname ##### -->
-<para>
-
-</para>
-
-@plugin:
-@longname:
-
-
<!-- ##### FUNCTION gst_plugin_get_filename ##### -->
<para>
@@ -210,16 +165,6 @@ A macro used to define a statically linked plugin.
@Returns:
-<!-- ##### FUNCTION gst_plugin_load_plugin ##### -->
-<para>
-
-</para>
-
-@plugin:
-@error:
-@Returns:
-
-
<!-- ##### FUNCTION gst_plugin_unload_plugin ##### -->
<para>
diff --git a/docs/gst/tmpl/gstreamer-unused.sgml b/docs/gst/tmpl/gstreamer-unused.sgml
index 2b293643a..7110bc58b 100644
--- a/docs/gst/tmpl/gstreamer-unused.sgml
+++ b/docs/gst/tmpl/gstreamer-unused.sgml
@@ -1056,27 +1056,6 @@ Cache time and byteoffsets.
GstTimeCache
-<!-- ##### SECTION ./tmpl/gsttypefind.sgml:Long_Description ##### -->
-<para>
-This element can be added to the pipeline and will notify the listener of
-the detected mime type of the stream. It is used in autoplugging.
-</para>
-
-
-<!-- ##### SECTION ./tmpl/gsttypefind.sgml:See_Also ##### -->
-<para>
-
-</para>
-
-
-<!-- ##### SECTION ./tmpl/gsttypefind.sgml:Short_Description ##### -->
-Detect the mime type of a media stream
-
-
-<!-- ##### SECTION ./tmpl/gsttypefind.sgml:Title ##### -->
-GstTypeFind
-
-
<!-- ##### SECTION ./tmpl/gsttypes.sgml:Long_Description ##### -->
<para>
@@ -1835,6 +1814,12 @@ to the current function, i.e. "('element')"
@format: printf-style format string
@args...: printf arguments
+<!-- ##### MACRO GST_DISABLE_TYPEFIND ##### -->
+<para>
+
+</para>
+
+
<!-- ##### MACRO GST_DISKSRC ##### -->
<para>
@@ -1898,6 +1883,13 @@ Queries whether the cothread holding this element needs to be stopped.
@obj: The element to query
+<!-- ##### MACRO GST_ELEMENT_IS_EOS ##### -->
+<para>
+Query wether this element is in the End Of Stream state.
+</para>
+
+@obj: a #GstElement to query
+
<!-- ##### MACRO GST_ELEMENT_IS_MULTI_IN ##### -->
<para>
Query whether this object has multiple input pads.
@@ -1906,6 +1898,31 @@ Query whether this object has multiple input pads.
@obj: Element to query for multiple input pads.
+<!-- ##### MACRO GST_ELEMENT_RANK_MARGINAL ##### -->
+<para>
+The element is only marginally usefull for autoplugging
+</para>
+
+
+<!-- ##### MACRO GST_ELEMENT_RANK_NONE ##### -->
+<para>
+The plugin may not be used in autoplugging
+</para>
+
+
+<!-- ##### MACRO GST_ELEMENT_RANK_PRIMARY ##### -->
+<para>
+The plugin is well suited for autoplugging
+</para>
+
+
+<!-- ##### MACRO GST_ELEMENT_RANK_SECONDARY ##### -->
+<para>
+The plugin is suited for autoplugging but only as a second
+candidate.
+</para>
+
+
<!-- ##### MACRO GST_ESDSINK ##### -->
<para>
@@ -2769,6 +2786,37 @@ Get the flag indicating the properties are fixed from the template.
@plugin:
+<!-- ##### MACRO GST_PLUGIN_DESC ##### -->
+<para>
+A handy macro to define a plugin description. This macro handles with all the issues
+involved with the different linking methods for this plugin.
+</para>
+
+@major: The major version of GStreamer this plugin was compiled against.
+@minor: The minor version of GStreamer this plugin was compiled against.
+@name: The name of the plugin.
+@init: The init function of this plugin.
+
+<!-- ##### MACRO GST_PLUGIN_DESC_DYNAMIC ##### -->
+<para>
+The macro used to define dynamically loaded plugins.
+</para>
+
+@major: The major version of GStreamer this plugin was compiled against.
+@minor: The minor version of GStreamer this plugin was compiled against.
+@name: The name of the plugin.
+@init: The init function of this plugin.
+
+<!-- ##### MACRO GST_PLUGIN_DESC_STATIC ##### -->
+<para>
+A macro used to define a statically linked plugin.
+</para>
+
+@major: The major version of GStreamer this plugin was compiled against.
+@minor: The minor version of GStreamer this plugin was compiled against.
+@name: The name of the plugin.
+@init: The init function of this plugin.
+
<!-- ##### MACRO GST_PROPS_BOOL_ID ##### -->
<para>
@@ -5717,6 +5765,15 @@ Query the element for the current mime type
</para>
+<!-- ##### SIGNAL GstXML::object-loaded ##### -->
+<para>
+
+</para>
+
+@gstxml: the object which received the signal.
+@arg1:
+@arg2:
+
<!-- ##### USER_FUNCTION GstXMLRegistryAddPathList ##### -->
<para>
@@ -7704,6 +7761,14 @@ safely be modified.
@caps:
+<!-- ##### FUNCTION gst_caps_get_type_id ##### -->
+<para>
+
+</para>
+
+@caps:
+@Returns:
+
<!-- ##### FUNCTION gst_caps_list_check_compatibility ##### -->
<para>
@@ -7741,6 +7806,14 @@ safely be modified.
@Returns:
@count:
+<!-- ##### FUNCTION gst_caps_set_type_id ##### -->
+<para>
+
+</para>
+
+@caps:
+@type_id:
+
<!-- ##### FUNCTION gst_clock_activate ##### -->
<para>
@@ -7915,6 +7988,20 @@ safely be modified.
@data:
@Returns:
+<!-- ##### FUNCTION gst_debug_logv ##### -->
+<para>
+
+</para>
+
+@category:
+@level:
+@file:
+@function:
+@line:
+@object:
+@format:
+@args:
+
<!-- ##### FUNCTION gst_debug_print_stack_trace ##### -->
<para>
@@ -7998,6 +8085,14 @@ of an element he doesn't need anymore.
@a:
@b:
+<!-- ##### FUNCTION gst_element_factory_add_pad_template ##### -->
+<para>
+
+</para>
+
+@elementfactory:
+@templ:
+
<!-- ##### FUNCTION gst_element_factory_add_sink ##### -->
<para>
@@ -8054,6 +8149,25 @@ of an element he doesn't need anymore.
@parent:
@Returns:
+<!-- ##### FUNCTION gst_element_factory_make_or_warn ##### -->
+<para>
+
+</para>
+
+@factoryname:
+@name:
+@Returns:
+
+<!-- ##### FUNCTION gst_element_factory_new ##### -->
+<para>
+
+</para>
+
+@name:
+@type:
+@details:
+@Returns:
+
<!-- ##### FUNCTION gst_element_factory_register ##### -->
<para>
@@ -8070,6 +8184,14 @@ of an element he doesn't need anymore.
@parent:
@Returns:
+<!-- ##### MACRO gst_element_factory_set_rank ##### -->
+<para>
+
+</para>
+
+@factory:
+@rank:
+
<!-- ##### FUNCTION gst_element_flags_get_type ##### -->
<para>
@@ -9294,6 +9416,15 @@ Destroys the pipeline.
@name:
@Returns:
+<!-- ##### FUNCTION gst_plugin_load_plugin ##### -->
+<para>
+
+</para>
+
+@plugin:
+@error:
+@Returns:
+
<!-- ##### FUNCTION gst_plugin_load_thyself ##### -->
<para>
@@ -9308,6 +9439,14 @@ Destroys the pipeline.
@mime:
+<!-- ##### FUNCTION gst_plugin_new ##### -->
+<para>
+
+</para>
+
+@filename:
+@Returns:
+
<!-- ##### FUNCTION gst_plugin_save_thyself ##### -->
<para>
@@ -9316,6 +9455,14 @@ Destroys the pipeline.
@parent:
@Returns:
+<!-- ##### FUNCTION gst_plugin_set_longname ##### -->
+<para>
+
+</para>
+
+@plugin:
+@longname:
+
<!-- ##### FUNCTION gst_plugin_unload_all ##### -->
<para>
@@ -10040,6 +10187,19 @@ Destroy the scheduler
</para>
+<!-- ##### FUNCTION gst_type_find_factory_register ##### -->
+<para>
+
+</para>
+
+@plugin:
+@name:
+@rank:
+@func:
+@extensions:
+@possible_caps:
+@data:
+
<!-- ##### FUNCTION gst_type_get_sink_to_src ##### -->
<para>
diff --git a/docs/gst/tmpl/gstthread.sgml b/docs/gst/tmpl/gstthread.sgml
index 6d7021906..38a7691b0 100644
--- a/docs/gst/tmpl/gstthread.sgml
+++ b/docs/gst/tmpl/gstthread.sgml
@@ -34,15 +34,6 @@ The GstThread object
</para>
-<!-- ##### FUNCTION gst_thread_new ##### -->
-<para>
-
-</para>
-
-@name:
-@Returns:
-
-
<!-- ##### SIGNAL GstThread::shutdown ##### -->
<para>
@@ -55,3 +46,12 @@ The GstThread object
The thread priority
</para>
+<!-- ##### FUNCTION gst_thread_new ##### -->
+<para>
+
+</para>
+
+@name:
+@Returns:
+
+
diff --git a/docs/gst/tmpl/gsttypefind.sgml b/docs/gst/tmpl/gsttypefind.sgml
index 10ae8f64b..6cd2b8bb8 100644
--- a/docs/gst/tmpl/gsttypefind.sgml
+++ b/docs/gst/tmpl/gsttypefind.sgml
@@ -98,17 +98,3 @@ gst_type_find_factory_register()
@Returns:
-<!-- ##### FUNCTION gst_type_find_factory_register ##### -->
-<para>
-
-</para>
-
-@plugin:
-@name:
-@rank:
-@func:
-@extensions:
-@possible_caps:
-@data:
-
-
diff --git a/docs/gst/tmpl/gstxml.sgml b/docs/gst/tmpl/gstxml.sgml
index 08450b21b..ea4e4bd24 100644
--- a/docs/gst/tmpl/gstxml.sgml
+++ b/docs/gst/tmpl/gstxml.sgml
@@ -105,25 +105,3 @@ All GstElements can be serialized to an XML presentation and subsequently loaded
@Returns:
-<!-- ##### SIGNAL GstXML::object-loaded ##### -->
-<para>
-
-</para>
-
-@:
-@:
-@:
-
-@gstxml: the object which received the signal.
-@arg1:
-@arg2:
-
-<!-- ##### SIGNAL GstXML::object-loaded ##### -->
-<para>
-
-</para>
-
-@gstxml: the object which received the signal.
-@arg1:
-@arg2:
-
diff --git a/docs/libs/.gitignore b/docs/libs/.gitignore
index 30446aa26..c20d3bb02 100644
--- a/docs/libs/.gitignore
+++ b/docs/libs/.gitignore
@@ -1,12 +1,15 @@
-Makefile
-Makefile.in
+*.stamp
html
xml
-gstreamer-libs-unused.txt
-gstreamer-libs-undocumented.txt
+Makefile
+Makefile.in
gstreamer-libs-decl.txt
gstreamer-libs-decl-list.txt
-*.stamp
+gstreamer-libs-presed-scan.c
+gstreamer-libs-undocumented.txt
+gstreamer-libs-unused.txt
gstreamer-libs.args
gstreamer-libs.hierarchy
+gstreamer-libs.interfaces
+gstreamer-libs.prerequisites
gstreamer-libs.signals
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 9751930a0..69a0458e6 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -10,13 +10,39 @@ else
GST_AUTOPLUG_DIRS = autoplug helloworld2
endif
-SUBDIRS = $(GST_AUTOPLUG_DIRS) $(GST_LOADSAVE_DIRS) \
- helloworld \
- queue queue2 queue3 queue4 \
- launch thread plugins mixer cutter pingpong manual
+SUBDIRS = \
+ helloworld \
+ queue \
+ queue2 \
+ queue3 \
+ queue4 \
+ launch \
+ thread \
+ plugins \
+ mixer \
+ cutter \
+ pingpong \
+ manual \
+ retag \
+ $(GST_LOADSAVE_DIRS) \
+ $(GST_AUTOPLUG_DIRS)
-DIST_SUBDIRS = autoplug \
- helloworld helloworld2 \
- queue queue2 queue3 queue4 \
- launch thread xml plugins typefind mixer cutter pingpong manual
+
+DIST_SUBDIRS = autoplug \
+ helloworld \
+ helloworld2 \
+ queue \
+ queue2 \
+ queue3 \
+ queue4 \
+ launch \
+ thread \
+ plugins \
+ mixer \
+ cutter \
+ pingpong \
+ manual \
+ xml \
+ typefind \
+ retag
diff --git a/examples/retag/.gitignore b/examples/retag/.gitignore
new file mode 100644
index 000000000..a54ae58a5
--- /dev/null
+++ b/examples/retag/.gitignore
@@ -0,0 +1,2 @@
+retag
+transcode
diff --git a/examples/retag/Makefile.am b/examples/retag/Makefile.am
new file mode 100644
index 000000000..6a686a51e
--- /dev/null
+++ b/examples/retag/Makefile.am
@@ -0,0 +1,7 @@
+noinst_PROGRAMS = retag transcode
+
+retag_LDADD = $(GST_LIBS)
+retag_CFLAGS = $(GST_CFLAGS)
+
+transcode_LDADD = $(GST_LIBS)
+transcode_CFLAGS = $(GST_CFLAGS)
diff --git a/examples/retag/retag.c b/examples/retag/retag.c
new file mode 100644
index 000000000..2824ba724
--- /dev/null
+++ b/examples/retag/retag.c
@@ -0,0 +1,103 @@
+/*
+ * This example shows how to use interfaces and the tag subsystem.
+ * It takes an mp3 file as input, and makes an ogg file out of it. While doing
+ * this, it parses the filename and sets artist and title in the ogg file.
+ * It assumes the filename to be "<artist> - <title>.mp3"
+ *
+ * Run the program as "retag <mp3 file>"
+ *
+ * To run this program, you need to have the gst-plugins package (specifically
+ * the vorbis and mad plugins) installed.
+ */
+
+/* main header */
+#include <gst/gst.h>
+/* and a header we need for the string manipulation */
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *bin, *filesrc, *tag_changer, *filesink;
+ gchar *artist, *title, *ext, *filename;
+
+ /* check that the argument is there */
+ if (argc != 2) {
+ g_print ("usage: %s <mp3 file>\n", argv[0]);
+ return 1;
+ }
+
+ /* initialize GStreamer */
+ gst_init (&argc, &argv);
+
+ /* parse the mp3 name */
+ artist = strrchr (argv[1], '/');
+ if (artist == NULL)
+ artist = argv[1];
+ artist = g_strdup (artist);
+ ext = strrchr (artist, '.');
+ if (ext) *ext = '\0';
+ title = strstr (artist, " - ");
+ if (title == NULL) {
+ g_print ("The format of the mp3 file is invalid.\n");
+ return 1;
+ }
+ *title = '\0';
+ title += 3;
+
+
+ /* create a new bin to hold the elements */
+ bin = gst_pipeline_new ("pipeline");
+ g_assert (bin);
+
+ /* create a file reader */
+ filesrc = gst_element_factory_make ("filesrc", "disk_source");
+ g_assert (filesrc);
+
+ /* now it's time to get the tag_changer */
+ tag_changer = gst_element_factory_make ("id3tag", "tag_changer");
+ if (!tag_changer) {
+ g_print ("could not find plugin \"mad\"");
+ return 1;
+ }
+
+ /* and a file writer */
+ filesink = gst_element_factory_make ("filesink", "filesink");
+ g_assert (filesink);
+
+ /* set the filenames */
+ filename = g_strdup_printf ("%s.temp", argv[1]); /* easy solution */
+ g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
+ g_object_set (G_OBJECT (filesink), "location", filename, NULL);
+
+ /* make sure the tag setter uses our stuff
+ (though that should already be default) */
+ gst_tag_setter_set_merge_mode (GST_TAG_SETTER (tag_changer), GST_TAG_MERGE_KEEP);
+ /* set the tagging information */
+ gst_tag_setter_add (GST_TAG_SETTER (tag_changer), GST_TAG_MERGE_REPLACE,
+ GST_TAG_ARTIST, artist,
+ GST_TAG_TITLE, title,
+ NULL);
+
+ /* add objects to the main pipeline */
+ gst_bin_add_many (GST_BIN (bin), filesrc, tag_changer, filesink, NULL);
+
+ /* link the elements */
+ gst_element_link_many (filesrc, tag_changer, filesink, NULL);
+
+ /* start playing */
+ gst_element_set_state (bin, GST_STATE_PLAYING);
+
+ while (gst_bin_iterate (GST_BIN (bin)));
+
+ /* stop the bin */
+ gst_element_set_state (bin, GST_STATE_NULL);
+
+ /* rename the file to the correct name and remove the old one */
+ remove (argv[1]);
+ rename (filename, argv[1]);
+ g_free (filename);
+
+ return 0;
+}
+
diff --git a/examples/retag/transcode.c b/examples/retag/transcode.c
new file mode 100644
index 000000000..c41f96ed8
--- /dev/null
+++ b/examples/retag/transcode.c
@@ -0,0 +1,106 @@
+/*
+ * This example shows how to use interfaces and the tag subsystem.
+ * It takes an mp3 file as input, and makes an ogg file out of it. While doing
+ * this, it parses the filename and sets artist and title in the ogg file.
+ * It assumes the filename to be "<artist> - <title>.mp3"
+ *
+ * Run the program as "retag <mp3 file>"
+ *
+ * To run this program, you need to have the gst-plugins package (specifically
+ * the vorbis and mad plugins) installed.
+ */
+
+/* main header */
+#include <gst/gst.h>
+/* and a header we need for the string manipulation */
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *bin, *filesrc, *decoder, *encoder, *filesink;
+ gchar *artist, *title, *ext, *filename;
+
+ /* initialize GStreamer */
+ gst_init (&argc, &argv);
+
+ /* check that the argument is there */
+ if (argc != 2) {
+ g_print ("usage: %s <mp3 file>\n", argv[0]);
+ return 1;
+ }
+
+ /* parse the mp3 name */
+ artist = strrchr (argv[1], '/');
+ if (artist == NULL)
+ artist = argv[1];
+ artist = g_strdup (artist);
+ ext = strrchr (artist, '.');
+ if (ext) *ext = '\0';
+ title = strstr (artist, " - ");
+ if (title == NULL) {
+ g_print ("The format of the mp3 file is invalid.\n");
+ return 1;
+ }
+ *title = '\0';
+ title += 3;
+
+
+ /* create a new bin to hold the elements */
+ bin = gst_pipeline_new ("pipeline");
+ g_assert (bin);
+
+ /* create a file reader */
+ filesrc = gst_element_factory_make ("filesrc", "disk_source");
+ g_assert (filesrc);
+
+ /* now it's time to get the decoder */
+ decoder = gst_element_factory_make ("mad", "decode");
+ if (!decoder) {
+ g_print ("could not find plugin \"mad\"");
+ return 1;
+ }
+
+ /* create the encoder */
+ encoder = gst_element_factory_make ("vorbisenc", "encoder");
+ if (!encoder) {
+ g_print ("cound not find plugin \"vorbisenc\"");
+ return 1;
+ }
+
+ /* and a file writer */
+ filesink = gst_element_factory_make ("filesink", "filesink");
+ g_assert (filesink);
+
+ /* set the filenames */
+ filename = g_strdup_printf ("%s.ogg", argv[1]); /* easy solution */
+ g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
+ g_object_set (G_OBJECT (filesink), "location", filename, NULL);
+ g_free (filename);
+
+ /* make sure the tag setter uses our stuff
+ (though that should already be default) */
+ gst_tag_setter_set_merge_mode (GST_TAG_SETTER (encoder), GST_TAG_MERGE_KEEP);
+ /* set the tagging information */
+ gst_tag_setter_add (GST_TAG_SETTER (encoder), GST_TAG_MERGE_REPLACE,
+ GST_TAG_ARTIST, artist,
+ GST_TAG_TITLE, title,
+ NULL);
+
+ /* add objects to the main pipeline */
+ gst_bin_add_many (GST_BIN (bin), filesrc, decoder, encoder, filesink, NULL);
+
+ /* link the elements */
+ gst_element_link_many (filesrc, decoder, encoder, filesink, NULL);
+
+ /* start playing */
+ gst_element_set_state (bin, GST_STATE_PLAYING);
+
+ while (gst_bin_iterate (GST_BIN (bin)));
+
+ /* stop the bin */
+ gst_element_set_state (bin, GST_STATE_NULL);
+
+ return 0;
+}
+
diff --git a/gst/Makefile.am b/gst/Makefile.am
index 64e0e5a62..a9fe911bf 100644
--- a/gst/Makefile.am
+++ b/gst/Makefile.am
@@ -114,6 +114,8 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
gstscheduler.c \
gststructure.c \
gstsystemclock.c \
+ gsttag.c \
+ gsttaginterface.c \
gstthread.c \
gstthreaddummy.c \
$(GST_TRACE_SRC) \
@@ -131,6 +133,8 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
BUILT_SOURCES = gstversion.h gstconfig.h gstmarshal.h gstmarshal.c gstenumtypes.h $(GST_ENUMTYPES_SRC)
+CLEANFILES = gstmarshal.h gstmarshal.c gstenumtypes.h $(GST_ENUMTYPES_SRC)
+DISTCLEANFILES = gstversion.h gstconfig.h
libgstreamer_@GST_MAJORMINOR@_la_CFLAGS = -D_GNU_SOURCE \
$(GST_CFLAGS) \
@@ -176,6 +180,8 @@ gst_headers = \
gstscheduler.h \
gststructure.h \
gstsystemclock.h \
+ gsttag.h \
+ gsttaginterface.h \
gstthread.h \
gsttrace.h \
gsttrashstack.h \
@@ -238,12 +244,4 @@ gstenumtypes.c: $(gst_headers)
--vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \
$^ > gstenumtypes.c
-# Don't want the generated marshal files in the dist
-dist-hook:
- rm -f $(distdir)/gstmarshal.c $(distdir)/gstmarshal.h
-
-# Clean generated files
-distclean-local:
- rm -f $(top_builddir)/gst/gstmarshal.c $(top_builddir)/gst/gstmarshal.h
-
EXTRA_DIST = ROADMAP
diff --git a/gst/gst.c b/gst/gst.c
index 8b1ef9535..f81e567eb 100644
--- a/gst/gst.c
+++ b/gst/gst.c
@@ -537,6 +537,7 @@ init_post (void)
_gst_plugin_initialize ();
_gst_event_initialize ();
_gst_buffer_initialize ();
+ _gst_tag_initialize ();
#ifndef GST_DISABLE_REGISTRY
if (!_gst_registry_fixed) {
diff --git a/gst/gst.h b/gst/gst.h
index 8f48c40c6..45662fe28 100644
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -27,42 +27,44 @@
#include <glib.h>
#include <popt.h>
-#include <gst/gstversion.h>
+#include <gst/gstenumtypes.h>
#include <gst/gsttypes.h>
+#include <gst/gstversion.h>
-#include <gst/gstinfo.h>
-#include <gst/gstobject.h>
-#include <gst/gstpad.h>
+#include <gst/gstautoplug.h>
+#include <gst/gstbin.h>
#include <gst/gstbuffer.h>
#include <gst/gstbufferpool-default.h>
+#include <gst/gstcaps.h>
+#include <gst/gstclock.h>
#include <gst/gstcpu.h>
#include <gst/gstelement.h>
-#include <gst/gstbin.h>
+#include <gst/gstevent.h>
#include <gst/gstindex.h>
+#include <gst/gstinfo.h>
+#include <gst/gstinterface.h>
+#include <gst/gstobject.h>
+#include <gst/gstpad.h>
#include <gst/gstpipeline.h>
+#include <gst/gstplugin.h>
+#include <gst/gstprops.h>
+#include <gst/gstscheduler.h>
+#include <gst/gststructure.h>
+#include <gst/gstsystemclock.h>
+#include <gst/gsttag.h>
+#include <gst/gsttaginterface.h>
#include <gst/gstthread.h>
+#include <gst/gsttrace.h>
#include <gst/gsttypefind.h>
-#include <gst/gstautoplug.h>
-#include <gst/gstcaps.h>
-#include <gst/gststructure.h>
-#include <gst/gstprops.h>
-#include <gst/gstplugin.h>
#include <gst/gsturi.h>
#include <gst/gsturitype.h>
#include <gst/gstutils.h>
-#include <gst/gsttrace.h>
-#include <gst/gstxml.h>
-#include <gst/gstscheduler.h>
-#include <gst/gstevent.h>
-#include <gst/gstclock.h>
-#include <gst/gstsystemclock.h>
-#include <gst/gstinterface.h>
#include <gst/gstvalue.h>
+#include <gst/gstxml.h>
#include <gst/gstparse.h>
#include <gst/gstregistry.h>
#include <gst/gstregistrypool.h>
-#include <gst/gstenumtypes.h>
/* API compatibility stuff */
#include <gst/gstcompat.h>
diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c
index 6df3cf8cb..3a01d34dd 100644
--- a/gst/gstbuffer.c
+++ b/gst/gstbuffer.c
@@ -167,6 +167,7 @@ gst_buffer_default_copy (GstBuffer *buffer)
GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
+ GST_BUFFER_OFFSET_END (copy) = GST_BUFFER_OFFSET_END (buffer);
GST_BUFFER_BUFFERPOOL (copy) = NULL;
GST_BUFFER_POOL_PRIVATE (copy) = NULL;
@@ -204,6 +205,7 @@ gst_buffer_new (void)
GST_BUFFER_TIMESTAMP (newbuf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (newbuf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE;
+ GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_BUFFERPOOL (newbuf) = NULL;
GST_BUFFER_POOL_PRIVATE (newbuf) = NULL;
@@ -335,8 +337,9 @@ gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size)
GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
}
- GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
/* make sure nobody overwrites data as it would overwrite in the parent.
* data in parent cannot be overwritten because we hold a ref */
GST_DATA_FLAG_SET (parent, GST_DATA_READONLY);
@@ -453,13 +456,17 @@ gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len)
/* if we completely merged the two buffers (appended), we can
* calculate the duration too. Also make sure we's not messing with
* invalid DURATIONS */
- if (offset == 0 && buf1->size + buf2->size == len &&
- GST_BUFFER_DURATION_IS_VALID (buf1) &&
- GST_BUFFER_DURATION_IS_VALID (buf2))
- {
- /* add duration */
- GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf1) +
- GST_BUFFER_DURATION (buf2);
+ if (offset == 0 && buf1->size + buf2->size == len) {
+ if (GST_BUFFER_DURATION_IS_VALID (buf1) &&
+ GST_BUFFER_DURATION_IS_VALID (buf2)) {
+ /* add duration */
+ GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf1) +
+ GST_BUFFER_DURATION (buf2);
+ }
+ if (GST_BUFFER_OFFSET_END_IS_VALID (buf2)) {
+ /* add offset_end */
+ GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_END (buf2);
+ }
}
return newbuf;
diff --git a/gst/gstbuffer.h b/gst/gstbuffer.h
index 4191f7bdc..ab19247bf 100644
--- a/gst/gstbuffer.h
+++ b/gst/gstbuffer.h
@@ -63,6 +63,7 @@ extern GType _gst_buffer_pool_type;
#define GST_BUFFER_DURATION(buf) (GST_BUFFER(buf)->duration)
#define GST_BUFFER_FORMAT(buf) (GST_BUFFER(buf)->format)
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
+#define GST_BUFFER_OFFSET_END(buf) (GST_BUFFER(buf)->offset_end)
#define GST_BUFFER_BUFFERPOOL(buf) (GST_BUFFER(buf)->pool)
#define GST_BUFFER_POOL_PRIVATE(buf) (GST_BUFFER(buf)->pool_private)
@@ -72,6 +73,7 @@ extern GType _gst_buffer_pool_type;
#define GST_BUFFER_DURATION_IS_VALID(buffer) (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)))
#define GST_BUFFER_TIMESTAMP_IS_VALID(buffer) (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)))
#define GST_BUFFER_OFFSET_IS_VALID(buffer) (GST_BUFFER_OFFSET (buffer) != GST_BUFFER_OFFSET_NONE)
+#define GST_BUFFER_OFFSET_END_IS_VALID(buffer) (GST_BUFFER_OFFSET_END (buffer) != GST_BUFFER_OFFSET_NONE)
#define GST_BUFFER_MAXSIZE_IS_VALID(buffer) (GST_BUFFER_MAXSIZE (buffer) != GST_BUFFER_MAXSIZE_NONE)
typedef enum {
@@ -101,8 +103,11 @@ struct _GstBuffer {
* for video frames, this could be the number of frames,
* for audio data, this could be the number of audio samples,
* for file data or compressed data, this could be the number of bytes
+ * offset_end is the last offset contained in the buffer. The format specifies
+ * the meaning of both of them exactly.
*/
guint64 offset;
+ guint64 offset_end;
/* this is a pointer to the buffer pool (if any) */
GstBufferPool *pool;
diff --git a/gst/gstelement.c b/gst/gstelement.c
index d0758bb3c..5af2331f0 100644
--- a/gst/gstelement.c
+++ b/gst/gstelement.c
@@ -39,6 +39,8 @@ enum {
PAD_REMOVED,
ERROR,
EOS,
+ FOUND_TAG,
+ /* add more above */
LAST_SIGNAL
};
@@ -65,6 +67,7 @@ static void gst_element_dispose (GObject *object);
static GstElementStateReturn gst_element_change_state (GstElement *element);
static void gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg);
+static void gst_element_found_tag_func (GstElement* element, GstElement *source, GstTagList *tag_list);
#ifndef GST_DISABLE_LOADSAVE
static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
@@ -127,11 +130,16 @@ gst_element_class_init (GstElementClass *klass)
g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
gst_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
- G_TYPE_OBJECT, G_TYPE_STRING);
+ GST_TYPE_ELEMENT, G_TYPE_STRING);
gst_element_signals[EOS] =
g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
+ G_STRUCT_OFFSET (GstElementClass, eos), NULL, NULL,
gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
+ gst_element_signals[FOUND_TAG] =
+ g_signal_new ("found-tag", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstElementClass, found_tag), NULL, NULL,
+ gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
+ GST_TYPE_ELEMENT, G_TYPE_POINTER);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_real_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_real_get_property);
@@ -145,6 +153,7 @@ gst_element_class_init (GstElementClass *klass)
klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state);
klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func);
+ klass->found_tag = GST_DEBUG_FUNCPTR (gst_element_found_tag_func);
klass->padtemplates = NULL;
klass->numpadtemplates = 0;
@@ -931,7 +940,9 @@ gst_element_remove_pad (GstElement *element, GstPad *pad)
/* FIXME: what if someone calls _remove_pad instead of
_remove_ghost_pad? */
if (GST_IS_REAL_PAD (pad)) {
- g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
+ if (GST_RPAD_PEER (pad) != NULL) {
+ gst_pad_unlink (pad, GST_PAD (GST_RPAD_PEER (pad)));
+ }
}
/* remove it from the list */
@@ -2924,6 +2935,71 @@ gst_element_set_loop_function (GstElement *element,
}
}
}
+static inline void
+gst_element_emit_found_tag (GstElement* element, GstElement *source, GstTagList *tag_list)
+{
+ gst_object_ref (GST_OBJECT (element));
+ g_signal_emit (element, gst_element_signals[FOUND_TAG], 0, source, tag_list);
+ gst_object_unref (GST_OBJECT (element));
+}
+static void
+gst_element_found_tag_func (GstElement* element, GstElement *source, GstTagList *tag_list)
+{
+ /* tell the parent */
+ if (GST_OBJECT_PARENT (element)) {
+ GST_CAT_LOG_OBJECT (GST_CAT_EVENT, element, "forwarding tag event to %s",
+ GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
+ gst_element_emit_found_tag (GST_ELEMENT (GST_OBJECT_PARENT (element)), source, tag_list);
+ }
+}
+/**
+ * gst_element_found_tags:
+ * @element: the element that found the tags
+ * @tag_list: the found tags
+ *
+ * This function emits the found_tags signal. This is a recursive signal, so
+ * every parent will emit that signal, too, before this function returns.
+ * Only emit this signal, when you extracted these tags out of the data stream,
+ * not when you handle an event.
+ */
+void
+gst_element_found_tags (GstElement *element, GstTagList *tag_list)
+{
+ gst_element_emit_found_tag (element, element, tag_list);
+}
+/**
+ * gst_element_found_tags_for_pad:
+ * @element: element that found the tag
+ * @pad: src pad the tags correspond to
+ * @timestamp: time the tags were found
+ * @list: the taglist
+ *
+ * This is a convenience routine for tag finding. Most of the time you only
+ * want to push the found tags down one pad, in that case this function is for
+ * you. It takes ownership of the taglist, emits the found-tag signal and pushes
+ * a tag event down the pad.
+ */
+void
+gst_element_found_tags_for_pad (GstElement *element, GstPad *pad, GstClockTime timestamp,
+ GstTagList *list)
+{
+ GstEvent *tag_event;
+
+ g_return_if_fail (GST_IS_ELEMENT (element));
+ g_return_if_fail (GST_IS_REAL_PAD (pad));
+ g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
+ g_return_if_fail (element == GST_PAD_PARENT (pad));
+ g_return_if_fail (list != NULL);
+
+ tag_event = gst_event_new_tag (list);
+ GST_EVENT_TIMESTAMP (tag_event) = timestamp;
+ gst_element_found_tags (element, gst_event_tag_get_list (tag_event));
+ if (GST_PAD_IS_USABLE (pad)) {
+ gst_pad_push (pad, GST_DATA (tag_event));
+ } else {
+ gst_data_unref (GST_DATA (tag_event));
+ }
+}
static inline void
gst_element_set_eos_recursive (GstElement *element)
diff --git a/gst/gstelement.h b/gst/gstelement.h
index 2a983413b..f40547fe6 100644
--- a/gst/gstelement.h
+++ b/gst/gstelement.h
@@ -32,6 +32,7 @@
#include <gst/gstplugin.h>
#include <gst/gstpluginfeature.h>
#include <gst/gstindex.h>
+#include <gst/gsttag.h>
G_BEGIN_DECLS
@@ -137,7 +138,6 @@ typedef enum {
} GstElementFlags;
#define GST_ELEMENT_IS_THREAD_SUGGESTED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_THREAD_SUGGESTED))
-#define GST_ELEMENT_IS_EOS(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_EOS))
#define GST_ELEMENT_IS_EVENT_AWARE(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_EVENT_AWARE))
#define GST_ELEMENT_IS_DECOUPLED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_DECOUPLED))
@@ -206,6 +206,7 @@ struct _GstElementClass {
void (*pad_removed) (GstElement *element, GstPad *pad);
void (*error) (GstElement *element, GstElement *source, gchar *error);
void (*eos) (GstElement *element);
+ void (*found_tag) (GstElement *element, GstElement *source, GstTagList *tag_list);
/* local pointers for get/set */
void (*set_property) (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
@@ -254,7 +255,6 @@ void gst_element_class_set_details (GstElementClass *klass,
void gst_element_default_error (GObject *object, GstObject *orig, gchar *error);
GType gst_element_get_type (void);
-
void gst_element_set_loop_function (GstElement *element,
GstElementLoopFunction loop);
@@ -350,6 +350,10 @@ gboolean gst_element_convert (GstElement *element,
GstFormat src_format, gint64 src_value,
GstFormat *dest_format, gint64 *dest_value);
+void gst_element_found_tags (GstElement *element, GstTagList *tag_list);
+void gst_element_found_tags_for_pad (GstElement *element, GstPad *pad, GstClockTime timestamp,
+ GstTagList *list);
+
void gst_element_set_eos (GstElement *element);
void gst_element_error (GstElement *element, const gchar *error, ...);
@@ -394,6 +398,8 @@ struct _GstElementFactory {
GList * padtemplates;
guint numpadtemplates;
+ GList *interfaces; /* interfaces this element implements */
+
GST_OBJECT_PADDING
};
@@ -431,6 +437,8 @@ gboolean gst_element_factory_can_sink_caps (GstElementFactory *factory,
void __gst_element_factory_add_pad_template (GstElementFactory *elementfactory,
GstPadTemplate *templ);
+void __gst_element_factory_add_interface (GstElementFactory *elementfactory,
+ const gchar *interfacename);
G_END_DECLS
diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c
index 595f0ca47..8e1e7abfb 100644
--- a/gst/gstelementfactory.c
+++ b/gst/gstelementfactory.c
@@ -84,6 +84,8 @@ gst_element_factory_init (GstElementFactory *factory)
{
factory->padtemplates = NULL;
factory->numpadtemplates = 0;
+
+ factory->interfaces = NULL;
}
/**
* gst_element_factory_find:
@@ -148,6 +150,10 @@ gst_element_factory_cleanup (GstElementFactory *factory)
g_list_free (factory->padtemplates);
factory->padtemplates = NULL;
factory->numpadtemplates = 0;
+
+ g_list_foreach (factory->interfaces, (GFunc) g_free, NULL);
+ g_list_free (factory->interfaces);
+ factory->interfaces = NULL;
}
/**
* gst_element_register:
@@ -165,6 +171,8 @@ gboolean
gst_element_register (GstPlugin *plugin, const gchar *name, guint rank, GType type)
{
GstElementFactory *factory;
+ GType *interfaces;
+ guint n_interfaces, i;
GstElementClass *klass;
g_return_val_if_fail (name != NULL, FALSE);
@@ -190,6 +198,12 @@ gst_element_register (GstPlugin *plugin, const gchar *name, guint rank, GType ty
g_list_foreach (factory->padtemplates, (GFunc) g_object_ref, NULL);
factory->numpadtemplates = klass->numpadtemplates;
+ interfaces = g_type_interfaces (type, &n_interfaces);
+ for (i = 0; i < n_interfaces; i++) {
+ __gst_element_factory_add_interface (factory, g_type_name (interfaces[i]));
+ }
+ g_free (interfaces);
+
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), rank);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
@@ -388,6 +402,23 @@ gst_element_factory_get_num_pad_templates (GstElementFactory *factory)
return factory->numpadtemplates;
}
/**
+ * __gst_element_factory_add_interface:
+ * @elementfactory: The elementfactory to add the interface to
+ * @interfacename: Name of the interface
+ *
+ * Adds the given interfacename to the list of implemented interfaces of the
+ * element.
+ */
+void
+__gst_element_factory_add_interface (GstElementFactory *elementfactory, const gchar *interfacename)
+{
+ g_return_if_fail (GST_IS_ELEMENT_FACTORY (elementfactory));
+ g_return_if_fail (interfacename != NULL);
+ g_return_if_fail (interfacename[0] != '\0'); /* no empty string */
+
+ elementfactory->interfaces = g_list_prepend (elementfactory->interfaces, g_strdup (interfacename));
+}
+/**
* gst_element_factory_get_pad_templates:
* @factory: a #GstElementFactory
*
diff --git a/gst/gstevent.c b/gst/gstevent.c
index a213e8a7b..ad63b7814 100644
--- a/gst/gstevent.c
+++ b/gst/gstevent.c
@@ -29,6 +29,8 @@
#include "gstmemchunk.h"
#include "gstevent.h"
#include "gstlog.h"
+#include "gsttag.h"
+
#ifndef GST_DISABLE_TRACE
/* #define GST_WITH_ALLOC_TRACE */
#include "gsttrace.h"
@@ -70,6 +72,12 @@ _gst_event_copy (GstEvent *event)
memcpy (copy, event, sizeof (GstEvent));
/* FIXME copy/ref additional fields */
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:
+ copy->event_data.structure.structure = gst_structure_copy (event->event_data.structure.structure);
+ default:
+ break;
+ }
return copy;
}
@@ -83,6 +91,8 @@ _gst_event_free (GstEvent* event)
gst_object_unref (GST_EVENT_SRC (event));
}
switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:
+ gst_tag_list_free (event->event_data.structure.structure);
default:
break;
}
diff --git a/gst/gstevent.h b/gst/gstevent.h
index ab8ace7fb..a060dc9dc 100644
--- a/gst/gstevent.h
+++ b/gst/gstevent.h
@@ -48,7 +48,8 @@ typedef enum {
GST_EVENT_FILLER = 12,
GST_EVENT_TS_OFFSET = 13,
GST_EVENT_INTERRUPT = 14,
- GST_EVENT_NAVIGATION = 15
+ GST_EVENT_NAVIGATION = 15,
+ GST_EVENT_TAG = 16
} GstEventType;
extern GType _gst_event_type;
diff --git a/gst/gstinfo.c b/gst/gstinfo.c
index 843a31fdb..2fefe8505 100644
--- a/gst/gstinfo.c
+++ b/gst/gstinfo.c
@@ -258,11 +258,11 @@ void gst_debug_log (GstDebugCategory *category, GstDebugLevel level,
va_list var_args;
va_start (var_args, format);
- gst_debug_logv (category, level, file, function, line, object, format, var_args);
+ gst_debug_log_valist (category, level, file, function, line, object, format, var_args);
va_end (var_args);
}
/**
- * gst_debug_logv:
+ * gst_debug_log_valist:
* @category: category to log
* @level: level of the message is in
* @file: the file that emitted the message, usually the __FILE__ identifier
@@ -274,9 +274,9 @@ void gst_debug_log (GstDebugCategory *category, GstDebugLevel level,
*
* Logs the given message using the currently registered debugging handlers.
*/
-void gst_debug_logv (GstDebugCategory *category, GstDebugLevel level,
- const gchar *file, const gchar *function, gint line,
- GObject *object, gchar *format, va_list args)
+void gst_debug_log_valist (GstDebugCategory *category, GstDebugLevel level,
+ const gchar *file, const gchar *function, gint line,
+ GObject *object, gchar *format, va_list args)
{
gchar *message;
LogFuncEntry *entry;
diff --git a/gst/gstinfo.h b/gst/gstinfo.h
index 17ab30544..a1a91e8a9 100644
--- a/gst/gstinfo.h
+++ b/gst/gstinfo.h
@@ -162,7 +162,7 @@ void gst_debug_log (GstDebugCategory * category,
GObject * object,
gchar * format,
...) G_GNUC_PRINTF (7, 8) G_GNUC_NO_INSTRUMENT;
-void gst_debug_logv (GstDebugCategory * category,
+void gst_debug_log_valist (GstDebugCategory * category,
GstDebugLevel level,
const gchar * file,
const gchar * function,
@@ -388,7 +388,7 @@ const gchar* _gst_debug_nameof_funcptr (void * ptr);
#ifdef __GNUC__
# pragma GCC poison gst_debug_log
-# pragma GCC poison gst_debug_logv
+# pragma GCC poison gst_debug_log_valist
# pragma GCC poison gst_debug_log_default
# pragma GCC poison _gst_debug_category_new
#endif
diff --git a/gst/gststructure.c b/gst/gststructure.c
index e01f5bed4..f92dd32f5 100644
--- a/gst/gststructure.c
+++ b/gst/gststructure.c
@@ -48,7 +48,7 @@ GType gst_structure_get_type(void)
void _gst_structure_initialize(void)
{
- static GTypeValueTable type_value_table = {
+ static const GTypeValueTable type_value_table = {
_gst_structure_value_init,
_gst_structure_value_free,
_gst_structure_value_copy,
@@ -58,7 +58,7 @@ void _gst_structure_initialize(void)
NULL,
NULL,
};
- static GTypeInfo structure_info = {
+ static const GTypeInfo structure_info = {
0,
NULL,
NULL,
@@ -84,6 +84,27 @@ void _gst_structure_initialize(void)
}
/**
+ * gst_structure_id_empty_new:
+ * @name: name of new structure
+ *
+ * Creates a new, empty #GstStructure with the given name.
+ *
+ * Returns: a new, empty #GstStructure
+ */
+GstStructure *gst_structure_id_empty_new(GQuark quark)
+{
+ GstStructure *structure;
+
+ g_return_val_if_fail(quark != 0, NULL);
+
+ structure = g_new0(GstStructure, 1);
+ structure->name = quark;
+ structure->fields = g_array_new(FALSE,TRUE,sizeof(GstStructureField));
+
+ return structure;
+}
+
+/**
* gst_structure_empty_new:
* @name: name of new structure
*
@@ -262,15 +283,15 @@ void gst_structure_set_name(GstStructure *structure, const gchar *name)
* value is freed.
*/
void gst_structure_id_set_value(GstStructure *structure, GQuark fieldname,
- GValue *value)
+ const GValue *value)
{
- GstStructureField field = { 0 };
+ GstStructureField field = { 0, { 0, } };
g_return_if_fail(structure != NULL);
g_return_if_fail(G_IS_VALUE(value));
field.name = fieldname;
- g_value_init(&field.value, G_TYPE_INT);
+ g_value_init(&field.value, G_VALUE_TYPE (value));
g_value_copy(value, &field.value);
gst_structure_set_field(structure, &field);
@@ -287,7 +308,7 @@ void gst_structure_id_set_value(GstStructure *structure, GQuark fieldname,
* value is freed.
*/
void gst_structure_set_value(GstStructure *structure, const gchar *field,
- GValue *value)
+ const GValue *value)
{
g_return_if_fail(structure != NULL);
g_return_if_fail(field != NULL);
@@ -355,13 +376,6 @@ void gst_structure_set_valist(GstStructure *structure, const gchar *fieldname,
g_value_init(&field.value, G_TYPE_DOUBLE);
g_value_set_double(&field.value, d);
break;
-#if 0
- case GST_TYPE_FOURCC:
- i = va_arg(varargs, int);
- g_value_init(&field.value, G_TYPE_FOURCC);
- gst_value_set_fourcc(&field.value, i);
- break;
-#endif
case G_TYPE_BOOLEAN:
i = va_arg(varargs, int);
g_value_init(&field.value, G_TYPE_BOOLEAN);
@@ -373,7 +387,14 @@ void gst_structure_set_valist(GstStructure *structure, const gchar *fieldname,
g_value_set_string(&field.value, s);
break;
default:
- g_assert_not_reached();
+ if(type == GST_TYPE_FOURCC){
+ i = va_arg(varargs, int);
+ g_value_init(&field.value, GST_TYPE_FOURCC);
+ gst_value_set_fourcc(&field.value, i);
+ break;
+ }else{
+ g_critical("unimplemented vararg field type %d\n", (int)type);
+ }
break;
}
@@ -384,6 +405,32 @@ void gst_structure_set_valist(GstStructure *structure, const gchar *fieldname,
}
/**
+ * gst_structure_set_field_copy:
+ * @structure: a #GstStructure
+ * @field: the #GstStructureField to set
+ *
+ * Sets a field in the structure. If the structure currently contains
+ * a field with the same name, it is replaced with the provided field.
+ * Otherwise, the field is added to the structure. The field's value
+ * is deeply copied.
+ *
+ * This function is intended mainly for internal use. The function
+ * #gst_structure_set() is recommended instead of this one.
+ */
+void gst_structure_set_field_copy (GstStructure *structure,
+ const GstStructureField *field)
+{
+ GstStructureField f = { 0 };
+ GType type = G_VALUE_TYPE (&field->value);
+
+ f.name = field->name;
+ g_value_init (&f.value, type);
+ g_value_copy (&field->value, &f.value);
+
+ gst_structure_set_field (structure, &f);
+}
+
+/**
* gst_structure_set_field:
* @structure: a #GstStructure
* @field: the #GstStructureField to set
@@ -424,7 +471,7 @@ void gst_structure_set_field(GstStructure *structure, GstStructureField *field)
*
* Returns: the #GstStructureField with the given ID
*/
-GstStructureField *gst_structure_id_get_field(GstStructure *structure,
+GstStructureField *gst_structure_id_get_field(const GstStructure *structure,
GQuark field_id)
{
GstStructureField *field;
@@ -452,7 +499,7 @@ GstStructureField *gst_structure_id_get_field(GstStructure *structure,
* Returns: the #GstStructureField with the given name
*/
GstStructureField *
-gst_structure_get_field(GstStructure *structure, const gchar *fieldname)
+gst_structure_get_field(const GstStructure *structure, const gchar *fieldname)
{
g_return_val_if_fail(structure != NULL, NULL);
g_return_val_if_fail(fieldname != NULL, NULL);
@@ -471,7 +518,7 @@ gst_structure_get_field(GstStructure *structure, const gchar *fieldname)
* Returns: the #GValue corresponding to the field with the given name.
*/
const GValue *
-gst_structure_get_value(GstStructure *structure, const gchar *fieldname)
+gst_structure_get_value(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
@@ -525,6 +572,30 @@ gst_structure_remove_field(GstStructure *structure, const gchar *fieldname)
}
/**
+ * gst_structure_remove_all_fields:
+ * @structure: a #GstStructure
+ *
+ * Removes all fields in a GstStructure.
+ */
+void
+gst_structure_remove_all_fields(GstStructure *structure)
+{
+ GstStructureField *field;
+ int i;
+
+ g_return_if_fail(structure != NULL);
+
+ for (i = structure->fields->len - 1; i >= 0; i-- ) {
+ field = GST_STRUCTURE_FIELD(structure, i);
+
+ if (G_IS_VALUE (&field->value)) {
+ g_value_unset(&field->value);
+ }
+ structure->fields = g_array_remove_index (structure->fields, i);
+ }
+}
+
+/**
* gst_structure_get_field_type:
* @structure: a #GstStructure
* @fieldname: the name of the field
@@ -536,7 +607,7 @@ gst_structure_remove_field(GstStructure *structure, const gchar *fieldname)
* Returns: the #GValue of the field
*/
GType
-gst_structure_get_field_type(GstStructure *structure, const gchar *fieldname)
+gst_structure_get_field_type(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
@@ -558,7 +629,7 @@ gst_structure_get_field_type(GstStructure *structure, const gchar *fieldname)
* Returns: the number of fields in the structure
*/
gint
-gst_structure_n_fields(GstStructure *structure)
+gst_structure_n_fields(const GstStructure *structure)
{
g_return_val_if_fail(structure != NULL, 0);
@@ -597,7 +668,7 @@ gst_structure_field_foreach (GstStructure *structure,
* Returns: TRUE if the structure contains a field with the given name
*/
gboolean
-gst_structure_has_field(GstStructure *structure, const gchar *fieldname)
+gst_structure_has_field(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
@@ -620,7 +691,7 @@ gst_structure_has_field(GstStructure *structure, const gchar *fieldname)
* Returns: TRUE if the structure contains a field with the given name and type
*/
gboolean
-gst_structure_has_field_typed(GstStructure *structure, const gchar *fieldname,
+gst_structure_has_field_typed(const GstStructure *structure, const gchar *fieldname,
GType type)
{
GstStructureField *field;
@@ -650,7 +721,7 @@ gst_structure_has_field_typed(GstStructure *structure, const gchar *fieldname,
* Returns: TRUE if the value could be set correctly
*/
gboolean
-gst_structure_get_boolean(GstStructure *structure, const gchar *fieldname,
+gst_structure_get_boolean(const GstStructure *structure, const gchar *fieldname,
gboolean *value)
{
GstStructureField *field;
@@ -681,7 +752,7 @@ gst_structure_get_boolean(GstStructure *structure, const gchar *fieldname,
* Returns: TRUE if the value could be set correctly
*/
gboolean
-gst_structure_get_int(GstStructure *structure, const gchar *fieldname,
+gst_structure_get_int(const GstStructure *structure, const gchar *fieldname,
gint *value)
{
GstStructureField *field;
@@ -713,7 +784,7 @@ gst_structure_get_int(GstStructure *structure, const gchar *fieldname,
* Returns: TRUE if the value could be set correctly
*/
gboolean
-gst_structure_get_fourcc(GstStructure *structure, const gchar *fieldname,
+gst_structure_get_fourcc(const GstStructure *structure, const gchar *fieldname,
guint32 *value)
{
GstStructureField *field;
@@ -744,7 +815,7 @@ gst_structure_get_fourcc(GstStructure *structure, const gchar *fieldname,
*
* Returns: TRUE if the value could be set correctly
*/
-gboolean gst_structure_get_double(GstStructure *structure,
+gboolean gst_structure_get_double(const GstStructure *structure,
const gchar *fieldname, gdouble *value)
{
GstStructureField *field;
@@ -779,7 +850,7 @@ gboolean gst_structure_get_double(GstStructure *structure,
* Returns: a pointer to the string
*/
const gchar *
-gst_structure_get_string(GstStructure *structure, const gchar *fieldname)
+gst_structure_get_string(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
@@ -803,7 +874,7 @@ gst_structure_get_string(GstStructure *structure, const gchar *fieldname)
* Returns: a pointer to string allocated by g_malloc()
*/
gchar *
-gst_structure_to_string(GstStructure *structure)
+gst_structure_to_string(const GstStructure *structure)
{
GstStructureField *field;
GString *s;
diff --git a/gst/gststructure.h b/gst/gststructure.h
index 271734939..4ea6b10c6 100644
--- a/gst/gststructure.h
+++ b/gst/gststructure.h
@@ -51,6 +51,7 @@ GType gst_structure_get_type(void);
void _gst_structure_initialize(void);
GstStructure *gst_structure_empty_new(const gchar *name);
+GstStructure *gst_structure_id_empty_new(GQuark quark);
GstStructure *gst_structure_new(const gchar *name,
const gchar *firstfield, ...);
GstStructure *gst_structure_new_valist(const gchar *name,
@@ -60,46 +61,49 @@ void gst_structure_free(GstStructure *structure);
const gchar *gst_structure_get_name(GstStructure *structure);
void gst_structure_set_name(GstStructure *structure, const gchar *name);
-void gst_structure_set_field(GstStructure *structure,
+void gst_structure_set_field_copy (GstStructure *structure,
+ const GstStructureField *field);
+void gst_structure_set_field (GstStructure *structure,
GstStructureField *field);
void gst_structure_id_set_value(GstStructure *structure, GQuark field,
- GValue *value);
+ const GValue *value);
void gst_structure_set_value(GstStructure *structure, const gchar *field,
- GValue *value);
+ const GValue *value);
void gst_structure_set(GstStructure *structure, const gchar *field, ...);
void gst_structure_set_valist(GstStructure *structure, const gchar *field,
va_list varargs);
-const GValue *gst_structure_get_value(GstStructure *structure, const gchar *field);
-GstStructureField *gst_structure_get_field(GstStructure *structure,
+const GValue *gst_structure_get_value(const GstStructure *structure, const gchar *field);
+GstStructureField *gst_structure_get_field(const GstStructure *structure,
const gchar *fieldname);
-GstStructureField *gst_structure_id_get_field(GstStructure *structure,
+GstStructureField *gst_structure_id_get_field(const GstStructure *structure,
GQuark fieldname);
void gst_structure_remove_field(GstStructure *structure, const gchar *field);
+void gst_structure_remove_all_fields(GstStructure *structure);
-GType gst_structure_get_field_type(GstStructure *structure,
+GType gst_structure_get_field_type(const GstStructure *structure,
const gchar *field);
void gst_structure_field_foreach (GstStructure *structure,
GstStructureForeachFunc func, gpointer user_data);
-gint gst_structure_n_fields(GstStructure *structure);
-gboolean gst_structure_has_field(GstStructure *structure, const gchar *field);
-gboolean gst_structure_has_field_typed(GstStructure *structure,
+gint gst_structure_n_fields(const GstStructure *structure);
+gboolean gst_structure_has_field(const GstStructure *structure, const gchar *field);
+gboolean gst_structure_has_field_typed(const GstStructure *structure,
const gchar *field, GType type);
/* utility functions */
-gboolean gst_structure_get_boolean(GstStructure *structure, const gchar *field,
+gboolean gst_structure_get_boolean(const GstStructure *structure, const gchar *field,
gboolean *value);
-gboolean gst_structure_get_int(GstStructure *structure, const gchar *field,
+gboolean gst_structure_get_int(const GstStructure *structure, const gchar *field,
gint *value);
-gboolean gst_structure_get_fourcc(GstStructure *structure, const gchar *field,
+gboolean gst_structure_get_fourcc(const GstStructure *structure, const gchar *field,
guint32 *value);
-gboolean gst_structure_get_double(GstStructure *structure, const gchar *field,
+gboolean gst_structure_get_double(const GstStructure *structure, const gchar *field,
gdouble *value);
-const gchar *gst_structure_get_string(GstStructure *structure,
+const gchar *gst_structure_get_string(const GstStructure *structure,
const gchar *field);
-gchar * gst_structure_to_string(GstStructure *structure);
+gchar * gst_structure_to_string(const GstStructure *structure);
GstStructure * gst_structure_from_string (const gchar *string);
diff --git a/gst/gsttag.c b/gst/gsttag.c
new file mode 100644
index 000000000..c6c4f3f11
--- /dev/null
+++ b/gst/gsttag.c
@@ -0,0 +1,831 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttag.c: tag support (aka metadata)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gst_private.h"
+#include "gsttag.h"
+#include "gstinfo.h"
+#include "gstvalue.h"
+
+#include <gobject/gvaluecollector.h>
+#include <string.h>
+
+#define GST_TAG_IS_VALID(tag) (gst_tag_get_info (tag) != NULL)
+
+typedef struct {
+ GType type; /* type the data is in */
+
+ gchar * nick; /* translated name */
+ gchar * blurb; /* translated description of type */
+
+ GstTagMergeFunc merge_func; /* functions to merge the values */
+} GstTagInfo;
+
+#define TAGLIST "taglist"
+static GQuark gst_tag_list_quark;
+static GMutex *__tag_mutex;
+static GHashTable *__tags;
+#define TAG_LOCK g_mutex_lock (__tag_mutex)
+#define TAG_UNLOCK g_mutex_unlock (__tag_mutex)
+
+void
+_gst_tag_initialize (void)
+{
+ gst_tag_list_quark = g_quark_from_static_string (TAGLIST);
+ __tag_mutex = g_mutex_new ();
+ __tags = g_hash_table_new (g_direct_hash, g_direct_equal);
+ gst_tag_register (GST_TAG_TITLE,
+ G_TYPE_STRING,
+ _("title"),
+ _("commonly used title"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_ARTIST,
+ G_TYPE_STRING,
+ _("artist"),
+ _("person(s) resposible for the recording"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_ALBUM,
+ G_TYPE_STRING,
+ _("album"),
+ _("album containing this data"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_DATE,
+ G_TYPE_UINT, /* FIXME: own data type for dates? */
+ _("date"),
+ _("date the data was created in julien days"),
+ NULL);
+ gst_tag_register (GST_TAG_GENRE,
+ G_TYPE_STRING,
+ _("genre"),
+ _("genre this data belongs to"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_COMMENT,
+ G_TYPE_STRING,
+ _("comment"),
+ _("free text commenting the data"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_TRACK_NUMBER,
+ G_TYPE_UINT,
+ _("track number"),
+ _("track number inside a collection"),
+ gst_tag_merge_use_first);
+ gst_tag_register (GST_TAG_TRACK_COUNT,
+ G_TYPE_STRING,
+ _("track count"),
+ _("count of tracks inside collection this track belongs to"),
+ gst_tag_merge_use_first);
+ gst_tag_register (GST_TAG_LOCATION,
+ G_TYPE_STRING,
+ _("loccation"),
+ _("original location of file as a URI"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_DESCRIPTION,
+ G_TYPE_STRING,
+ _("description"),
+ _("short text describing the content of the data"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_VERSION,
+ G_TYPE_STRING,
+ _("version"),
+ _("version of this data"),
+ NULL);
+ gst_tag_register (GST_TAG_ISRC,
+ G_TYPE_STRING,
+ _("ISRC"),
+ _("International Standard Recording Code - see http://www.ifpi.org/isrc/"),
+ NULL);
+ gst_tag_register (GST_TAG_ORGANIZATION,
+ G_TYPE_STRING,
+ _("organization"),
+ _("organization"), /* FIXME */
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_COPYRIGHT,
+ G_TYPE_STRING,
+ _("copyright"),
+ _("copyright notice of the data"),
+ NULL);
+ gst_tag_register (GST_TAG_CONTACT,
+ G_TYPE_STRING,
+ _("contact"),
+ _("contact information"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_LICENSE,
+ G_TYPE_STRING,
+ _("license"),
+ _("license of data"),
+ NULL);
+ gst_tag_register (GST_TAG_PERFORMER,
+ G_TYPE_STRING,
+ _("performer"),
+ _("person(s) performing"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_DURATION,
+ G_TYPE_UINT64,
+ _("duration"),
+ _("length in GStreamer time units (nanoseconds)"),
+ NULL);
+ gst_tag_register (GST_TAG_CODEC,
+ G_TYPE_STRING,
+ _("codec"),
+ _("codec the data is stored in"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_MINIMUM_BITRATE,
+ G_TYPE_UINT,
+ _("minimum bitrate"),
+ _("minimum bitrate in bits/s"),
+ NULL);
+ gst_tag_register (GST_TAG_BITRATE,
+ G_TYPE_UINT,
+ _("bitrate"),
+ _("exact or average bitrate in bits/s"),
+ NULL);
+ gst_tag_register (GST_TAG_MAXIMUM_BITRATE,
+ G_TYPE_UINT,
+ _("maximum bitrate"),
+ _("maximum bitrate in bits/s"),
+ NULL);
+}
+/**
+ * gst_tag_merge_use_first:
+ * @dest: uninitialized GValue to store result in
+ * @src: GValue to copy from
+ *
+ * This is a convenience function for the func argument of gst_tag_register().
+ * It creates a copy of the first value from the list.
+ */
+void
+gst_tag_merge_use_first (GValue *dest, const GValue *src)
+{
+ const GValue *ret = gst_value_list_get_value (src, 0);
+
+ g_value_init (dest, G_VALUE_TYPE (ret));
+ g_value_copy (ret, dest);
+}
+/**
+ * gst_tag_merge_strings_with_comma:
+ * @dest: uninitialized GValue to store result in
+ * @src: GValue to copy from
+ *
+ * This is a convenience function for the func argument of gst_tag_register().
+ * It concatenates all given strings using a comma. The tag must be registered
+ * as a G_TYPE_STRING or this function will fail.
+ */
+void
+gst_tag_merge_strings_with_comma (GValue *dest, const GValue *src)
+{
+ GString *str;
+ gint i, count;
+
+ count = gst_value_list_get_size (src);
+ str = g_string_new (g_value_get_string (gst_value_list_get_value (src, 0)));
+ for (i = 1; i < count; i++) {
+ /* seperator between two string */
+ str = g_string_append (str, _(", "));
+ str = g_string_append (str, g_value_get_string (gst_value_list_get_value (src, 1)));
+ }
+
+ g_value_init (dest, G_TYPE_STRING);
+ g_value_take_string (dest, str->str);
+ g_string_free (str, FALSE);
+}
+static GstTagInfo *
+gst_tag_lookup (GQuark entry)
+{
+ GstTagInfo *ret;
+
+ TAG_LOCK;
+ ret = g_hash_table_lookup (__tags, GUINT_TO_POINTER (entry));
+ TAG_UNLOCK;
+
+ return ret;
+}
+/**
+ * gst_tag_register:
+ * @name: the name or identifier string
+ * @type: the type this data is in
+ * @nick: human-readable name
+ * @blurb: a human-readable description about this tag
+ * @func: function for merging multiple values of this tag
+ *
+ * Registers a new tag type for the use with GStreamer's type system. If a type
+ * with that name is already registered, that one is used.
+ * The old registration may have used a different type however. So don't rely
+ * on youre supplied values.
+ * If you know the type is already registered, use gst_tag_lookup instead.
+ * This function takes ownership of all supplied variables.
+ */
+void
+gst_tag_register (gchar *name, GType type, gchar *nick, gchar *blurb,
+ GstTagMergeFunc func)
+{
+ GQuark key;
+ GstTagInfo *info;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (nick != NULL);
+ g_return_if_fail (blurb != NULL);
+ g_return_if_fail (type != 0 && type != GST_VALUE_TYPE_LIST);
+
+ key = g_quark_from_string (name);
+ info = gst_tag_lookup (key);
+ g_return_if_fail (info == NULL);
+
+ info = g_new (GstTagInfo, 1);
+ info->type = type;
+ info->nick = nick;
+ info->blurb = blurb;
+ info->merge_func = func;
+
+ TAG_LOCK;
+ g_hash_table_insert (__tags, GUINT_TO_POINTER (key), info);
+ TAG_UNLOCK;
+}
+/**
+ * gst_tag_exists:
+ * @tag: name of the tag
+ *
+ * Checks if the given type is already registered.
+ *
+ * Returns: TRUE if the type is already registered
+ */
+gboolean
+gst_tag_exists (const gchar *tag)
+{
+ g_return_val_if_fail (tag != NULL, FALSE);
+
+ return gst_tag_lookup (g_quark_from_string (tag)) != NULL;
+}
+/**
+ * gst_tag_get_type:
+ * @tag: the tag
+ *
+ * Gets the #GType used for this tag.
+ *
+ * Returns: the #GType of this tag
+ */
+GType
+gst_tag_get_type (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, 0);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, 0);
+
+ return info->type;
+}
+/**
+ * gst_tag_get_nick
+ * @tag: the tag
+ *
+ * Returns the human-readable name of this tag, You must not change or free
+ * this string.
+ *
+ * Returns: the human-readable name of this tag
+ */
+const gchar *
+gst_tag_get_nick (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, NULL);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->nick;
+}
+/**
+ * gst_tag_get_description:
+ * @tag: the tag
+ *
+ * Returns the human-readable description of this tag, You must not change or
+ * free this string.
+ *
+ * Return the human-readable description of this tag
+ */
+const gchar *
+gst_tag_get_description (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, NULL);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->blurb;
+}
+/**
+ * gst_tag_list_is_fixed:
+ * @tag: tag to check
+ *
+ * Checks if the given tag is fixed. A fixed tag can only contain one value.
+ * Unfixed tags can contain lists of values.
+ *
+ * Returns: TRUE, if the given tag is fixed.
+ */
+gboolean
+gst_tag_is_fixed (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, FALSE);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return info->merge_func == NULL;
+}
+/**
+ * gst_tag_list_new:
+ *
+ * Creates a new empty GstTagList.
+ *
+ * Returns: An empty tag list
+ */
+GstTagList *
+gst_tag_list_new (void)
+{
+ return GST_TAG_LIST (gst_structure_new (TAGLIST, NULL));
+}
+/**
+ * gst_is_tag_list:
+ * @p: Object that might be a taglist
+ *
+ * Checks if the given pointer is a taglist.
+ *
+ * Returns: TRUE, if the given pointer is a taglist
+ */
+gboolean
+gst_is_tag_list (gconstpointer p)
+{
+ g_return_val_if_fail (p != NULL, FALSE);
+
+ return ((GstStructure *) p)->name == gst_tag_list_quark;
+}
+typedef struct {
+ GstStructure * list;
+ GstTagMergeMode mode;
+} GstTagCopyData;
+static void
+gst_tag_list_add_value_internal (GstStructure *list, GstTagMergeMode mode, GQuark tag, GValue *value)
+{
+ GstTagInfo *info = gst_tag_lookup (tag);
+ GstStructureField *field;
+
+ g_assert (info != NULL);
+
+ if (info->merge_func && (field = gst_structure_id_get_field (list, tag)) != NULL) {
+ GValue value2 = { 0, };
+ switch (mode) {
+ case GST_TAG_MERGE_REPLACE_ALL:
+ case GST_TAG_MERGE_REPLACE:
+ gst_structure_id_set_value (list, tag, value);
+ break;
+ case GST_TAG_MERGE_PREPEND:
+ gst_value_list_concat (&value2, value, &field->value);
+ gst_structure_id_set_value (list, tag, &value2);
+ g_value_unset (&value2);
+ break;
+ case GST_TAG_MERGE_APPEND:
+ gst_value_list_concat (&value2, &field->value, value);
+ gst_structure_id_set_value (list, tag, &value2);
+ g_value_unset (&value2);
+ break;
+ case GST_TAG_MERGE_KEEP:
+ case GST_TAG_MERGE_KEEP_ALL:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ } else {
+ switch (mode) {
+ case GST_TAG_MERGE_APPEND:
+ case GST_TAG_MERGE_KEEP:
+ if (gst_structure_id_get_field (list, tag) != NULL)
+ break;
+ /* fall through */
+ case GST_TAG_MERGE_REPLACE_ALL:
+ case GST_TAG_MERGE_REPLACE:
+ case GST_TAG_MERGE_PREPEND:
+ gst_structure_id_set_value (list, tag, value);
+ break;
+ case GST_TAG_MERGE_KEEP_ALL:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+}
+static void
+gst_tag_list_copy_foreach (GstStructure *structure, GQuark tag, GValue *value, gpointer user_data)
+{
+ GstTagCopyData *copy = (GstTagCopyData *) user_data;
+
+ gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value);
+}
+/**
+ * gst_tag_list_insert:
+ * @into: list to merge into
+ * @from: list to merge from
+ * @mode: the mode to use
+ *
+ * Inserts the tags of the second list into the first list using the given mode.
+ */
+void
+gst_tag_list_insert (GstTagList *into, const GstTagList *from, GstTagMergeMode mode)
+{
+ GstTagCopyData data;
+
+ g_return_if_fail (GST_IS_TAG_LIST (into));
+ g_return_if_fail (GST_IS_TAG_LIST (from));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ data.list = (GstStructure *) into;
+ data.mode = mode;
+ if (mode == GST_TAG_MERGE_REPLACE_ALL) {
+ gst_structure_remove_all_fields (data.list);
+ }
+ gst_structure_field_foreach ((GstStructure *) from, gst_tag_list_copy_foreach, &data);
+}
+/**
+ * gst_tag_list_copy:
+ * @list: list to copy
+ *
+ * Copies a given #GstTagList.
+ *
+ * Returns: copy of the given list
+ */
+GstTagList *
+gst_tag_list_copy (const GstTagList *list)
+{
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
+
+ return GST_TAG_LIST (gst_structure_copy ((GstStructure *) list));
+}
+/**
+ * gst_tag_list_merge:
+ * @list1: first list to merge
+ * @list2: second list to merge
+ * @mode: the mode to use
+ *
+ * Merges the two given lists into a new list. If one of the lists is NULL, a
+ * copy of the other is returned. If both lists are NULL, NULL is returned.
+ *
+ * Returns: the new list
+ */
+GstTagList *
+gst_tag_list_merge (const GstTagList *list1, const GstTagList *list2, GstTagMergeMode mode)
+{
+ g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL);
+ g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL);
+ g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL);
+
+ if (!list1 && !list2) {
+ return NULL;
+ } else if (!list1) {
+ return gst_tag_list_copy (list2);
+ } else if (!list2) {
+ return gst_tag_list_copy (list1);
+ } else {
+ GstTagList *ret;
+
+ ret = gst_tag_list_copy (list1);
+ gst_tag_list_insert (ret, list2, mode);
+ return ret;
+ }
+}
+/**
+ * gst_tag_list_free:
+ * @list: the list to free
+ *
+ * Frees the given list and all associated values.
+ */
+void
+gst_tag_list_free (GstTagList *list)
+{
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ gst_structure_free ((GstStructure *) list);
+}
+/**
+ * gst_tag_list_get_tag_size:
+ * @list: a taglist
+ * @tag: the tag to query
+ *
+ * Checks how many value are stored in this tag list for the given tag.
+ *
+ * Returns: The number of tags stored
+ */
+guint
+gst_tag_list_get_tag_size (const GstTagList *list, const gchar *tag)
+{
+ const GValue *value;
+
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
+
+ value = gst_structure_get_value ((GstStructure *) list, tag);
+ if (value == NULL)
+ return 0;
+ if (G_VALUE_TYPE (value) != GST_VALUE_TYPE_LIST)
+ return 1;
+
+ return gst_value_list_get_size (value);
+}
+/**
+ * gst_tag_list_add:
+ * @list: list to set tags in
+ * @mode: the mode to use
+ * @tag: tag
+ * @...: values to set
+ *
+ * Sets the values for the given tags using the specified mode.
+ */
+void
+gst_tag_list_add (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
+{
+ va_list args;
+
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+ g_return_if_fail (tag != NULL);
+
+ va_start (args, tag);
+ gst_tag_list_add_valist (list, mode, tag, args);
+ va_end (args);
+}
+/**
+ * gst_tag_list_add_valist:
+ * @list: list to set tags in
+ * @mode: the mode to use
+ * @tag: tag
+ * @var_args: tag / value pairs to set
+ *
+ * Sets the values for the given tags using the specified mode.
+ */
+void
+gst_tag_list_add_valist (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
+{
+ GstTagInfo *info;
+ GQuark quark;
+ gchar *error = NULL;
+
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+ g_return_if_fail (tag != NULL);
+
+ while (tag != NULL) {
+ GValue value = { 0, };
+ quark = g_quark_from_string (tag);
+ info = gst_tag_lookup (quark);
+ g_return_if_fail (info != NULL);
+ g_value_init (&value, info->type);
+ G_VALUE_COLLECT (&value, var_args, 0, &error);
+ if (error) {
+ g_warning ("%s: %s", G_STRLOC, error);
+ g_free (error);
+ /* we purposely leak the value here, it might not be
+ * in a sane state if an error condition occoured
+ */
+ return;
+ }
+ gst_tag_list_add_value_internal (list, mode, quark, &value);
+ g_value_unset (&value);
+ tag = va_arg (var_args, gchar *);
+ }
+}
+/**
+ * gst_tag_list_remove_tag:
+ * @list: list to remove tag from
+ * @tag: tag to remove
+ *
+ * Removes the goven tag from the taglist.
+ */
+void
+gst_tag_list_remove_tag (GstTagList *list, const gchar *tag)
+{
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (tag != NULL);
+
+ gst_structure_remove_field ((GstStructure *) list, tag);
+}
+typedef struct {
+ GstTagForeachFunc func;
+ gpointer data;
+} TagForeachData;
+static void
+structure_foreach_wrapper (GstStructure *structure, GQuark field_id,
+ GValue *value, gpointer user_data)
+{
+ TagForeachData *data = (TagForeachData *) user_data;
+ data->func (GST_TAG_LIST (structure), g_quark_to_string (field_id), data->data);
+}
+/**
+ * gst_tag_list_foreach:
+ * @list: list to iterate over
+ * @func: function to be called for each tag
+ * @user_data: user specified data
+ *
+ * Calls the given function for each tag inside the tag list. Note that if there
+ * is no tag, the function won't be called at all.
+ */
+void
+gst_tag_list_foreach (GstTagList *list, GstTagForeachFunc func, gpointer user_data)
+{
+ TagForeachData data;
+
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (func != NULL);
+
+ data.func = func;
+ data.data = user_data;
+ gst_structure_field_foreach ((GstStructure *) list, structure_foreach_wrapper, &data);
+}
+
+/***** tag events *****/
+
+/**
+ * gst_event_new_tag:
+ * @list: the tag list to put into the event or NULL for an empty list
+ *
+ * Creates a new tag event with the given list and takes ownership of it.
+ *
+ * Returns: a new tag event
+ */
+GstEvent *
+gst_event_new_tag (GstTagList *list)
+{
+ GstEvent *ret;
+
+ g_return_val_if_fail (list == NULL || GST_IS_TAG_LIST (list), NULL);
+
+ ret = gst_event_new (GST_EVENT_TAG);
+ if (!list)
+ list = gst_tag_list_new ();
+ ret->event_data.structure.structure = (GstStructure *) list;
+
+ return ret;
+}
+/**
+ * get_event_tag_get_list:
+ * @tag_event: a tagging #GstEvent
+ *
+ * Gets the taglist from a given tagging event.
+ *
+ * Returns: The #GstTagList of the event
+ */
+GstTagList *
+gst_event_tag_get_list (GstEvent *tag_event)
+{
+ g_return_val_if_fail (GST_IS_EVENT (tag_event), NULL);
+ g_return_val_if_fail (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG, NULL);
+
+ return GST_TAG_LIST (tag_event->event_data.structure.structure);
+}
+
+/**
+ * gst_tag_list_get_value_index:
+ * @list: a #GStTagList
+ * @tag: tag to read out
+ * @index: number of entry to read out
+ *
+ * Gets the value that is at the given index for the given tag in the given
+ * list.
+ *
+ * Returns: The GValue for the specified entry or NULL if the tag wasn't available
+ * or the tag doesn't have as many entries
+ */
+G_CONST_RETURN GValue *
+gst_tag_list_get_value_index (const GstTagList *list, const gchar *tag, guint index)
+{
+ const GValue *value;
+
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
+ g_return_val_if_fail (tag != NULL, NULL);
+
+ value = gst_structure_get_value ((GstStructure *) list, tag);
+ if (value == NULL) return NULL;
+
+ if (GST_VALUE_HOLDS_LIST (value)) {
+ if (index >= gst_value_list_get_size (value)) return NULL;
+ return gst_value_list_get_value (value, index);
+ } else {
+ if (index > 0) return NULL;
+ return value;
+ }
+}
+
+/**
+ * gst_tag_list_copy_value:
+ * @dest: uninitialized #GValue to copy into
+ * @list: list to get the tag from
+ * @tag: tag to read out
+ *
+ * Copies the contents for the given tag into the value, merging multiple values
+ * into one if multiple values are associated with the tag.
+ * You must g_value_unset() the value after use.
+ *
+ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
+ * given list.
+ */
+gboolean
+gst_tag_list_copy_value (GValue *dest, const GstTagList *list, const gchar *tag)
+{
+ const GValue *src;
+
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
+ g_return_val_if_fail (tag != NULL, FALSE);
+ g_return_val_if_fail (dest != NULL, FALSE);
+ g_return_val_if_fail (G_VALUE_TYPE (dest) == 0, FALSE);
+
+ src = gst_structure_get_value ((GstStructure *) list, tag);
+ if (!src) return FALSE;
+
+ if (G_VALUE_TYPE (src) == GST_VALUE_TYPE_LIST) {
+ GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag));
+ /* must be there or lists aren't allowed */
+ g_assert (info->merge_func);
+ info->merge_func (dest, src);
+ } else {
+ g_value_init (dest, G_VALUE_TYPE (src));
+ g_value_copy (src, dest);
+ }
+ return TRUE;
+}
+
+/***** evil macros to get all the gst_tag_list_get_*() functions right *****/
+
+#define TAG_MERGE_FUNCS(name,type) \
+gboolean \
+gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag, \
+ type *value) \
+{ \
+ GValue v = { 0, }; \
+ \
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \
+ g_return_val_if_fail (tag != NULL, FALSE); \
+ g_return_val_if_fail (value != NULL, FALSE); \
+ \
+ if (!gst_tag_list_copy_value (&v, list, tag)) \
+ return FALSE; \
+ *value = COPY_FUNC (g_value_get_ ## name (&v)); \
+ g_value_unset (&v); \
+ return TRUE; \
+} \
+ \
+gboolean \
+gst_tag_list_get_ ## name ## _index (const GstTagList *list, const gchar *tag, \
+ guint index, type *value) \
+{ \
+ const GValue *v; \
+ \
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \
+ g_return_val_if_fail (tag != NULL, FALSE); \
+ g_return_val_if_fail (value != NULL, FALSE); \
+ \
+ if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL) \
+ return FALSE; \
+ *value = COPY_FUNC (g_value_get_ ## name (v)); \
+ return TRUE; \
+}
+
+#define COPY_FUNC /**/
+TAG_MERGE_FUNCS (char, gchar)
+TAG_MERGE_FUNCS (uchar, guchar)
+TAG_MERGE_FUNCS (boolean, gboolean)
+TAG_MERGE_FUNCS (int, gint)
+TAG_MERGE_FUNCS (uint, guint)
+TAG_MERGE_FUNCS (long, glong)
+TAG_MERGE_FUNCS (ulong, gulong)
+TAG_MERGE_FUNCS (int64, gint64)
+TAG_MERGE_FUNCS (uint64, guint64)
+TAG_MERGE_FUNCS (float, gfloat)
+TAG_MERGE_FUNCS (double, gdouble)
+#undef COPY_FUNC
+
+#define COPY_FUNC g_strdup
+TAG_MERGE_FUNCS (string, gchar *)
+
+
+
+
diff --git a/gst/gsttag.h b/gst/gsttag.h
new file mode 100644
index 000000000..6d1efbe5a
--- /dev/null
+++ b/gst/gsttag.h
@@ -0,0 +1,232 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttag.h: Header for tag support
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_TAG_H__
+#define __GST_TAG_H__
+
+#include <gst/gststructure.h>
+#include <gst/gstevent.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GST_TAG_MERGE_UNDEFINED,
+ GST_TAG_MERGE_REPLACE_ALL,
+ GST_TAG_MERGE_REPLACE,
+ GST_TAG_MERGE_APPEND,
+ GST_TAG_MERGE_PREPEND,
+ GST_TAG_MERGE_KEEP,
+ GST_TAG_MERGE_KEEP_ALL,
+ /* add more */
+ GST_TAG_MERGE_COUNT
+} GstTagMergeMode;
+#define GST_TAG_MODE_IS_VALID(mode) (((mode) > GST_TAG_MERGE_UNDEFINED) && ((mode) < GST_TAG_MERGE_COUNT))
+
+typedef GstStructure GstTagList;
+#define GST_TAG_LIST(x) ((GstTagList *) (x))
+#define GST_IS_TAG_LIST(x) (gst_is_tag_list (GST_TAG_LIST (x)))
+
+typedef void (* GstTagForeachFunc) (const GstTagList *list, const gchar *tag, gpointer user_data);
+typedef void (* GstTagMergeFunc) (GValue *dest, const GValue *src);
+
+/* initialize tagging system */
+void _gst_tag_initialize (void);
+
+void gst_tag_register (gchar * name,
+ GType type,
+ gchar * nick,
+ gchar * blurb,
+ GstTagMergeFunc func);
+/* some default merging functions */
+void gst_tag_merge_use_first (GValue * dest,
+ const GValue * values);
+void gst_tag_merge_strings_with_comma (GValue * dest,
+ const GValue * values);
+
+/* basic tag support */
+gboolean gst_tag_exists (const gchar * tag);
+GType gst_tag_get_type (const gchar * tag);
+const gchar * gst_tag_get_nick (const gchar * tag);
+const gchar * gst_tag_get_description (const gchar * tag);
+gboolean gst_tag_is_fixed (const gchar * tag);
+
+/* tag lists */
+GstTagList * gst_tag_list_new (void);
+gboolean gst_is_tag_list (gconstpointer p);
+GstTagList * gst_tag_list_copy (const GstTagList * list);
+void gst_tag_list_insert (GstTagList * into,
+ const GstTagList * from,
+ GstTagMergeMode mode);
+GstTagList * gst_tag_list_merge (const GstTagList * list1,
+ const GstTagList * list2,
+ GstTagMergeMode mode);
+void gst_tag_list_free (GstTagList * list);
+guint gst_tag_list_get_tag_size (const GstTagList * list,
+ const gchar * tag);
+void gst_tag_list_add (GstTagList * list,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ ...);
+void gst_tag_list_add_valist (GstTagList * list,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ va_list var_args);
+void gst_tag_list_remove_tag (GstTagList * list,
+ const gchar * tag);
+void gst_tag_list_foreach (GstTagList * list,
+ GstTagForeachFunc func,
+ gpointer user_data);
+
+G_CONST_RETURN GValue *
+ gst_tag_list_get_value_index (const GstTagList * list,
+ const gchar * tag,
+ guint index);
+gboolean gst_tag_list_copy_value (GValue * dest,
+ const GstTagList * list,
+ const gchar * tag);
+
+/* simplifications (FIXME: do we want them?) */
+gboolean gst_tag_list_get_char (const GstTagList * list,
+ const gchar * tag,
+ gchar * value);
+gboolean gst_tag_list_get_char_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gchar * value);
+gboolean gst_tag_list_get_uchar (const GstTagList * list,
+ const gchar * tag,
+ guchar * value);
+gboolean gst_tag_list_get_uchar_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ guchar * value);
+gboolean gst_tag_list_get_boolean (const GstTagList * list,
+ const gchar * tag,
+ gboolean * value);
+gboolean gst_tag_list_get_boolean_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gboolean * value);
+gboolean gst_tag_list_get_int (const GstTagList * list,
+ const gchar * tag,
+ gint * value);
+gboolean gst_tag_list_get_int_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gint * value);
+gboolean gst_tag_list_get_uint (const GstTagList * list,
+ const gchar * tag,
+ guint * value);
+gboolean gst_tag_list_get_uint_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ guint * value);
+gboolean gst_tag_list_get_long (const GstTagList * list,
+ const gchar * tag,
+ glong * value);
+gboolean gst_tag_list_get_long_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ glong * value);
+gboolean gst_tag_list_get_ulong (const GstTagList * list,
+ const gchar * tag,
+ gulong * value);
+gboolean gst_tag_list_get_ulong_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gulong * value);
+gboolean gst_tag_list_get_int64 (const GstTagList * list,
+ const gchar * tag,
+ gint64 * value);
+gboolean gst_tag_list_get_int64_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gint64 * value);
+gboolean gst_tag_list_get_uint64 (const GstTagList * list,
+ const gchar * tag,
+ guint64 * value);
+gboolean gst_tag_list_get_uint64_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ guint64 * value);
+gboolean gst_tag_list_get_float (const GstTagList * list,
+ const gchar * tag,
+ gfloat * value);
+gboolean gst_tag_list_get_float_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gfloat * value);
+gboolean gst_tag_list_get_double (const GstTagList * list,
+ const gchar * tag,
+ gdouble * value);
+gboolean gst_tag_list_get_double_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gdouble * value);
+gboolean gst_tag_list_get_string (const GstTagList * list,
+ const gchar * tag,
+ gchar ** value);
+gboolean gst_tag_list_get_string_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gchar ** value);
+gboolean gst_tag_list_get_pointer (const GstTagList * list,
+ const gchar * tag,
+ gpointer * value);
+gboolean gst_tag_list_get_pointer_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gpointer * value);
+
+/* tag events */
+GstEvent * gst_event_new_tag (GstTagList * list);
+GstTagList * gst_event_tag_get_list (GstEvent * tag_event);
+
+
+/* GStreamer core tags (need to be discussed) */
+#define GST_TAG_TITLE "title"
+#define GST_TAG_ARTIST "artist"
+#define GST_TAG_ALBUM "album"
+#define GST_TAG_DATE "date"
+#define GST_TAG_GENRE "genre"
+#define GST_TAG_COMMENT "comment"
+#define GST_TAG_TRACK_NUMBER "track-number"
+#define GST_TAG_TRACK_COUNT "track-count"
+#define GST_TAG_LOCATION "location"
+#define GST_TAG_DESCRIPTION "description"
+#define GST_TAG_VERSION "version"
+#define GST_TAG_ISRC "isrc"
+#define GST_TAG_ORGANIZATION "organization"
+#define GST_TAG_COPYRIGHT "copyright"
+#define GST_TAG_CONTACT "contact"
+#define GST_TAG_LICENSE "license"
+#define GST_TAG_PERFORMER "performer"
+#define GST_TAG_DURATION "duration"
+#define GST_TAG_CODEC "codec"
+#define GST_TAG_BITRATE "bitrate"
+#define GST_TAG_MINIMUM_BITRATE "minimum-bitrate"
+#define GST_TAG_MAXIMUM_BITRATE "maximum-bitrate"
+
+
+G_END_DECLS
+
+#endif /* __GST_EVENT_H__ */
diff --git a/gst/gsttaginterface.c b/gst/gsttaginterface.c
new file mode 100644
index 000000000..a7e6d7134
--- /dev/null
+++ b/gst/gsttaginterface.c
@@ -0,0 +1,214 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttaginterface.c: interface for tag setting on elements
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gsttaginterface.h"
+#include <gobject/gvaluecollector.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_tag_interface_debug);
+#define GST_CAT_DEFAULT tag_tag_interface_debug
+
+static GQuark gst_tag_key;
+
+typedef struct {
+ GstTagMergeMode mode;
+ GstTagList * list;
+} GstTagData;
+
+GType
+gst_tag_setter_get_type (void)
+{
+ static GType tag_setter_type = 0;
+
+ if (! tag_setter_type) {
+ static const GTypeInfo tag_setter_info = {
+ sizeof (GstTagSetterIFace), /* class_size */
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0,
+ NULL
+ };
+
+ GST_DEBUG_CATEGORY_INIT (gst_tag_interface_debug, "GstTagInterface", 0, "interfaces for tagging");
+
+ tag_setter_type = g_type_register_static (G_TYPE_INTERFACE, "GstTagSetter",
+ &tag_setter_info, 0);
+
+ g_type_interface_add_prerequisite (tag_setter_type, GST_TYPE_ELEMENT);
+
+ gst_tag_key = g_quark_from_static_string ("GST_TAG_SETTER");
+ }
+
+ return tag_setter_type;
+}
+static void
+gst_tag_data_free (gpointer p)
+{
+ GstTagData *data = (GstTagData *) p;
+
+ if (data->list)
+ gst_tag_list_free (data->list);
+
+ g_free (data);
+}
+static GstTagData *
+gst_tag_setter_get_data (GstTagSetter *setter)
+{
+ GstTagData *data;
+
+ data = g_object_get_qdata (G_OBJECT (setter), gst_tag_key);
+ if (!data) {
+ data = g_new (GstTagData, 1);
+ data->list = NULL;
+ data->mode = GST_TAG_MERGE_KEEP;
+ g_object_set_qdata_full (G_OBJECT (setter), gst_tag_key, data, gst_tag_data_free);
+ }
+
+ return data;
+}
+/**
+ * gst_tag_setter_merge:
+ * @setter: a #GstTagSetter
+ * @list: a tag list to merge from
+ * @mode: the mode to merge with
+ *
+ * Merges the given list into the setter's list using the given mode.
+ */
+void
+gst_tag_setter_merge (GstTagSetter *setter, const GstTagList *list, GstTagMergeMode mode)
+{
+ GstTagData *data;
+
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ data = gst_tag_setter_get_data (setter);
+ if (!data->list) {
+ data->list = gst_tag_list_copy (list);
+ } else {
+ gst_tag_list_merge (data->list, list, mode);
+ }
+}
+/**
+ * gst_tag_setter_add:
+ * @setter: a #GstTagSetter
+ * @mode: the mode to use
+ * @tag: tag to set
+ * @...: more tag / value pairs to set
+ *
+ * Adds the given tag / value pairs on the setter using the given merge mode.
+ * The list must be terminated with GST_TAG_INVALID.
+ */
+void
+gst_tag_setter_add (GstTagSetter *setter, GstTagMergeMode mode, const gchar *tag, ...)
+{
+ va_list args;
+
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ va_start (args, tag);
+ gst_tag_setter_add_valist (setter, mode, tag, args);
+ va_end (args);
+}
+/**
+ * gst_tag_setter_add_valist:
+ * @setter: a #GstTagSetter
+ * @mode: the mode to use
+ * @tag: tag to set
+ * @var_args: tag / value pairs to set
+ *
+ * Adds the given tag / value pairs on the setter using the given merge mode.
+ * The list must be terminated with GST_TAG_INVALID.
+ */
+void
+gst_tag_setter_add_valist (GstTagSetter *setter, GstTagMergeMode mode, const gchar *tag, va_list var_args)
+{
+ GstTagData *data;
+
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ data = gst_tag_setter_get_data (setter);
+ if (!data->list)
+ data->list = gst_tag_list_new ();
+
+ gst_tag_list_add_valist (data->list, mode, tag, var_args);
+}
+/**
+ * gst_tag_setter_get_list:
+ * @setter: a #GstTagSetter
+ *
+ * Retrieves a copy of the current list of tags the setter uses.
+ * You need to gst_tag_list_free() the list after use.
+ *
+ * Returns: a current snapshot of the taglist used in the setter
+ * or NULL if none is used.
+ */
+const GstTagList *
+gst_tag_setter_get_list (GstTagSetter *setter)
+{
+ g_return_val_if_fail (GST_IS_TAG_SETTER (setter), NULL);
+
+ return gst_tag_setter_get_data (setter)->list;
+}
+/**
+ * gst_tag_setter_set_merge_mode:
+ * @setter: a #GstTagSetter
+ * @overwrite: The mode with which tags are added
+ *
+ * Sets the given merge mode that is used for adding tags from events to tags
+ * specified by this interface. The default is #GST_TAG_MERGE_KEEP, which keeps
+ * the tags by this interface and discards tags from events.
+ */
+void
+gst_tag_setter_set_merge_mode (GstTagSetter *setter, GstTagMergeMode mode)
+{
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ gst_tag_setter_get_data (setter)->mode = mode;
+}
+/**
+ * gst_tag_setter_get_merge_mode:
+ * @setter: a #GstTagSetter
+ *
+ * Queries the mode by which tags inside the setter are overwritten by tags
+ * from events
+ *
+ * Returns: the merge mode used inside the element.
+ */
+GstTagMergeMode
+gst_tag_setter_get_merge_mode (GstTagSetter *setter)
+{
+ g_return_val_if_fail (GST_IS_TAG_SETTER (setter), FALSE);
+
+ return gst_tag_setter_get_data (setter)->mode;
+}
diff --git a/gst/gsttaginterface.h b/gst/gsttaginterface.h
new file mode 100644
index 000000000..cb8513791
--- /dev/null
+++ b/gst/gsttaginterface.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttaginterface.h: Interfaces for tagging
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_TAG_INTERFACE_H__
+#define __GST_TAG_INTERFACE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_TAG_SETTER (gst_tag_setter_get_type ())
+#define GST_TAG_SETTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TAG_SETTER, GstTagSetter))
+#define GST_TAG_SETTER_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GST_TYPE_TAG_SETTER, GstTagSetter))
+#define GST_IS_TAG_SETTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TAG_SETTER))
+#define GST_TAG_SETTER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GST_TYPE_TAG_SETTER, GstTagSetterIFace))
+
+typedef struct _GstTagSetter GstTagSetter; /* Dummy typedef */
+typedef struct _GstTagSetterIFace GstTagSetterIFace;
+
+/* use an empty interface here to allow detection of elements using user-set
+ tags */
+struct _GstTagSetterIFace
+{
+ GTypeInterface g_iface;
+
+ /* signals */
+
+ /* virtual table */
+};
+
+GType gst_tag_setter_get_type (void) G_GNUC_CONST;
+
+void gst_tag_setter_merge (GstTagSetter * setter,
+ const GstTagList * list,
+ GstTagMergeMode mode);
+void gst_tag_setter_add (GstTagSetter * setter,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ ...);
+void gst_tag_setter_add_valist (GstTagSetter * setter,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ va_list var_args);
+const GstTagList *gst_tag_setter_get_list (GstTagSetter * setter);
+
+void gst_tag_setter_set_merge_mode (GstTagSetter * setter,
+ GstTagMergeMode mode);
+GstTagMergeMode gst_tag_setter_get_merge_mode (GstTagSetter * setter);
+
+G_END_DECLS
+
+#endif /* __GST_TAG_INTERFACE_H__ */
diff --git a/gst/gsttaglist.c b/gst/gsttaglist.c
new file mode 100644
index 000000000..c6c4f3f11
--- /dev/null
+++ b/gst/gsttaglist.c
@@ -0,0 +1,831 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttag.c: tag support (aka metadata)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gst_private.h"
+#include "gsttag.h"
+#include "gstinfo.h"
+#include "gstvalue.h"
+
+#include <gobject/gvaluecollector.h>
+#include <string.h>
+
+#define GST_TAG_IS_VALID(tag) (gst_tag_get_info (tag) != NULL)
+
+typedef struct {
+ GType type; /* type the data is in */
+
+ gchar * nick; /* translated name */
+ gchar * blurb; /* translated description of type */
+
+ GstTagMergeFunc merge_func; /* functions to merge the values */
+} GstTagInfo;
+
+#define TAGLIST "taglist"
+static GQuark gst_tag_list_quark;
+static GMutex *__tag_mutex;
+static GHashTable *__tags;
+#define TAG_LOCK g_mutex_lock (__tag_mutex)
+#define TAG_UNLOCK g_mutex_unlock (__tag_mutex)
+
+void
+_gst_tag_initialize (void)
+{
+ gst_tag_list_quark = g_quark_from_static_string (TAGLIST);
+ __tag_mutex = g_mutex_new ();
+ __tags = g_hash_table_new (g_direct_hash, g_direct_equal);
+ gst_tag_register (GST_TAG_TITLE,
+ G_TYPE_STRING,
+ _("title"),
+ _("commonly used title"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_ARTIST,
+ G_TYPE_STRING,
+ _("artist"),
+ _("person(s) resposible for the recording"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_ALBUM,
+ G_TYPE_STRING,
+ _("album"),
+ _("album containing this data"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_DATE,
+ G_TYPE_UINT, /* FIXME: own data type for dates? */
+ _("date"),
+ _("date the data was created in julien days"),
+ NULL);
+ gst_tag_register (GST_TAG_GENRE,
+ G_TYPE_STRING,
+ _("genre"),
+ _("genre this data belongs to"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_COMMENT,
+ G_TYPE_STRING,
+ _("comment"),
+ _("free text commenting the data"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_TRACK_NUMBER,
+ G_TYPE_UINT,
+ _("track number"),
+ _("track number inside a collection"),
+ gst_tag_merge_use_first);
+ gst_tag_register (GST_TAG_TRACK_COUNT,
+ G_TYPE_STRING,
+ _("track count"),
+ _("count of tracks inside collection this track belongs to"),
+ gst_tag_merge_use_first);
+ gst_tag_register (GST_TAG_LOCATION,
+ G_TYPE_STRING,
+ _("loccation"),
+ _("original location of file as a URI"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_DESCRIPTION,
+ G_TYPE_STRING,
+ _("description"),
+ _("short text describing the content of the data"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_VERSION,
+ G_TYPE_STRING,
+ _("version"),
+ _("version of this data"),
+ NULL);
+ gst_tag_register (GST_TAG_ISRC,
+ G_TYPE_STRING,
+ _("ISRC"),
+ _("International Standard Recording Code - see http://www.ifpi.org/isrc/"),
+ NULL);
+ gst_tag_register (GST_TAG_ORGANIZATION,
+ G_TYPE_STRING,
+ _("organization"),
+ _("organization"), /* FIXME */
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_COPYRIGHT,
+ G_TYPE_STRING,
+ _("copyright"),
+ _("copyright notice of the data"),
+ NULL);
+ gst_tag_register (GST_TAG_CONTACT,
+ G_TYPE_STRING,
+ _("contact"),
+ _("contact information"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_LICENSE,
+ G_TYPE_STRING,
+ _("license"),
+ _("license of data"),
+ NULL);
+ gst_tag_register (GST_TAG_PERFORMER,
+ G_TYPE_STRING,
+ _("performer"),
+ _("person(s) performing"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_DURATION,
+ G_TYPE_UINT64,
+ _("duration"),
+ _("length in GStreamer time units (nanoseconds)"),
+ NULL);
+ gst_tag_register (GST_TAG_CODEC,
+ G_TYPE_STRING,
+ _("codec"),
+ _("codec the data is stored in"),
+ gst_tag_merge_strings_with_comma);
+ gst_tag_register (GST_TAG_MINIMUM_BITRATE,
+ G_TYPE_UINT,
+ _("minimum bitrate"),
+ _("minimum bitrate in bits/s"),
+ NULL);
+ gst_tag_register (GST_TAG_BITRATE,
+ G_TYPE_UINT,
+ _("bitrate"),
+ _("exact or average bitrate in bits/s"),
+ NULL);
+ gst_tag_register (GST_TAG_MAXIMUM_BITRATE,
+ G_TYPE_UINT,
+ _("maximum bitrate"),
+ _("maximum bitrate in bits/s"),
+ NULL);
+}
+/**
+ * gst_tag_merge_use_first:
+ * @dest: uninitialized GValue to store result in
+ * @src: GValue to copy from
+ *
+ * This is a convenience function for the func argument of gst_tag_register().
+ * It creates a copy of the first value from the list.
+ */
+void
+gst_tag_merge_use_first (GValue *dest, const GValue *src)
+{
+ const GValue *ret = gst_value_list_get_value (src, 0);
+
+ g_value_init (dest, G_VALUE_TYPE (ret));
+ g_value_copy (ret, dest);
+}
+/**
+ * gst_tag_merge_strings_with_comma:
+ * @dest: uninitialized GValue to store result in
+ * @src: GValue to copy from
+ *
+ * This is a convenience function for the func argument of gst_tag_register().
+ * It concatenates all given strings using a comma. The tag must be registered
+ * as a G_TYPE_STRING or this function will fail.
+ */
+void
+gst_tag_merge_strings_with_comma (GValue *dest, const GValue *src)
+{
+ GString *str;
+ gint i, count;
+
+ count = gst_value_list_get_size (src);
+ str = g_string_new (g_value_get_string (gst_value_list_get_value (src, 0)));
+ for (i = 1; i < count; i++) {
+ /* seperator between two string */
+ str = g_string_append (str, _(", "));
+ str = g_string_append (str, g_value_get_string (gst_value_list_get_value (src, 1)));
+ }
+
+ g_value_init (dest, G_TYPE_STRING);
+ g_value_take_string (dest, str->str);
+ g_string_free (str, FALSE);
+}
+static GstTagInfo *
+gst_tag_lookup (GQuark entry)
+{
+ GstTagInfo *ret;
+
+ TAG_LOCK;
+ ret = g_hash_table_lookup (__tags, GUINT_TO_POINTER (entry));
+ TAG_UNLOCK;
+
+ return ret;
+}
+/**
+ * gst_tag_register:
+ * @name: the name or identifier string
+ * @type: the type this data is in
+ * @nick: human-readable name
+ * @blurb: a human-readable description about this tag
+ * @func: function for merging multiple values of this tag
+ *
+ * Registers a new tag type for the use with GStreamer's type system. If a type
+ * with that name is already registered, that one is used.
+ * The old registration may have used a different type however. So don't rely
+ * on youre supplied values.
+ * If you know the type is already registered, use gst_tag_lookup instead.
+ * This function takes ownership of all supplied variables.
+ */
+void
+gst_tag_register (gchar *name, GType type, gchar *nick, gchar *blurb,
+ GstTagMergeFunc func)
+{
+ GQuark key;
+ GstTagInfo *info;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (nick != NULL);
+ g_return_if_fail (blurb != NULL);
+ g_return_if_fail (type != 0 && type != GST_VALUE_TYPE_LIST);
+
+ key = g_quark_from_string (name);
+ info = gst_tag_lookup (key);
+ g_return_if_fail (info == NULL);
+
+ info = g_new (GstTagInfo, 1);
+ info->type = type;
+ info->nick = nick;
+ info->blurb = blurb;
+ info->merge_func = func;
+
+ TAG_LOCK;
+ g_hash_table_insert (__tags, GUINT_TO_POINTER (key), info);
+ TAG_UNLOCK;
+}
+/**
+ * gst_tag_exists:
+ * @tag: name of the tag
+ *
+ * Checks if the given type is already registered.
+ *
+ * Returns: TRUE if the type is already registered
+ */
+gboolean
+gst_tag_exists (const gchar *tag)
+{
+ g_return_val_if_fail (tag != NULL, FALSE);
+
+ return gst_tag_lookup (g_quark_from_string (tag)) != NULL;
+}
+/**
+ * gst_tag_get_type:
+ * @tag: the tag
+ *
+ * Gets the #GType used for this tag.
+ *
+ * Returns: the #GType of this tag
+ */
+GType
+gst_tag_get_type (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, 0);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, 0);
+
+ return info->type;
+}
+/**
+ * gst_tag_get_nick
+ * @tag: the tag
+ *
+ * Returns the human-readable name of this tag, You must not change or free
+ * this string.
+ *
+ * Returns: the human-readable name of this tag
+ */
+const gchar *
+gst_tag_get_nick (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, NULL);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->nick;
+}
+/**
+ * gst_tag_get_description:
+ * @tag: the tag
+ *
+ * Returns the human-readable description of this tag, You must not change or
+ * free this string.
+ *
+ * Return the human-readable description of this tag
+ */
+const gchar *
+gst_tag_get_description (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, NULL);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->blurb;
+}
+/**
+ * gst_tag_list_is_fixed:
+ * @tag: tag to check
+ *
+ * Checks if the given tag is fixed. A fixed tag can only contain one value.
+ * Unfixed tags can contain lists of values.
+ *
+ * Returns: TRUE, if the given tag is fixed.
+ */
+gboolean
+gst_tag_is_fixed (const gchar *tag)
+{
+ GstTagInfo *info;
+
+ g_return_val_if_fail (tag != NULL, FALSE);
+ info = gst_tag_lookup (g_quark_from_string (tag));
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return info->merge_func == NULL;
+}
+/**
+ * gst_tag_list_new:
+ *
+ * Creates a new empty GstTagList.
+ *
+ * Returns: An empty tag list
+ */
+GstTagList *
+gst_tag_list_new (void)
+{
+ return GST_TAG_LIST (gst_structure_new (TAGLIST, NULL));
+}
+/**
+ * gst_is_tag_list:
+ * @p: Object that might be a taglist
+ *
+ * Checks if the given pointer is a taglist.
+ *
+ * Returns: TRUE, if the given pointer is a taglist
+ */
+gboolean
+gst_is_tag_list (gconstpointer p)
+{
+ g_return_val_if_fail (p != NULL, FALSE);
+
+ return ((GstStructure *) p)->name == gst_tag_list_quark;
+}
+typedef struct {
+ GstStructure * list;
+ GstTagMergeMode mode;
+} GstTagCopyData;
+static void
+gst_tag_list_add_value_internal (GstStructure *list, GstTagMergeMode mode, GQuark tag, GValue *value)
+{
+ GstTagInfo *info = gst_tag_lookup (tag);
+ GstStructureField *field;
+
+ g_assert (info != NULL);
+
+ if (info->merge_func && (field = gst_structure_id_get_field (list, tag)) != NULL) {
+ GValue value2 = { 0, };
+ switch (mode) {
+ case GST_TAG_MERGE_REPLACE_ALL:
+ case GST_TAG_MERGE_REPLACE:
+ gst_structure_id_set_value (list, tag, value);
+ break;
+ case GST_TAG_MERGE_PREPEND:
+ gst_value_list_concat (&value2, value, &field->value);
+ gst_structure_id_set_value (list, tag, &value2);
+ g_value_unset (&value2);
+ break;
+ case GST_TAG_MERGE_APPEND:
+ gst_value_list_concat (&value2, &field->value, value);
+ gst_structure_id_set_value (list, tag, &value2);
+ g_value_unset (&value2);
+ break;
+ case GST_TAG_MERGE_KEEP:
+ case GST_TAG_MERGE_KEEP_ALL:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ } else {
+ switch (mode) {
+ case GST_TAG_MERGE_APPEND:
+ case GST_TAG_MERGE_KEEP:
+ if (gst_structure_id_get_field (list, tag) != NULL)
+ break;
+ /* fall through */
+ case GST_TAG_MERGE_REPLACE_ALL:
+ case GST_TAG_MERGE_REPLACE:
+ case GST_TAG_MERGE_PREPEND:
+ gst_structure_id_set_value (list, tag, value);
+ break;
+ case GST_TAG_MERGE_KEEP_ALL:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+}
+static void
+gst_tag_list_copy_foreach (GstStructure *structure, GQuark tag, GValue *value, gpointer user_data)
+{
+ GstTagCopyData *copy = (GstTagCopyData *) user_data;
+
+ gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value);
+}
+/**
+ * gst_tag_list_insert:
+ * @into: list to merge into
+ * @from: list to merge from
+ * @mode: the mode to use
+ *
+ * Inserts the tags of the second list into the first list using the given mode.
+ */
+void
+gst_tag_list_insert (GstTagList *into, const GstTagList *from, GstTagMergeMode mode)
+{
+ GstTagCopyData data;
+
+ g_return_if_fail (GST_IS_TAG_LIST (into));
+ g_return_if_fail (GST_IS_TAG_LIST (from));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ data.list = (GstStructure *) into;
+ data.mode = mode;
+ if (mode == GST_TAG_MERGE_REPLACE_ALL) {
+ gst_structure_remove_all_fields (data.list);
+ }
+ gst_structure_field_foreach ((GstStructure *) from, gst_tag_list_copy_foreach, &data);
+}
+/**
+ * gst_tag_list_copy:
+ * @list: list to copy
+ *
+ * Copies a given #GstTagList.
+ *
+ * Returns: copy of the given list
+ */
+GstTagList *
+gst_tag_list_copy (const GstTagList *list)
+{
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
+
+ return GST_TAG_LIST (gst_structure_copy ((GstStructure *) list));
+}
+/**
+ * gst_tag_list_merge:
+ * @list1: first list to merge
+ * @list2: second list to merge
+ * @mode: the mode to use
+ *
+ * Merges the two given lists into a new list. If one of the lists is NULL, a
+ * copy of the other is returned. If both lists are NULL, NULL is returned.
+ *
+ * Returns: the new list
+ */
+GstTagList *
+gst_tag_list_merge (const GstTagList *list1, const GstTagList *list2, GstTagMergeMode mode)
+{
+ g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL);
+ g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL);
+ g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL);
+
+ if (!list1 && !list2) {
+ return NULL;
+ } else if (!list1) {
+ return gst_tag_list_copy (list2);
+ } else if (!list2) {
+ return gst_tag_list_copy (list1);
+ } else {
+ GstTagList *ret;
+
+ ret = gst_tag_list_copy (list1);
+ gst_tag_list_insert (ret, list2, mode);
+ return ret;
+ }
+}
+/**
+ * gst_tag_list_free:
+ * @list: the list to free
+ *
+ * Frees the given list and all associated values.
+ */
+void
+gst_tag_list_free (GstTagList *list)
+{
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ gst_structure_free ((GstStructure *) list);
+}
+/**
+ * gst_tag_list_get_tag_size:
+ * @list: a taglist
+ * @tag: the tag to query
+ *
+ * Checks how many value are stored in this tag list for the given tag.
+ *
+ * Returns: The number of tags stored
+ */
+guint
+gst_tag_list_get_tag_size (const GstTagList *list, const gchar *tag)
+{
+ const GValue *value;
+
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
+
+ value = gst_structure_get_value ((GstStructure *) list, tag);
+ if (value == NULL)
+ return 0;
+ if (G_VALUE_TYPE (value) != GST_VALUE_TYPE_LIST)
+ return 1;
+
+ return gst_value_list_get_size (value);
+}
+/**
+ * gst_tag_list_add:
+ * @list: list to set tags in
+ * @mode: the mode to use
+ * @tag: tag
+ * @...: values to set
+ *
+ * Sets the values for the given tags using the specified mode.
+ */
+void
+gst_tag_list_add (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
+{
+ va_list args;
+
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+ g_return_if_fail (tag != NULL);
+
+ va_start (args, tag);
+ gst_tag_list_add_valist (list, mode, tag, args);
+ va_end (args);
+}
+/**
+ * gst_tag_list_add_valist:
+ * @list: list to set tags in
+ * @mode: the mode to use
+ * @tag: tag
+ * @var_args: tag / value pairs to set
+ *
+ * Sets the values for the given tags using the specified mode.
+ */
+void
+gst_tag_list_add_valist (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
+{
+ GstTagInfo *info;
+ GQuark quark;
+ gchar *error = NULL;
+
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+ g_return_if_fail (tag != NULL);
+
+ while (tag != NULL) {
+ GValue value = { 0, };
+ quark = g_quark_from_string (tag);
+ info = gst_tag_lookup (quark);
+ g_return_if_fail (info != NULL);
+ g_value_init (&value, info->type);
+ G_VALUE_COLLECT (&value, var_args, 0, &error);
+ if (error) {
+ g_warning ("%s: %s", G_STRLOC, error);
+ g_free (error);
+ /* we purposely leak the value here, it might not be
+ * in a sane state if an error condition occoured
+ */
+ return;
+ }
+ gst_tag_list_add_value_internal (list, mode, quark, &value);
+ g_value_unset (&value);
+ tag = va_arg (var_args, gchar *);
+ }
+}
+/**
+ * gst_tag_list_remove_tag:
+ * @list: list to remove tag from
+ * @tag: tag to remove
+ *
+ * Removes the goven tag from the taglist.
+ */
+void
+gst_tag_list_remove_tag (GstTagList *list, const gchar *tag)
+{
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (tag != NULL);
+
+ gst_structure_remove_field ((GstStructure *) list, tag);
+}
+typedef struct {
+ GstTagForeachFunc func;
+ gpointer data;
+} TagForeachData;
+static void
+structure_foreach_wrapper (GstStructure *structure, GQuark field_id,
+ GValue *value, gpointer user_data)
+{
+ TagForeachData *data = (TagForeachData *) user_data;
+ data->func (GST_TAG_LIST (structure), g_quark_to_string (field_id), data->data);
+}
+/**
+ * gst_tag_list_foreach:
+ * @list: list to iterate over
+ * @func: function to be called for each tag
+ * @user_data: user specified data
+ *
+ * Calls the given function for each tag inside the tag list. Note that if there
+ * is no tag, the function won't be called at all.
+ */
+void
+gst_tag_list_foreach (GstTagList *list, GstTagForeachFunc func, gpointer user_data)
+{
+ TagForeachData data;
+
+ g_return_if_fail (GST_IS_TAG_LIST (list));
+ g_return_if_fail (func != NULL);
+
+ data.func = func;
+ data.data = user_data;
+ gst_structure_field_foreach ((GstStructure *) list, structure_foreach_wrapper, &data);
+}
+
+/***** tag events *****/
+
+/**
+ * gst_event_new_tag:
+ * @list: the tag list to put into the event or NULL for an empty list
+ *
+ * Creates a new tag event with the given list and takes ownership of it.
+ *
+ * Returns: a new tag event
+ */
+GstEvent *
+gst_event_new_tag (GstTagList *list)
+{
+ GstEvent *ret;
+
+ g_return_val_if_fail (list == NULL || GST_IS_TAG_LIST (list), NULL);
+
+ ret = gst_event_new (GST_EVENT_TAG);
+ if (!list)
+ list = gst_tag_list_new ();
+ ret->event_data.structure.structure = (GstStructure *) list;
+
+ return ret;
+}
+/**
+ * get_event_tag_get_list:
+ * @tag_event: a tagging #GstEvent
+ *
+ * Gets the taglist from a given tagging event.
+ *
+ * Returns: The #GstTagList of the event
+ */
+GstTagList *
+gst_event_tag_get_list (GstEvent *tag_event)
+{
+ g_return_val_if_fail (GST_IS_EVENT (tag_event), NULL);
+ g_return_val_if_fail (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG, NULL);
+
+ return GST_TAG_LIST (tag_event->event_data.structure.structure);
+}
+
+/**
+ * gst_tag_list_get_value_index:
+ * @list: a #GStTagList
+ * @tag: tag to read out
+ * @index: number of entry to read out
+ *
+ * Gets the value that is at the given index for the given tag in the given
+ * list.
+ *
+ * Returns: The GValue for the specified entry or NULL if the tag wasn't available
+ * or the tag doesn't have as many entries
+ */
+G_CONST_RETURN GValue *
+gst_tag_list_get_value_index (const GstTagList *list, const gchar *tag, guint index)
+{
+ const GValue *value;
+
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
+ g_return_val_if_fail (tag != NULL, NULL);
+
+ value = gst_structure_get_value ((GstStructure *) list, tag);
+ if (value == NULL) return NULL;
+
+ if (GST_VALUE_HOLDS_LIST (value)) {
+ if (index >= gst_value_list_get_size (value)) return NULL;
+ return gst_value_list_get_value (value, index);
+ } else {
+ if (index > 0) return NULL;
+ return value;
+ }
+}
+
+/**
+ * gst_tag_list_copy_value:
+ * @dest: uninitialized #GValue to copy into
+ * @list: list to get the tag from
+ * @tag: tag to read out
+ *
+ * Copies the contents for the given tag into the value, merging multiple values
+ * into one if multiple values are associated with the tag.
+ * You must g_value_unset() the value after use.
+ *
+ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
+ * given list.
+ */
+gboolean
+gst_tag_list_copy_value (GValue *dest, const GstTagList *list, const gchar *tag)
+{
+ const GValue *src;
+
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
+ g_return_val_if_fail (tag != NULL, FALSE);
+ g_return_val_if_fail (dest != NULL, FALSE);
+ g_return_val_if_fail (G_VALUE_TYPE (dest) == 0, FALSE);
+
+ src = gst_structure_get_value ((GstStructure *) list, tag);
+ if (!src) return FALSE;
+
+ if (G_VALUE_TYPE (src) == GST_VALUE_TYPE_LIST) {
+ GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag));
+ /* must be there or lists aren't allowed */
+ g_assert (info->merge_func);
+ info->merge_func (dest, src);
+ } else {
+ g_value_init (dest, G_VALUE_TYPE (src));
+ g_value_copy (src, dest);
+ }
+ return TRUE;
+}
+
+/***** evil macros to get all the gst_tag_list_get_*() functions right *****/
+
+#define TAG_MERGE_FUNCS(name,type) \
+gboolean \
+gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag, \
+ type *value) \
+{ \
+ GValue v = { 0, }; \
+ \
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \
+ g_return_val_if_fail (tag != NULL, FALSE); \
+ g_return_val_if_fail (value != NULL, FALSE); \
+ \
+ if (!gst_tag_list_copy_value (&v, list, tag)) \
+ return FALSE; \
+ *value = COPY_FUNC (g_value_get_ ## name (&v)); \
+ g_value_unset (&v); \
+ return TRUE; \
+} \
+ \
+gboolean \
+gst_tag_list_get_ ## name ## _index (const GstTagList *list, const gchar *tag, \
+ guint index, type *value) \
+{ \
+ const GValue *v; \
+ \
+ g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \
+ g_return_val_if_fail (tag != NULL, FALSE); \
+ g_return_val_if_fail (value != NULL, FALSE); \
+ \
+ if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL) \
+ return FALSE; \
+ *value = COPY_FUNC (g_value_get_ ## name (v)); \
+ return TRUE; \
+}
+
+#define COPY_FUNC /**/
+TAG_MERGE_FUNCS (char, gchar)
+TAG_MERGE_FUNCS (uchar, guchar)
+TAG_MERGE_FUNCS (boolean, gboolean)
+TAG_MERGE_FUNCS (int, gint)
+TAG_MERGE_FUNCS (uint, guint)
+TAG_MERGE_FUNCS (long, glong)
+TAG_MERGE_FUNCS (ulong, gulong)
+TAG_MERGE_FUNCS (int64, gint64)
+TAG_MERGE_FUNCS (uint64, guint64)
+TAG_MERGE_FUNCS (float, gfloat)
+TAG_MERGE_FUNCS (double, gdouble)
+#undef COPY_FUNC
+
+#define COPY_FUNC g_strdup
+TAG_MERGE_FUNCS (string, gchar *)
+
+
+
+
diff --git a/gst/gsttaglist.h b/gst/gsttaglist.h
new file mode 100644
index 000000000..6d1efbe5a
--- /dev/null
+++ b/gst/gsttaglist.h
@@ -0,0 +1,232 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttag.h: Header for tag support
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_TAG_H__
+#define __GST_TAG_H__
+
+#include <gst/gststructure.h>
+#include <gst/gstevent.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GST_TAG_MERGE_UNDEFINED,
+ GST_TAG_MERGE_REPLACE_ALL,
+ GST_TAG_MERGE_REPLACE,
+ GST_TAG_MERGE_APPEND,
+ GST_TAG_MERGE_PREPEND,
+ GST_TAG_MERGE_KEEP,
+ GST_TAG_MERGE_KEEP_ALL,
+ /* add more */
+ GST_TAG_MERGE_COUNT
+} GstTagMergeMode;
+#define GST_TAG_MODE_IS_VALID(mode) (((mode) > GST_TAG_MERGE_UNDEFINED) && ((mode) < GST_TAG_MERGE_COUNT))
+
+typedef GstStructure GstTagList;
+#define GST_TAG_LIST(x) ((GstTagList *) (x))
+#define GST_IS_TAG_LIST(x) (gst_is_tag_list (GST_TAG_LIST (x)))
+
+typedef void (* GstTagForeachFunc) (const GstTagList *list, const gchar *tag, gpointer user_data);
+typedef void (* GstTagMergeFunc) (GValue *dest, const GValue *src);
+
+/* initialize tagging system */
+void _gst_tag_initialize (void);
+
+void gst_tag_register (gchar * name,
+ GType type,
+ gchar * nick,
+ gchar * blurb,
+ GstTagMergeFunc func);
+/* some default merging functions */
+void gst_tag_merge_use_first (GValue * dest,
+ const GValue * values);
+void gst_tag_merge_strings_with_comma (GValue * dest,
+ const GValue * values);
+
+/* basic tag support */
+gboolean gst_tag_exists (const gchar * tag);
+GType gst_tag_get_type (const gchar * tag);
+const gchar * gst_tag_get_nick (const gchar * tag);
+const gchar * gst_tag_get_description (const gchar * tag);
+gboolean gst_tag_is_fixed (const gchar * tag);
+
+/* tag lists */
+GstTagList * gst_tag_list_new (void);
+gboolean gst_is_tag_list (gconstpointer p);
+GstTagList * gst_tag_list_copy (const GstTagList * list);
+void gst_tag_list_insert (GstTagList * into,
+ const GstTagList * from,
+ GstTagMergeMode mode);
+GstTagList * gst_tag_list_merge (const GstTagList * list1,
+ const GstTagList * list2,
+ GstTagMergeMode mode);
+void gst_tag_list_free (GstTagList * list);
+guint gst_tag_list_get_tag_size (const GstTagList * list,
+ const gchar * tag);
+void gst_tag_list_add (GstTagList * list,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ ...);
+void gst_tag_list_add_valist (GstTagList * list,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ va_list var_args);
+void gst_tag_list_remove_tag (GstTagList * list,
+ const gchar * tag);
+void gst_tag_list_foreach (GstTagList * list,
+ GstTagForeachFunc func,
+ gpointer user_data);
+
+G_CONST_RETURN GValue *
+ gst_tag_list_get_value_index (const GstTagList * list,
+ const gchar * tag,
+ guint index);
+gboolean gst_tag_list_copy_value (GValue * dest,
+ const GstTagList * list,
+ const gchar * tag);
+
+/* simplifications (FIXME: do we want them?) */
+gboolean gst_tag_list_get_char (const GstTagList * list,
+ const gchar * tag,
+ gchar * value);
+gboolean gst_tag_list_get_char_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gchar * value);
+gboolean gst_tag_list_get_uchar (const GstTagList * list,
+ const gchar * tag,
+ guchar * value);
+gboolean gst_tag_list_get_uchar_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ guchar * value);
+gboolean gst_tag_list_get_boolean (const GstTagList * list,
+ const gchar * tag,
+ gboolean * value);
+gboolean gst_tag_list_get_boolean_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gboolean * value);
+gboolean gst_tag_list_get_int (const GstTagList * list,
+ const gchar * tag,
+ gint * value);
+gboolean gst_tag_list_get_int_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gint * value);
+gboolean gst_tag_list_get_uint (const GstTagList * list,
+ const gchar * tag,
+ guint * value);
+gboolean gst_tag_list_get_uint_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ guint * value);
+gboolean gst_tag_list_get_long (const GstTagList * list,
+ const gchar * tag,
+ glong * value);
+gboolean gst_tag_list_get_long_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ glong * value);
+gboolean gst_tag_list_get_ulong (const GstTagList * list,
+ const gchar * tag,
+ gulong * value);
+gboolean gst_tag_list_get_ulong_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gulong * value);
+gboolean gst_tag_list_get_int64 (const GstTagList * list,
+ const gchar * tag,
+ gint64 * value);
+gboolean gst_tag_list_get_int64_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gint64 * value);
+gboolean gst_tag_list_get_uint64 (const GstTagList * list,
+ const gchar * tag,
+ guint64 * value);
+gboolean gst_tag_list_get_uint64_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ guint64 * value);
+gboolean gst_tag_list_get_float (const GstTagList * list,
+ const gchar * tag,
+ gfloat * value);
+gboolean gst_tag_list_get_float_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gfloat * value);
+gboolean gst_tag_list_get_double (const GstTagList * list,
+ const gchar * tag,
+ gdouble * value);
+gboolean gst_tag_list_get_double_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gdouble * value);
+gboolean gst_tag_list_get_string (const GstTagList * list,
+ const gchar * tag,
+ gchar ** value);
+gboolean gst_tag_list_get_string_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gchar ** value);
+gboolean gst_tag_list_get_pointer (const GstTagList * list,
+ const gchar * tag,
+ gpointer * value);
+gboolean gst_tag_list_get_pointer_index (const GstTagList * list,
+ const gchar * tag,
+ guint index,
+ gpointer * value);
+
+/* tag events */
+GstEvent * gst_event_new_tag (GstTagList * list);
+GstTagList * gst_event_tag_get_list (GstEvent * tag_event);
+
+
+/* GStreamer core tags (need to be discussed) */
+#define GST_TAG_TITLE "title"
+#define GST_TAG_ARTIST "artist"
+#define GST_TAG_ALBUM "album"
+#define GST_TAG_DATE "date"
+#define GST_TAG_GENRE "genre"
+#define GST_TAG_COMMENT "comment"
+#define GST_TAG_TRACK_NUMBER "track-number"
+#define GST_TAG_TRACK_COUNT "track-count"
+#define GST_TAG_LOCATION "location"
+#define GST_TAG_DESCRIPTION "description"
+#define GST_TAG_VERSION "version"
+#define GST_TAG_ISRC "isrc"
+#define GST_TAG_ORGANIZATION "organization"
+#define GST_TAG_COPYRIGHT "copyright"
+#define GST_TAG_CONTACT "contact"
+#define GST_TAG_LICENSE "license"
+#define GST_TAG_PERFORMER "performer"
+#define GST_TAG_DURATION "duration"
+#define GST_TAG_CODEC "codec"
+#define GST_TAG_BITRATE "bitrate"
+#define GST_TAG_MINIMUM_BITRATE "minimum-bitrate"
+#define GST_TAG_MAXIMUM_BITRATE "maximum-bitrate"
+
+
+G_END_DECLS
+
+#endif /* __GST_EVENT_H__ */
diff --git a/gst/gsttagsetter.c b/gst/gsttagsetter.c
new file mode 100644
index 000000000..a7e6d7134
--- /dev/null
+++ b/gst/gsttagsetter.c
@@ -0,0 +1,214 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttaginterface.c: interface for tag setting on elements
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gsttaginterface.h"
+#include <gobject/gvaluecollector.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_tag_interface_debug);
+#define GST_CAT_DEFAULT tag_tag_interface_debug
+
+static GQuark gst_tag_key;
+
+typedef struct {
+ GstTagMergeMode mode;
+ GstTagList * list;
+} GstTagData;
+
+GType
+gst_tag_setter_get_type (void)
+{
+ static GType tag_setter_type = 0;
+
+ if (! tag_setter_type) {
+ static const GTypeInfo tag_setter_info = {
+ sizeof (GstTagSetterIFace), /* class_size */
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0,
+ NULL
+ };
+
+ GST_DEBUG_CATEGORY_INIT (gst_tag_interface_debug, "GstTagInterface", 0, "interfaces for tagging");
+
+ tag_setter_type = g_type_register_static (G_TYPE_INTERFACE, "GstTagSetter",
+ &tag_setter_info, 0);
+
+ g_type_interface_add_prerequisite (tag_setter_type, GST_TYPE_ELEMENT);
+
+ gst_tag_key = g_quark_from_static_string ("GST_TAG_SETTER");
+ }
+
+ return tag_setter_type;
+}
+static void
+gst_tag_data_free (gpointer p)
+{
+ GstTagData *data = (GstTagData *) p;
+
+ if (data->list)
+ gst_tag_list_free (data->list);
+
+ g_free (data);
+}
+static GstTagData *
+gst_tag_setter_get_data (GstTagSetter *setter)
+{
+ GstTagData *data;
+
+ data = g_object_get_qdata (G_OBJECT (setter), gst_tag_key);
+ if (!data) {
+ data = g_new (GstTagData, 1);
+ data->list = NULL;
+ data->mode = GST_TAG_MERGE_KEEP;
+ g_object_set_qdata_full (G_OBJECT (setter), gst_tag_key, data, gst_tag_data_free);
+ }
+
+ return data;
+}
+/**
+ * gst_tag_setter_merge:
+ * @setter: a #GstTagSetter
+ * @list: a tag list to merge from
+ * @mode: the mode to merge with
+ *
+ * Merges the given list into the setter's list using the given mode.
+ */
+void
+gst_tag_setter_merge (GstTagSetter *setter, const GstTagList *list, GstTagMergeMode mode)
+{
+ GstTagData *data;
+
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ data = gst_tag_setter_get_data (setter);
+ if (!data->list) {
+ data->list = gst_tag_list_copy (list);
+ } else {
+ gst_tag_list_merge (data->list, list, mode);
+ }
+}
+/**
+ * gst_tag_setter_add:
+ * @setter: a #GstTagSetter
+ * @mode: the mode to use
+ * @tag: tag to set
+ * @...: more tag / value pairs to set
+ *
+ * Adds the given tag / value pairs on the setter using the given merge mode.
+ * The list must be terminated with GST_TAG_INVALID.
+ */
+void
+gst_tag_setter_add (GstTagSetter *setter, GstTagMergeMode mode, const gchar *tag, ...)
+{
+ va_list args;
+
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ va_start (args, tag);
+ gst_tag_setter_add_valist (setter, mode, tag, args);
+ va_end (args);
+}
+/**
+ * gst_tag_setter_add_valist:
+ * @setter: a #GstTagSetter
+ * @mode: the mode to use
+ * @tag: tag to set
+ * @var_args: tag / value pairs to set
+ *
+ * Adds the given tag / value pairs on the setter using the given merge mode.
+ * The list must be terminated with GST_TAG_INVALID.
+ */
+void
+gst_tag_setter_add_valist (GstTagSetter *setter, GstTagMergeMode mode, const gchar *tag, va_list var_args)
+{
+ GstTagData *data;
+
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ data = gst_tag_setter_get_data (setter);
+ if (!data->list)
+ data->list = gst_tag_list_new ();
+
+ gst_tag_list_add_valist (data->list, mode, tag, var_args);
+}
+/**
+ * gst_tag_setter_get_list:
+ * @setter: a #GstTagSetter
+ *
+ * Retrieves a copy of the current list of tags the setter uses.
+ * You need to gst_tag_list_free() the list after use.
+ *
+ * Returns: a current snapshot of the taglist used in the setter
+ * or NULL if none is used.
+ */
+const GstTagList *
+gst_tag_setter_get_list (GstTagSetter *setter)
+{
+ g_return_val_if_fail (GST_IS_TAG_SETTER (setter), NULL);
+
+ return gst_tag_setter_get_data (setter)->list;
+}
+/**
+ * gst_tag_setter_set_merge_mode:
+ * @setter: a #GstTagSetter
+ * @overwrite: The mode with which tags are added
+ *
+ * Sets the given merge mode that is used for adding tags from events to tags
+ * specified by this interface. The default is #GST_TAG_MERGE_KEEP, which keeps
+ * the tags by this interface and discards tags from events.
+ */
+void
+gst_tag_setter_set_merge_mode (GstTagSetter *setter, GstTagMergeMode mode)
+{
+ g_return_if_fail (GST_IS_TAG_SETTER (setter));
+ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
+
+ gst_tag_setter_get_data (setter)->mode = mode;
+}
+/**
+ * gst_tag_setter_get_merge_mode:
+ * @setter: a #GstTagSetter
+ *
+ * Queries the mode by which tags inside the setter are overwritten by tags
+ * from events
+ *
+ * Returns: the merge mode used inside the element.
+ */
+GstTagMergeMode
+gst_tag_setter_get_merge_mode (GstTagSetter *setter)
+{
+ g_return_val_if_fail (GST_IS_TAG_SETTER (setter), FALSE);
+
+ return gst_tag_setter_get_data (setter)->mode;
+}
diff --git a/gst/gsttagsetter.h b/gst/gsttagsetter.h
new file mode 100644
index 000000000..cb8513791
--- /dev/null
+++ b/gst/gsttagsetter.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gsttaginterface.h: Interfaces for tagging
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_TAG_INTERFACE_H__
+#define __GST_TAG_INTERFACE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_TAG_SETTER (gst_tag_setter_get_type ())
+#define GST_TAG_SETTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TAG_SETTER, GstTagSetter))
+#define GST_TAG_SETTER_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GST_TYPE_TAG_SETTER, GstTagSetter))
+#define GST_IS_TAG_SETTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TAG_SETTER))
+#define GST_TAG_SETTER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GST_TYPE_TAG_SETTER, GstTagSetterIFace))
+
+typedef struct _GstTagSetter GstTagSetter; /* Dummy typedef */
+typedef struct _GstTagSetterIFace GstTagSetterIFace;
+
+/* use an empty interface here to allow detection of elements using user-set
+ tags */
+struct _GstTagSetterIFace
+{
+ GTypeInterface g_iface;
+
+ /* signals */
+
+ /* virtual table */
+};
+
+GType gst_tag_setter_get_type (void) G_GNUC_CONST;
+
+void gst_tag_setter_merge (GstTagSetter * setter,
+ const GstTagList * list,
+ GstTagMergeMode mode);
+void gst_tag_setter_add (GstTagSetter * setter,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ ...);
+void gst_tag_setter_add_valist (GstTagSetter * setter,
+ GstTagMergeMode mode,
+ const gchar * tag,
+ va_list var_args);
+const GstTagList *gst_tag_setter_get_list (GstTagSetter * setter);
+
+void gst_tag_setter_set_merge_mode (GstTagSetter * setter,
+ GstTagMergeMode mode);
+GstTagMergeMode gst_tag_setter_get_merge_mode (GstTagSetter * setter);
+
+G_END_DECLS
+
+#endif /* __GST_TAG_INTERFACE_H__ */
diff --git a/gst/gstvalue.c b/gst/gstvalue.c
index 03b4ba9cb..79586e845 100644
--- a/gst/gstvalue.c
+++ b/gst/gstvalue.c
@@ -48,11 +48,175 @@ struct _GstValueIntersectInfo {
GType gst_type_fourcc;
GType gst_type_int_range;
GType gst_type_double_range;
+GType gst_value_type_list;
GArray *gst_value_compare_funcs;
GArray *gst_value_union_funcs;
GArray *gst_value_intersect_funcs;
+/* list */
+
+static void
+gst_value_init_list (GValue *value)
+{
+ value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof(GValue));
+}
+
+static GArray *
+gst_value_list_array_copy (const GArray *src)
+{
+ GArray *dest;
+ gint i;
+
+ dest = g_array_sized_new (FALSE, TRUE, sizeof(GValue), src->len);
+ g_array_set_size (dest, src->len);
+ for (i = 0; i < src->len; i++) {
+ g_value_init (&g_array_index(dest, GValue, i), G_VALUE_TYPE (&g_array_index(src, GValue, i)));
+ g_value_copy (&g_array_index(src, GValue, i), &g_array_index(dest, GValue, i));
+ }
+
+ return dest;
+}
+
+static void
+gst_value_copy_list (const GValue *src_value, GValue *dest_value)
+{
+ dest_value->data[0].v_pointer = gst_value_list_array_copy ((GArray *) src_value->data[0].v_pointer);
+}
+
+static void
+gst_value_free_list (GValue *value)
+{
+ gint i;
+ GArray *src = (GArray *) value->data[0].v_pointer;
+
+ if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
+ for (i = 0; i < src->len; i++) {
+ g_value_unset (&g_array_index(src, GValue, i));
+ }
+ g_array_free (src, TRUE);
+ }
+}
+
+static gpointer
+gst_value_list_peek_pointer (const GValue *value)
+{
+ return value->data[0].v_pointer;
+}
+
+static gchar *
+gst_value_collect_list (GValue *value, guint n_collect_values,
+ GTypeCValue *collect_values, guint collect_flags)
+{
+ if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
+ value->data[0].v_pointer = collect_values[0].v_pointer;
+ value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
+ } else {
+ value->data[0].v_pointer = gst_value_list_array_copy ((GArray *) collect_values[0].v_pointer);
+ }
+ return NULL;
+}
+
+static gchar *
+gst_value_lcopy_list (const GValue *value, guint n_collect_values,
+ GTypeCValue *collect_values, guint collect_flags)
+{
+ GArray **dest = collect_values[0].v_pointer;
+ if (!dest)
+ return g_strdup_printf ("value location for `%s' passed as NULL",
+ G_VALUE_TYPE_NAME (value));
+ if (!value->data[0].v_pointer)
+ return g_strdup_printf ("invalid value given for `%s'",
+ G_VALUE_TYPE_NAME (value));
+ if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
+ *dest = (GArray *) value->data[0].v_pointer;
+ } else {
+ *dest = gst_value_list_array_copy ((GArray *) value->data[0].v_pointer);
+ }
+ return NULL;
+}
+
+void
+gst_value_list_prepend_value (GValue *value, const GValue *prepend_value)
+{
+ g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
+
+ g_array_prepend_vals ((GArray *) value->data[0].v_pointer, prepend_value, 1);
+}
+
+void
+gst_value_list_append_value (GValue *value, const GValue *append_value)
+{
+ g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
+
+ g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
+}
+
+guint
+gst_value_list_get_size (const GValue *value)
+{
+ g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
+
+ return ((GArray *) value->data[0].v_pointer)->len;
+}
+
+const GValue *
+gst_value_list_get_value (const GValue *value, guint index)
+{
+ g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
+ g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
+
+ return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer, GValue, index);
+}
+
+/**
+ * gst_value_list_concat:
+ * @dest: an uninitialized #GValue to take the result
+ * @value1: first value to put into the union
+ * @value2: second value to put into the union
+ *
+ * Concatenates copies of value1 and value2 into a list. dest will be
+ * initialized to the type GST_VALUE_TYPE_LIST.
+ */
+void
+gst_value_list_concat (GValue *dest, const GValue *value1, const GValue *value2)
+{
+ guint i, value1_length, value2_length;
+ GArray *array;
+
+ g_return_if_fail (dest != NULL);
+ g_return_if_fail (G_VALUE_TYPE (dest) == 0);
+ g_return_if_fail (G_IS_VALUE (value1));
+ g_return_if_fail (G_IS_VALUE (value2));
+
+ value1_length = (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
+ value2_length = (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
+ g_value_init (dest, GST_VALUE_TYPE_LIST);
+ array = (GArray *) dest->data[0].v_pointer;
+ g_array_set_size (array, value1_length + value2_length);
+
+ if (GST_VALUE_HOLDS_LIST (value1)) {
+ for (i = 0; i < value1_length; i++) {
+ g_value_init (&g_array_index(array, GValue, i), G_VALUE_TYPE (gst_value_list_get_value (value1, i)));
+ g_value_copy (gst_value_list_get_value (value1, i), &g_array_index(array, GValue, i));
+ }
+ } else {
+ g_value_init (&g_array_index(array, GValue, 0), G_VALUE_TYPE (value1));
+ g_value_copy (value1, &g_array_index(array, GValue, 0));
+ }
+
+ if (GST_VALUE_HOLDS_LIST (value2)) {
+ for (i = 0; i < value2_length; i++) {
+ g_value_init (&g_array_index(array, GValue, i + value1_length), G_VALUE_TYPE (gst_value_list_get_value (value2, i)));
+ g_value_copy (gst_value_list_get_value (value2, i), &g_array_index(array, GValue, i + value1_length));
+ }
+ } else {
+ g_value_init (&g_array_index(array, GValue, value1_length), G_VALUE_TYPE (value2));
+ g_value_copy (value2, &g_array_index(array, GValue, value1_length));
+ }
+}
+
+/* fourcc */
static void
gst_value_init_fourcc (GValue *value)
@@ -147,7 +311,7 @@ gst_value_lcopy_int_range (const GValue *value, guint n_collect_values,
void
gst_value_set_int_range (GValue *value, int start, int end)
{
- g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
+ g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
value->data[0].v_long = start;
value->data[1].v_long = end;
@@ -156,7 +320,7 @@ gst_value_set_int_range (GValue *value, int start, int end)
int
gst_value_get_int_range_min (const GValue *value)
{
- g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
+ g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
return value->data[0].v_long;
}
@@ -164,11 +328,82 @@ gst_value_get_int_range_min (const GValue *value)
int
gst_value_get_int_range_max (const GValue *value)
{
- g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
+ g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
return value->data[1].v_long;
}
+/* double range */
+
+static void
+gst_value_init_double_range (GValue *value)
+{
+ value->data[0].v_double = 0;
+ value->data[1].v_double = 0;
+}
+
+static void
+gst_value_copy_double_range (const GValue *src_value, GValue *dest_value)
+{
+ dest_value->data[0].v_double = src_value->data[0].v_double;
+ dest_value->data[1].v_double = src_value->data[1].v_double;
+}
+
+static gchar *
+gst_value_collect_double_range (GValue *value, guint n_collect_values,
+ GTypeCValue *collect_values, guint collect_flags)
+{
+ /* FIXME */
+ value->data[0].v_double = collect_values[0].v_double;
+ value->data[1].v_double = collect_values[1].v_double;
+
+ return NULL;
+}
+
+static gchar *
+gst_value_lcopy_double_range (const GValue *value, guint n_collect_values,
+ GTypeCValue *collect_values, guint collect_flags)
+{
+ guint32 *double_range_p = collect_values[0].v_pointer;
+
+ /* FIXME */
+
+ if (!double_range_p)
+ return g_strdup_printf ("value location for `%s' passed as NULL",
+ G_VALUE_TYPE_NAME (value));
+
+ *double_range_p = value->data[0].v_double;
+
+ return NULL;
+}
+
+void
+gst_value_set_double_range (GValue *value, double start, double end)
+{
+ g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
+
+ value->data[0].v_double = start;
+ value->data[1].v_double = end;
+}
+
+double
+gst_value_get_double_range_min (const GValue *value)
+{
+ g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
+
+ return value->data[0].v_double;
+}
+
+double
+gst_value_get_double_range_max (const GValue *value)
+{
+ g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
+
+ return value->data[1].v_double;
+}
+
+/* fourcc */
+
static void
gst_value_transform_fourcc_string (const GValue *src_value,
GValue *dest_value)
@@ -190,26 +425,39 @@ gst_value_transform_int_range_string (const GValue *src_value,
static int
gst_value_compare_int (const GValue *value1, const GValue *value2)
{
- return value2->data[0].v_int - value1->data[0].v_int;
+ if (value1->data[0].v_int > value2->data[0].v_int)
+ return GST_VALUE_GREATER_THAN;
+ if (value1->data[0].v_int < value2->data[0].v_int)
+ return GST_VALUE_LESS_THAN;
+ return GST_VALUE_EQUAL;
}
static int
gst_value_compare_double (const GValue *value1, const GValue *value2)
{
- return (value2->data[0].v_double > value1->data[0].v_double) -
- (value2->data[0].v_double < value1->data[0].v_double);
+ if (value1->data[0].v_double > value2->data[0].v_double)
+ return GST_VALUE_GREATER_THAN;
+ if (value1->data[0].v_double < value2->data[0].v_double)
+ return GST_VALUE_LESS_THAN;
+ if (value1->data[0].v_double == value2->data[0].v_double)
+ return GST_VALUE_EQUAL;
+ return GST_VALUE_UNORDERED;
}
static int
gst_value_compare_string (const GValue *value1, const GValue *value2)
{
- return strcmp(value1->data[0].v_pointer, value2->data[0].v_pointer);
+ int x = strcmp(value1->data[0].v_pointer, value2->data[0].v_pointer);
+ if(x<0) return GST_VALUE_LESS_THAN;
+ if(x>0) return GST_VALUE_GREATER_THAN;
+ return GST_VALUE_EQUAL;
}
static int
gst_value_compare_fourcc (const GValue *value1, const GValue *value2)
{
- return value2->data[0].v_int - value1->data[0].v_int;
+ if (value2->data[0].v_int == value1->data[0].v_int) return GST_VALUE_EQUAL;
+ return GST_VALUE_UNORDERED;
}
gboolean
@@ -243,8 +491,8 @@ gst_value_compare (const GValue *value1, const GValue *value2)
return compare_info->func(value1, value2);
}
- g_return_val_if_fail(0 /* type not found */, 0);
- return 0;
+ g_return_val_if_fail(0 /* type not found */, GST_VALUE_UNORDERED);
+ return GST_VALUE_UNORDERED;
}
void
@@ -275,7 +523,7 @@ gst_value_can_union (const GValue *value1, const GValue *value2)
return FALSE;
}
-void
+gboolean
gst_value_union (GValue *dest, const GValue *value1, const GValue *value2)
{
GstValueUnionInfo *union_info;
@@ -285,10 +533,11 @@ gst_value_union (GValue *dest, const GValue *value1, const GValue *value2)
union_info = &g_array_index(gst_value_union_funcs, GstValueUnionInfo, i);
if(union_info->type1 == G_VALUE_TYPE(value1) &&
union_info->type2 == G_VALUE_TYPE(value2)) {
- union_info->func(dest, value1, value2);
- return;
+ return union_info->func(dest, value1, value2);
}
}
+ gst_value_list_concat (dest, value1, value2);
+ return TRUE;
}
void
@@ -364,7 +613,7 @@ gst_value_can_intersect (const GValue *value1, const GValue *value2)
return FALSE;
}
-void
+gboolean
gst_value_intersect (GValue *dest, const GValue *value1, const GValue *value2)
{
GstValueIntersectInfo *intersect_info;
@@ -375,10 +624,17 @@ gst_value_intersect (GValue *dest, const GValue *value1, const GValue *value2)
GstValueIntersectInfo, i);
if(intersect_info->type1 == G_VALUE_TYPE(value1) &&
intersect_info->type2 == G_VALUE_TYPE(value2)) {
- intersect_info->func(dest, value1, value2);
- return;
+ return intersect_info->func(dest, value1, value2);
}
}
+
+ if(gst_value_compare(value1, value2) == GST_VALUE_EQUAL){
+ g_value_init(dest, G_VALUE_TYPE(value1));
+ g_value_copy(value1, dest);
+ return TRUE;
+ }
+
+ return FALSE;
}
void
@@ -441,6 +697,36 @@ _gst_value_initialize (void)
gst_type_int_range = g_type_register_static (G_TYPE_BOXED, "GstIntRange", &info, 0);
}
+ {
+ static const GTypeValueTable value_table = {
+ gst_value_init_double_range,
+ NULL,
+ gst_value_copy_double_range,
+ NULL,
+ "i",
+ gst_value_collect_double_range,
+ "p",
+ gst_value_lcopy_double_range
+ };
+ info.value_table = &value_table;
+ gst_type_double_range = g_type_register_static (G_TYPE_BOXED, "GstDoubleRange", &info, 0);
+ }
+
+ {
+ static const GTypeValueTable value_table = {
+ gst_value_init_list,
+ gst_value_free_list,
+ gst_value_copy_list,
+ gst_value_list_peek_pointer,
+ "p",
+ gst_value_collect_list,
+ "p",
+ gst_value_lcopy_list
+ };
+ info.value_table = &value_table;
+ gst_value_type_list = g_type_register_static (G_TYPE_BOXED, "GstValueList", &info, 0);
+ }
+
g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
gst_value_transform_fourcc_string);
g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
diff --git a/gst/gstvalue.h b/gst/gstvalue.h
index 353e1dd27..0fa57cacd 100644
--- a/gst/gstvalue.h
+++ b/gst/gstvalue.h
@@ -31,15 +31,36 @@ typedef int (* GstValueUnionFunc) (GValue *dest, const GValue *value1,
typedef int (* GstValueIntersectFunc) (GValue *dest, const GValue *value1,
const GValue *value2);
-#define GST_VALUE_HOLDS_FOURCC(x) TRUE
+#define GST_MAKE_FOURCC(a,b,c,d) (guint32)((a)|(b)<<8|(c)<<16|(d)<<24)
+#define GST_STR_FOURCC(f) (guint32)(((f)[0])|((f)[1]<<8)|((f)[2]<<16)|((f)[3]<<24))
+
+#define GST_FOURCC_FORMAT "%c%c%c%c"
+#define GST_FOURCC_ARGS(fourcc) \
+ ((gchar) ((fourcc) &0xff)), \
+ ((gchar) (((fourcc)>>8 )&0xff)), \
+ ((gchar) (((fourcc)>>16)&0xff)), \
+ ((gchar) (((fourcc)>>24)&0xff))
#define GST_TYPE_FOURCC gst_type_fourcc
#define GST_TYPE_INT_RANGE gst_type_int_range
#define GST_TYPE_DOUBLE_RANGE gst_type_double_range
+#define GST_VALUE_TYPE_LIST gst_value_type_list
+
+#define GST_VALUE_HOLDS_FOURCC(x) (G_VALUE_TYPE(x) == gst_type_fourcc)
+#define GST_VALUE_HOLDS_INT_RANGE(x) (G_VALUE_TYPE(x) == gst_type_int_range)
+#define GST_VALUE_HOLDS_DOUBLE_RANGE(x) (G_VALUE_TYPE(x) == gst_type_double_range)
+#define GST_VALUE_HOLDS_LIST(x) (G_VALUE_TYPE(x) == GST_VALUE_TYPE_LIST)
+#define GST_VALUE_HOLDS_CAPS(x) TRUE /* FIXME */
+
+#define GST_VALUE_LESS_THAN (-1)
+#define GST_VALUE_EQUAL 0
+#define GST_VALUE_GREATER_THAN 1
+#define GST_VALUE_UNORDERED 2
extern GType gst_type_fourcc;
extern GType gst_type_int_range;
extern GType gst_type_double_range;
+extern GType gst_value_type_list;
void gst_value_set_fourcc (GValue *value, guint32 fourcc);
guint32 gst_value_get_fourcc (const GValue *value);
@@ -49,11 +70,21 @@ int gst_value_get_int_range_min (const GValue *value);
int gst_value_get_int_range_max (const GValue *value);
void gst_value_set_double_range (GValue *value, double start, double end);
-double gst_value_get_double_range_start (const GValue *value);
-double gst_value_get_double_range_end (const GValue *value);
+double gst_value_get_double_range_min (const GValue *value);
+double gst_value_get_double_range_max (const GValue *value);
+
+void gst_value_list_prepend_value (GValue *value, const GValue *prepend_value);
+void gst_value_list_append_value (GValue *value, const GValue *prepend_value);
+guint gst_value_list_get_size (const GValue *value);
+const GValue *gst_value_list_get_value (const GValue *value, guint index);
+void gst_value_list_concat (GValue *dest, const GValue *value1, const GValue *value2);
void _gst_value_initialize (void);
+int gst_value_compare (const GValue *src1, const GValue *src2);
+gboolean gst_value_intersect (GValue *dest, const GValue *src1, const GValue *src2);
+gboolean gst_value_union (GValue *dest, const GValue *src1, const GValue *src2);
+
G_END_DECLS
#endif
diff --git a/gst/registries/gstxmlregistry.c b/gst/registries/gstxmlregistry.c
index c0555a2c3..76f2679e7 100644
--- a/gst/registries/gstxmlregistry.c
+++ b/gst/registries/gstxmlregistry.c
@@ -687,8 +687,9 @@ gst_xml_registry_parse_element_factory (GMarkupParseContext *context, const gcha
GstElementFactory *factory = GST_ELEMENT_FACTORY (registry->current_feature);
if (!strcmp (tag, "name")) {
- g_free (registry->current_feature->name);
- registry->current_feature->name = g_strndup (text, text_len);
+ gchar *name = g_strndup (text, text_len);
+ gst_plugin_feature_set_name (registry->current_feature, name);
+ g_free (name);
}
else if (!strcmp (tag, "longname")) {
g_free (factory->details.longname);
@@ -709,12 +710,18 @@ gst_xml_registry_parse_element_factory (GMarkupParseContext *context, const gcha
else if (!strcmp(tag, "rank")) {
gint rank;
gchar *ret;
- rank = strtol (text, &ret, 0);
+
+ rank = strtol (text, &ret, 0);
if (ret == text + text_len) {
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), rank);
}
}
-
+ else if (!strcmp(tag, "interface")) {
+ gchar *tmp = g_strndup (text, text_len);
+ __gst_element_factory_add_interface (factory, tmp);
+ g_free (tmp);
+ }
+
return TRUE;
}
@@ -1464,23 +1471,29 @@ gst_xml_registry_save_feature (GstXMLRegistry *xmlregistry, GstPluginFeature *fe
if (GST_IS_ELEMENT_FACTORY (feature)) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
- GList *templates;
+ GList *walk;
PUT_ESCAPED ("longname", factory->details.longname);
PUT_ESCAPED ("class", factory->details.klass);
PUT_ESCAPED ("description", factory->details.description);
PUT_ESCAPED ("author", factory->details.author);
- templates = factory->padtemplates;
+ walk = factory->padtemplates;
- while (templates) {
- GstPadTemplate *template = GST_PAD_TEMPLATE (templates->data);
+ while (walk) {
+ GstPadTemplate *template = GST_PAD_TEMPLATE (walk->data);
CLASS (xmlregistry)->save_func (xmlregistry, "<padtemplate>\n");
gst_xml_registry_save_pad_template (xmlregistry, template);
CLASS (xmlregistry)->save_func (xmlregistry, "</padtemplate>\n");
- templates = g_list_next (templates);
+ walk = g_list_next (walk);
+ }
+
+ walk = factory->interfaces;
+ while (walk) {
+ PUT_ESCAPED ("interface", (gchar *) walk->data);
+ walk = g_list_next (walk);
}
}
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
diff --git a/libs/gst/Makefile.am b/libs/gst/Makefile.am
index 3bd8a76a3..fa04c8f2b 100644
--- a/libs/gst/Makefile.am
+++ b/libs/gst/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = control getbits bytestream
+SUBDIRS = bytestream control getbits
-DIST_SUBDIRS = control getbits bytestream
+DIST_SUBDIRS = bytestream control getbits
diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am
index a294dc11c..3aa752eda 100644
--- a/pkgconfig/Makefile.am
+++ b/pkgconfig/Makefile.am
@@ -1,10 +1,10 @@
### all of the standard pc files we need to generate
-pcfiles = \
- gstreamer-@GST_MAJORMINOR@.pc \
+pcfiles = \
+ gstreamer-@GST_MAJORMINOR@.pc \
gstreamer-control-@GST_MAJORMINOR@.pc
-pcfiles_uninstalled = \
- gstreamer-@GST_MAJORMINOR@-uninstalled.pc \
+pcfiles_uninstalled = \
+ gstreamer-@GST_MAJORMINOR@-uninstalled.pc \
gstreamer-control-@GST_MAJORMINOR@-uninstalled.pc
all-local: $(pcfiles) $(pcfiles_uninstalled)
@@ -18,10 +18,10 @@ $(pcfiles_uninstalled): %-@GST_MAJORMINOR@-uninstalled.pc: %-uninstalled.pc
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = $(pcfiles)
-EXTRA_DIST = \
- gstreamer.pc.in \
- gstreamer-uninstalled.pc.in \
- gstreamer-control.pc.in \
+EXTRA_DIST = \
+ gstreamer.pc.in \
+ gstreamer-uninstalled.pc.in \
+ gstreamer-control.pc.in \
gstreamer-control-uninstalled.pc.in
CLEANFILES = $(pcfiles) $(pcfiles_uninstalled)
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 000000000..91b6c79ae
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1,6 @@
+*.gmo
+remove-potcdate.sed
+stamp-po
+POTFILES
+cat-id-tbl.c
+gstreamer-0.7.pot
diff --git a/tests/old/examples/Makefile.am b/tests/old/examples/Makefile.am
index 9751930a0..69a0458e6 100644
--- a/tests/old/examples/Makefile.am
+++ b/tests/old/examples/Makefile.am
@@ -10,13 +10,39 @@ else
GST_AUTOPLUG_DIRS = autoplug helloworld2
endif
-SUBDIRS = $(GST_AUTOPLUG_DIRS) $(GST_LOADSAVE_DIRS) \
- helloworld \
- queue queue2 queue3 queue4 \
- launch thread plugins mixer cutter pingpong manual
+SUBDIRS = \
+ helloworld \
+ queue \
+ queue2 \
+ queue3 \
+ queue4 \
+ launch \
+ thread \
+ plugins \
+ mixer \
+ cutter \
+ pingpong \
+ manual \
+ retag \
+ $(GST_LOADSAVE_DIRS) \
+ $(GST_AUTOPLUG_DIRS)
-DIST_SUBDIRS = autoplug \
- helloworld helloworld2 \
- queue queue2 queue3 queue4 \
- launch thread xml plugins typefind mixer cutter pingpong manual
+
+DIST_SUBDIRS = autoplug \
+ helloworld \
+ helloworld2 \
+ queue \
+ queue2 \
+ queue3 \
+ queue4 \
+ launch \
+ thread \
+ plugins \
+ mixer \
+ cutter \
+ pingpong \
+ manual \
+ xml \
+ typefind \
+ retag
diff --git a/tests/old/examples/retag/.gitignore b/tests/old/examples/retag/.gitignore
new file mode 100644
index 000000000..a54ae58a5
--- /dev/null
+++ b/tests/old/examples/retag/.gitignore
@@ -0,0 +1,2 @@
+retag
+transcode
diff --git a/tests/old/examples/retag/Makefile.am b/tests/old/examples/retag/Makefile.am
new file mode 100644
index 000000000..6a686a51e
--- /dev/null
+++ b/tests/old/examples/retag/Makefile.am
@@ -0,0 +1,7 @@
+noinst_PROGRAMS = retag transcode
+
+retag_LDADD = $(GST_LIBS)
+retag_CFLAGS = $(GST_CFLAGS)
+
+transcode_LDADD = $(GST_LIBS)
+transcode_CFLAGS = $(GST_CFLAGS)
diff --git a/tests/old/examples/retag/retag.c b/tests/old/examples/retag/retag.c
new file mode 100644
index 000000000..2824ba724
--- /dev/null
+++ b/tests/old/examples/retag/retag.c
@@ -0,0 +1,103 @@
+/*
+ * This example shows how to use interfaces and the tag subsystem.
+ * It takes an mp3 file as input, and makes an ogg file out of it. While doing
+ * this, it parses the filename and sets artist and title in the ogg file.
+ * It assumes the filename to be "<artist> - <title>.mp3"
+ *
+ * Run the program as "retag <mp3 file>"
+ *
+ * To run this program, you need to have the gst-plugins package (specifically
+ * the vorbis and mad plugins) installed.
+ */
+
+/* main header */
+#include <gst/gst.h>
+/* and a header we need for the string manipulation */
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *bin, *filesrc, *tag_changer, *filesink;
+ gchar *artist, *title, *ext, *filename;
+
+ /* check that the argument is there */
+ if (argc != 2) {
+ g_print ("usage: %s <mp3 file>\n", argv[0]);
+ return 1;
+ }
+
+ /* initialize GStreamer */
+ gst_init (&argc, &argv);
+
+ /* parse the mp3 name */
+ artist = strrchr (argv[1], '/');
+ if (artist == NULL)
+ artist = argv[1];
+ artist = g_strdup (artist);
+ ext = strrchr (artist, '.');
+ if (ext) *ext = '\0';
+ title = strstr (artist, " - ");
+ if (title == NULL) {
+ g_print ("The format of the mp3 file is invalid.\n");
+ return 1;
+ }
+ *title = '\0';
+ title += 3;
+
+
+ /* create a new bin to hold the elements */
+ bin = gst_pipeline_new ("pipeline");
+ g_assert (bin);
+
+ /* create a file reader */
+ filesrc = gst_element_factory_make ("filesrc", "disk_source");
+ g_assert (filesrc);
+
+ /* now it's time to get the tag_changer */
+ tag_changer = gst_element_factory_make ("id3tag", "tag_changer");
+ if (!tag_changer) {
+ g_print ("could not find plugin \"mad\"");
+ return 1;
+ }
+
+ /* and a file writer */
+ filesink = gst_element_factory_make ("filesink", "filesink");
+ g_assert (filesink);
+
+ /* set the filenames */
+ filename = g_strdup_printf ("%s.temp", argv[1]); /* easy solution */
+ g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
+ g_object_set (G_OBJECT (filesink), "location", filename, NULL);
+
+ /* make sure the tag setter uses our stuff
+ (though that should already be default) */
+ gst_tag_setter_set_merge_mode (GST_TAG_SETTER (tag_changer), GST_TAG_MERGE_KEEP);
+ /* set the tagging information */
+ gst_tag_setter_add (GST_TAG_SETTER (tag_changer), GST_TAG_MERGE_REPLACE,
+ GST_TAG_ARTIST, artist,
+ GST_TAG_TITLE, title,
+ NULL);
+
+ /* add objects to the main pipeline */
+ gst_bin_add_many (GST_BIN (bin), filesrc, tag_changer, filesink, NULL);
+
+ /* link the elements */
+ gst_element_link_many (filesrc, tag_changer, filesink, NULL);
+
+ /* start playing */
+ gst_element_set_state (bin, GST_STATE_PLAYING);
+
+ while (gst_bin_iterate (GST_BIN (bin)));
+
+ /* stop the bin */
+ gst_element_set_state (bin, GST_STATE_NULL);
+
+ /* rename the file to the correct name and remove the old one */
+ remove (argv[1]);
+ rename (filename, argv[1]);
+ g_free (filename);
+
+ return 0;
+}
+
diff --git a/tests/old/examples/retag/transcode.c b/tests/old/examples/retag/transcode.c
new file mode 100644
index 000000000..c41f96ed8
--- /dev/null
+++ b/tests/old/examples/retag/transcode.c
@@ -0,0 +1,106 @@
+/*
+ * This example shows how to use interfaces and the tag subsystem.
+ * It takes an mp3 file as input, and makes an ogg file out of it. While doing
+ * this, it parses the filename and sets artist and title in the ogg file.
+ * It assumes the filename to be "<artist> - <title>.mp3"
+ *
+ * Run the program as "retag <mp3 file>"
+ *
+ * To run this program, you need to have the gst-plugins package (specifically
+ * the vorbis and mad plugins) installed.
+ */
+
+/* main header */
+#include <gst/gst.h>
+/* and a header we need for the string manipulation */
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+ GstElement *bin, *filesrc, *decoder, *encoder, *filesink;
+ gchar *artist, *title, *ext, *filename;
+
+ /* initialize GStreamer */
+ gst_init (&argc, &argv);
+
+ /* check that the argument is there */
+ if (argc != 2) {
+ g_print ("usage: %s <mp3 file>\n", argv[0]);
+ return 1;
+ }
+
+ /* parse the mp3 name */
+ artist = strrchr (argv[1], '/');
+ if (artist == NULL)
+ artist = argv[1];
+ artist = g_strdup (artist);
+ ext = strrchr (artist, '.');
+ if (ext) *ext = '\0';
+ title = strstr (artist, " - ");
+ if (title == NULL) {
+ g_print ("The format of the mp3 file is invalid.\n");
+ return 1;
+ }
+ *title = '\0';
+ title += 3;
+
+
+ /* create a new bin to hold the elements */
+ bin = gst_pipeline_new ("pipeline");
+ g_assert (bin);
+
+ /* create a file reader */
+ filesrc = gst_element_factory_make ("filesrc", "disk_source");
+ g_assert (filesrc);
+
+ /* now it's time to get the decoder */
+ decoder = gst_element_factory_make ("mad", "decode");
+ if (!decoder) {
+ g_print ("could not find plugin \"mad\"");
+ return 1;
+ }
+
+ /* create the encoder */
+ encoder = gst_element_factory_make ("vorbisenc", "encoder");
+ if (!encoder) {
+ g_print ("cound not find plugin \"vorbisenc\"");
+ return 1;
+ }
+
+ /* and a file writer */
+ filesink = gst_element_factory_make ("filesink", "filesink");
+ g_assert (filesink);
+
+ /* set the filenames */
+ filename = g_strdup_printf ("%s.ogg", argv[1]); /* easy solution */
+ g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
+ g_object_set (G_OBJECT (filesink), "location", filename, NULL);
+ g_free (filename);
+
+ /* make sure the tag setter uses our stuff
+ (though that should already be default) */
+ gst_tag_setter_set_merge_mode (GST_TAG_SETTER (encoder), GST_TAG_MERGE_KEEP);
+ /* set the tagging information */
+ gst_tag_setter_add (GST_TAG_SETTER (encoder), GST_TAG_MERGE_REPLACE,
+ GST_TAG_ARTIST, artist,
+ GST_TAG_TITLE, title,
+ NULL);
+
+ /* add objects to the main pipeline */
+ gst_bin_add_many (GST_BIN (bin), filesrc, decoder, encoder, filesink, NULL);
+
+ /* link the elements */
+ gst_element_link_many (filesrc, decoder, encoder, filesink, NULL);
+
+ /* start playing */
+ gst_element_set_state (bin, GST_STATE_PLAYING);
+
+ while (gst_bin_iterate (GST_BIN (bin)));
+
+ /* stop the bin */
+ gst_element_set_state (bin, GST_STATE_NULL);
+
+ return 0;
+}
+
diff --git a/tests/old/testsuite/Makefile.am b/tests/old/testsuite/Makefile.am
index 0e181893d..261e4d6e6 100644
--- a/tests/old/testsuite/Makefile.am
+++ b/tests/old/testsuite/Makefile.am
@@ -14,11 +14,11 @@ GST_DEBUG_DIRS = debug
endif
SUBDIRS = bytestream cleanup dynparams \
- caps plugin elements clock refcounting threads \
+ caps plugin elements clock refcounting tags threads \
indexers debug $(GST_PARSE_DIRS) $(GST_DEBUG_DIRS)
DIST_SUBDIRS = bytestream caps cleanup clock dynparams elements indexers \
- plugin refcounting threads parse debug
+ plugin refcounting tags threads parse debug
tests_pass = test_gst_init
tests_fail =
diff --git a/tests/old/testsuite/threads/queue.c b/tests/old/testsuite/threads/queue.c
index 2435e31c2..191ae43f0 100644
--- a/tests/old/testsuite/threads/queue.c
+++ b/tests/old/testsuite/threads/queue.c
@@ -76,7 +76,7 @@ main (gint argc, gchar *argv[])
gst_element_set_state (thread, GST_STATE_PLAYING);
g_print ("SLEEPING 1 sec\n");
sleep (1);
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ gst_bin_sync_children_state (GST_BIN (pipeline));
g_print ("SLEEPING 2 sec\n");
sleep (2);
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 0e181893d..261e4d6e6 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -14,11 +14,11 @@ GST_DEBUG_DIRS = debug
endif
SUBDIRS = bytestream cleanup dynparams \
- caps plugin elements clock refcounting threads \
+ caps plugin elements clock refcounting tags threads \
indexers debug $(GST_PARSE_DIRS) $(GST_DEBUG_DIRS)
DIST_SUBDIRS = bytestream caps cleanup clock dynparams elements indexers \
- plugin refcounting threads parse debug
+ plugin refcounting tags threads parse debug
tests_pass = test_gst_init
tests_fail =
diff --git a/testsuite/threads/queue.c b/testsuite/threads/queue.c
index 2435e31c2..191ae43f0 100644
--- a/testsuite/threads/queue.c
+++ b/testsuite/threads/queue.c
@@ -76,7 +76,7 @@ main (gint argc, gchar *argv[])
gst_element_set_state (thread, GST_STATE_PLAYING);
g_print ("SLEEPING 1 sec\n");
sleep (1);
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ gst_bin_sync_children_state (GST_BIN (pipeline));
g_print ("SLEEPING 2 sec\n");
sleep (2);
diff --git a/tools/gst-launch.c b/tools/gst-launch.c
index 5eb22d8b1..0cc231581 100644
--- a/tools/gst-launch.c
+++ b/tools/gst-launch.c
@@ -221,6 +221,34 @@ fault_setup (void)
sigaction (SIGQUIT, &action, NULL);
}
+static void
+print_tag (const GstTagList *list, const gchar *tag, gpointer unused)
+{
+ gint i, count;
+
+ count = gst_tag_list_get_tag_size (list, tag);
+
+ for (i = 0; i < count; i++) {
+
+ gchar *str = g_strdup_value_contents (
+ gst_tag_list_get_value_index (list, tag, i));
+
+ if (i == 0) {
+ g_print ("%15s: %s\n", gst_tag_get_nick (tag), str);
+ } else {
+ g_print (" : %s\n", str);
+ }
+
+ g_free (str);
+ }
+}
+static void
+found_tag (GObject *pipeline, GstElement *source, GstTagList *tags)
+{
+ g_print ("FOUND TAG : element \"%s\"\n", GST_STR_NULL (GST_ELEMENT_NAME (source)));
+ gst_tag_list_foreach (tags, print_tag, NULL);
+}
+
/* we only use sighandler here because the registers are not important */
static void
sigint_handler_sighandler (int signum)
@@ -286,11 +314,14 @@ main(int argc, char *argv[])
gint i, j;
/* options */
gboolean verbose = FALSE;
+ gboolean tags = FALSE;
gboolean no_fault = FALSE;
gboolean trace = FALSE;
gchar *savefile = NULL;
gchar *exclude_args = NULL;
struct poptOption options[] = {
+ {"tags", 't', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &tags, 0,
+ "output tags (also known as metadata)", NULL},
{"verbose", 'v', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &verbose, 0,
"output status information and property notifications", NULL},
{"exclude", 'X', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &exclude_args, 0,
@@ -301,7 +332,7 @@ main(int argc, char *argv[])
#endif
{"no-fault", 'f', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &no_fault, 0,
"Do not install a fault handler", NULL},
- {"trace", 't', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &trace, 0,
+ {"trace", 'T', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &trace, 0,
"print alloc trace if enabled at compile time", NULL},
{"iterations",'i',POPT_ARG_INT|POPT_ARGFLAG_STRIP, &max_iterations, 0,
"number of times to iterate pipeline", NULL},
@@ -382,6 +413,9 @@ main(int argc, char *argv[])
gchar **exclude_list = exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
g_signal_connect (pipeline, "deep_notify", G_CALLBACK (gst_element_default_deep_notify), exclude_list);
}
+ if (tags) {
+ g_signal_connect (pipeline, "found-tag", G_CALLBACK (found_tag), NULL);
+ }
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error), NULL);
#ifndef GST_DISABLE_LOADSAVE