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
This commit is contained in:
Benjamin Otte 2003-11-24 02:09:23 +00:00
parent b4f14a29f6
commit 385b9ee5c4
66 changed files with 4299 additions and 562 deletions

View file

@ -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

1
docs/.gitignore vendored
View file

@ -5,3 +5,4 @@ Makefile.in
*.la
.deps
.libs
version.entities

View file

@ -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

1
docs/gst/.gitignore vendored
View file

@ -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

View file

@ -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:

View file

@ -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.

View file

@ -262,6 +262,7 @@ The basic structure of a buffer.
@timestamp:
@duration:
@offset:
@offset_end:
@pool:
@pool_private:

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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:

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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.

View file

@ -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>

View file

@ -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>

View file

@ -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:

View file

@ -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:

View file

@ -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:

13
docs/libs/.gitignore vendored
View file

@ -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

View file

@ -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

2
examples/retag/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
retag
transcode

View file

@ -0,0 +1,7 @@
noinst_PROGRAMS = retag transcode
retag_LDADD = $(GST_LIBS)
retag_CFLAGS = $(GST_CFLAGS)
transcode_LDADD = $(GST_LIBS)
transcode_CFLAGS = $(GST_CFLAGS)

103
examples/retag/retag.c Normal file
View file

@ -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;
}

106
examples/retag/transcode.c Normal file
View file

@ -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;
}

View file

@ -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

View file

@ -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) {

View file

@ -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/gstthread.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/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/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>

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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));
@ -387,6 +401,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

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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,
@ -83,6 +83,27 @@ void _gst_structure_initialize(void)
_gst_structure_transform_to_string);
}
/**
* 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;
}
@ -383,6 +404,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
@ -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;
@ -524,6 +571,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
@ -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;

View file

@ -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);

831
gst/gsttag.c Normal file
View file

@ -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 *)

232
gst/gsttag.h Normal file
View file

@ -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__ */

214
gst/gsttaginterface.c Normal file
View file

@ -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;
}

70
gst/gsttaginterface.h Normal file
View file

@ -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__ */

831
gst/gsttaglist.c Normal file
View file

@ -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 *)

232
gst/gsttaglist.h Normal file
View file

@ -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__ */

214
gst/gsttagsetter.c Normal file
View file

@ -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;
}

70
gst/gsttagsetter.h Normal file
View file

@ -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__ */

View file

@ -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,

View file

@ -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

View file

@ -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)) {

View file

@ -1,3 +1,3 @@
SUBDIRS = control getbits bytestream
SUBDIRS = bytestream control getbits
DIST_SUBDIRS = control getbits bytestream
DIST_SUBDIRS = bytestream control getbits

View file

@ -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)

6
po/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
*.gmo
remove-potcdate.sed
stamp-po
POTFILES
cat-id-tbl.c
gstreamer-0.7.pot

View file

@ -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

2
tests/old/examples/retag/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
retag
transcode

View file

@ -0,0 +1,7 @@
noinst_PROGRAMS = retag transcode
retag_LDADD = $(GST_LIBS)
retag_CFLAGS = $(GST_CFLAGS)
transcode_LDADD = $(GST_LIBS)
transcode_CFLAGS = $(GST_CFLAGS)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 =

View file

@ -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);

View file

@ -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 =

View file

@ -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);

View file

@ -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