From 1a3888c76039344b5e45d73d72a6c3ca76b18740 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Sat, 29 Nov 2003 04:09:27 +0000 Subject: [PATCH] Merge HEAD from CAPS-ROOT to CAPS-MERGE-1 Original commit message from CVS: Merge HEAD from CAPS-ROOT to CAPS-MERGE-1 --- ChangeLog | 10 + Makefile.am | 9 +- configure.ac | 12 +- docs/.gitignore | 1 + docs/Makefile.am | 4 +- docs/gst/.gitignore | 1 + docs/gst/Makefile.am | 60 +- docs/gst/tmpl/gstautoplug.sgml | 16 +- docs/gst/tmpl/gstbuffer.sgml | 1 + docs/gst/tmpl/gstcaps.sgml | 18 - docs/gst/tmpl/gstconfig.sgml | 7 - docs/gst/tmpl/gstelement.sgml | 17 +- docs/gst/tmpl/gstelementfactory.sgml | 71 -- docs/gst/tmpl/gstevent.sgml | 1 + docs/gst/tmpl/gstinfo.sgml | 15 - docs/gst/tmpl/gstplugin.sgml | 77 +- docs/gst/tmpl/gstreamer-unused.sgml | 517 ++++++++++++- docs/gst/tmpl/gsttypefind.sgml | 14 - docs/gst/tmpl/gsturi.sgml | 51 -- docs/gst/tmpl/gstxml.sgml | 10 +- docs/htmlinstall.mak | 5 + docs/libs/.gitignore | 13 +- docs/libs/Makefile.am | 56 +- docs/manual/appendix-quotes.xml | 16 + docs/manual/quotes.xml | 16 + docs/manuals.mak | 8 +- docs/random/caps_grammar | 13 +- examples/Makefile.am | 37 +- gst/Makefile.am | 17 +- gst/autoplug/gstspideridentity.c | 2 +- gst/elements/gstbufferstore.c | 2 +- gst/elements/gstfakesink.c | 4 +- gst/elements/gstfakesrc.c | 4 +- gst/elements/gstfilesink.c | 105 ++- gst/elements/gstfilesink.h | 1 + gst/elements/gstfilesrc.c | 156 +++- gst/elements/gstfilesrc.h | 1 + gst/elements/gstidentity.c | 4 +- gst/gst.c | 50 +- gst/gst.h | 36 +- gst/gstbin.c | 4 +- gst/gstbuffer.c | 23 +- gst/gstbuffer.h | 5 + gst/gstcaps.c | 11 +- gst/gstelement.c | 152 +++- gst/gstelement.h | 20 +- gst/gstelementfactory.c | 105 ++- gst/gstevent.c | 10 + gst/gstevent.h | 9 +- gst/gstindex.c | 26 + gst/gstindex.h | 1 + gst/gstinfo.c | 10 +- gst/gstinfo.h | 4 +- gst/gstinterface.c | 3 + gst/gstmarshal.list | 1 + gst/gstobject.c | 1 + gst/gstpad.c | 14 +- gst/gstplugin.c | 30 + gst/gstplugin.h | 3 + gst/gstpluginfeature.c | 34 +- gst/gstpluginfeature.h | 8 +- gst/gstprops.c | 14 + gst/gstqueue.c | 6 + gst/gststructure.c | 2 +- gst/gststructure.h | 3 +- gst/gsttag.c | 831 +++++++++++++++++++++ gst/gsttaglist.c | 831 +++++++++++++++++++++ gst/gsturi.c | 505 ++++++++----- gst/gsturi.h | 78 +- gst/gstvalue.c | 47 ++ gst/gstvalue.h | 7 + gst/gstxml.c | 1 + gst/parse/grammar.y | 104 ++- gst/parse/parse.l | 15 + gst/parse/types.h | 19 + gst/registries/gstxmlregistry.c | 123 +-- gst/schedulers/gstbasicscheduler.c | 57 +- gstreamer.spec.in | 13 +- libs/gst/Makefile.am | 4 +- libs/gst/control/dparammanager.c | 1 - pkgconfig/Makefile.am | 16 +- plugins/elements/gstbufferstore.c | 2 +- plugins/elements/gstfakesink.c | 4 +- plugins/elements/gstfakesrc.c | 4 +- plugins/elements/gstfilesink.c | 105 ++- plugins/elements/gstfilesink.h | 1 + plugins/elements/gstfilesrc.c | 156 +++- plugins/elements/gstfilesrc.h | 1 + plugins/elements/gstidentity.c | 4 +- plugins/elements/gstqueue.c | 6 + po/Makefile.in.in | 2 +- po/de.po | 35 +- po/es.po | 32 +- po/nl.po | 32 +- po/no.po | 32 +- tests/old/examples/Makefile.am | 37 +- tests/old/testsuite/Makefile.am | 4 +- tests/old/testsuite/bytestream/Makefile.am | 2 +- tests/old/testsuite/caps/.gitignore | 2 + tests/old/testsuite/cleanup/Makefile.am | 6 +- tests/old/testsuite/debug/global.c | 1 + tests/old/testsuite/threads/queue.c | 2 +- testsuite/Makefile.am | 4 +- testsuite/bytestream/Makefile.am | 2 +- testsuite/caps/.gitignore | 2 + testsuite/cleanup/Makefile.am | 6 +- testsuite/debug/global.c | 1 + testsuite/threads/queue.c | 2 +- tools/Makefile.am | 27 +- tools/gst-inspect.c | 10 - tools/gst-launch.c | 41 +- tools/gst-xmlinspect.c | 10 - 112 files changed, 4188 insertions(+), 996 deletions(-) create mode 100644 gst/gsttag.c create mode 100644 gst/gsttaglist.c diff --git a/ChangeLog b/ChangeLog index 403a518ba2..d27e8a6fe6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2003-11-14 Thomas Vander Stichele + + * put GST_CACHE_DIR in config.h, as ordered by iain + +2003-11-14 Thomas Vander Stichele + + * Slap walters back into place. + * remove GST_CONFIG_DIR, it isn't used anymore, and it looks like + GST_CACHE_DIR replaces it (which is up for fixing next) + 2003-06-02 Colin Walters * Take over the world. diff --git a/Makefile.am b/Makefile.am index 7eea6b8bba..c6d6c5e0f9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,17 +28,18 @@ aclocaldir = $(datadir)/aclocal aclocal_DATA = gst-element-check-@GST_MAJORMINOR@.m4 SUBDIRS = include gst libs tools \ - $(SUBDIRS_TESTS) $(SUBDIRS_EXAMPLES) $(SUBDIRS_DOCS) \ - pkgconfig po + $(SUBDIRS_TESTS) $(SUBDIRS_EXAMPLES) \ + pkgconfig po \ + $(SUBDIRS_DOCS) # These are all the possible subdirs DIST_SUBDIRS = include libs gst \ tools \ tests testsuite \ examples \ - docs \ pkgconfig \ - po + po \ + docs EXTRA_DIST = gstreamer.spec.in gst-element-check.m4 \ configure.ac autogen.sh depcomp \ diff --git a/configure.ac b/configure.ac index 837d8f9c25..5c8d147248 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_CANONICAL_TARGET([]) dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AS_VERSION(gstreamer, GST_VERSION, 0, 7, 1, 1, GST_CVS="no", GST_CVS="yes") +AS_VERSION(gstreamer, GST_VERSION, 0, 7, 2, 1, GST_CVS="no", GST_CVS="yes") if test x$program_suffix = xNONE ; then program_suffix=-$GST_VERSION_MAJOR.$GST_VERSION_MINOR @@ -168,7 +168,7 @@ dnl ==================================== dnl === GLib 2 === dnl Minimum required version of GLib2 dnl required for compilation without warnings -GLIB2_REQ="2.0.1" +GLIB2_REQ="2.2" AC_SUBST(GLIB2_REQ) dnl Check for glib2 @@ -311,9 +311,9 @@ esac], [:]) dnl Default value AS_AC_EXPAND(GST_CACHE_DIR, $GST_CACHE_DIR) +AC_DEFINE_UNQUOTED(GST_CACHE_DIR, "$GST_CACHE_DIR", [Location of registry]) AC_MSG_NOTICE(Using $GST_CACHE_DIR as registry cache dir) - dnl building of tests AC_ARG_ENABLE(tests, AC_HELP_STRING([--disable-tests],[disable building test apps]), @@ -616,6 +616,7 @@ testsuite/indexers/Makefile testsuite/parse/Makefile testsuite/plugin/Makefile testsuite/refcounting/Makefile +testsuite/tags/Makefile testsuite/threads/Makefile examples/Makefile examples/autoplug/Makefile @@ -631,20 +632,21 @@ 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/version.entities docs/faq/Makefile docs/gst/Makefile docs/libs/Makefile docs/manual/Makefile -docs/pwg/Makefile docs/plugins/Makefile docs/plugins/gstreamer-plugins.types +docs/pwg/Makefile docs/xsl/Makefile +docs/version.entities pkgconfig/Makefile stamp.h pkgconfig/gstreamer.pc diff --git a/docs/.gitignore b/docs/.gitignore index 08f5ed37d8..2cd23a3717 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -5,3 +5,4 @@ Makefile.in *.la .deps .libs +version.entities diff --git a/docs/Makefile.am b/docs/Makefile.am index 50cdcbe4a6..892624abef 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -12,14 +12,14 @@ SUBDIRS_DOCS = endif SUBDIRS = $(SUBDIRS_DOCS) $(SUBDIRS_PLUGINS) -DIST_SUBDIRS = faq manual pwg gst libs plugins xsl +DIST_SUBDIRS = gst faq manual pwg libs plugins xsl EXTRA_DIST = \ slides manuals.mak htmlinstall.mak \ image-png image-pdf image-eps version.entities.in upload: - @for a in manual pwg faq; do cd $$a; make upload; cd ..; done + @for a in manual faq pwg; do cd $$a; make upload; cd ..; done dist-hook: $(RM) -rf $(distdir)/random/CVS diff --git a/docs/gst/.gitignore b/docs/gst/.gitignore index f6923174cf..d785f34447 100644 --- a/docs/gst/.gitignore +++ b/docs/gst/.gitignore @@ -12,6 +12,7 @@ gstreamer-unused.txt gstreamer-undocumented.txt gstreamer-decl-list.txt gstreamer-decl.txt +gstreamer-presed-scan.c gstreamer-scan.c gstreamer-scan gstreamer.args diff --git a/docs/gst/Makefile.am b/docs/gst/Makefile.am index 45add71cdd..c9e3424320 100644 --- a/docs/gst/Makefile.am +++ b/docs/gst/Makefile.am @@ -71,7 +71,7 @@ extra_files = # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib # contains GtkObjects/GObjects and you want to document signals and properties. -GTKDOC_CFLAGS = $(GST_CFLAGS) +GTKDOC_CFLAGS = $(GST_CFLAGS) -I$(top_builddir) GTKDOC_LIBS = $(GST_LIBS) $(SCANOBJ_DEPS) GTKDOC_CC=$(LIBTOOL) --mode=compile $(CC) @@ -126,15 +126,17 @@ all-local: html-build.stamp scan-build.stamp: $(HFILE_GLOB) $(SCANOBJ_DEPS) $(basefiles) @echo '*** Scanning header files ***' if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null ; then \ - CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" $(GTK_DOC_SCANOBJ) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE).types . ; \ + fi ; \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" $(GTK_DOC_SCANOBJ) --module=$(DOC_MODULE) ; \ else \ cd $(srcdir) ; \ for i in $(SCANOBJ_FILES) ; do \ test -f $$i || touch $$i ; \ done \ fi - cd $(srcdir) && \ - gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) + gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) touch scan-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp @@ -144,7 +146,11 @@ $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) @echo '*** Rebuilding template files ***' - cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE)-decl.txt . ; \ + cp $(srcdir)/$(DOC_MODULE)-sections.txt . ; \ + fi + gtkdoc-mktmpl --module=$(DOC_MODULE) touch tmpl-build.stamp tmpl.stamp: tmpl-build.stamp @@ -154,7 +160,6 @@ tmpl.stamp: tmpl-build.stamp sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) @echo '*** Building SGML ***' - cd $(srcdir) && \ gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS) touch sgml-build.stamp @@ -168,11 +173,12 @@ sgml.stamp: sgml-build.stamp # use bytes; in gtkdoc-fixxref html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) @echo '*** Building HTML ***' - test -d $(srcdir)/html || mkdir $(srcdir)/html - cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) - test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html ) + test -d html || mkdir html + cd html && gtkdoc-mkhtml $(DOC_MODULE) $(srcdir)/../$(DOC_MAIN_SGML_FILE) + test "x$(HTML_IMAGES)" = "x" || for i in $(HTML_IMAGES) ; do \ + cp $(srcdir)/$$i html ; done @echo '-- Fixing Crossreferences' - cd $(srcdir) && LANG=C && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + LANG=C && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) touch html-build.stamp endif @@ -194,10 +200,20 @@ distclean-local: clean rm -rf tmpl/*.sgml.bak rm -f $(DOC_MODULE).hierarchy rm -f *.stamp || true + if test x"$(srcdir)" != x. ; then \ + rm -f $(DOC_MODULE)-docs.sgml ; \ + rm -f $(DOC_MODULE).types ; \ + rm -f $(DOC_MODULE).interfaces ; \ + rm -f $(DOC_MODULE).prerequisites ; \ + rm -f $(DOC_MODULE)-sections.txt ; \ + rm -rf tmpl/*.sgml ; \ + fi + rm -rf *.o # thomas: make docs parallel installable; devhelp requires majorminor too +if DOC_HTML install-data-local: - $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) (installfiles=`echo $(srcdir)/html/*.html $(srcdir)/html/*.png`; \ if test "$$installfiles" = '$(srcdir)/html/*.html'; \ then echo '-- Nothing to install' ; \ @@ -211,7 +227,27 @@ install-data-local: $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ echo '-- Installing $(srcdir)/html/index.sgml' ; \ $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ - fi) + fi) +uninstall-local: + (installfiles=`echo $(srcdir)/html/*.html $(srcdir)/html/*.png`; \ + if test "$$installfiles" = '$(srcdir)/html/*.html'; \ + then echo '-- Nothing to uninstall' ; \ + else \ + for i in $$installfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ + fi) + rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) +else +install-data-local: +uninstall-local: +endif # # Require gtk-doc when making dist diff --git a/docs/gst/tmpl/gstautoplug.sgml b/docs/gst/tmpl/gstautoplug.sgml index 6c5bd633a2..3acf7c2215 100644 --- a/docs/gst/tmpl/gstautoplug.sgml +++ b/docs/gst/tmpl/gstautoplug.sgml @@ -99,6 +99,14 @@ The autoplug object + + + + + +@gstautoplug: the object which received the signal. +@arg1: + The type of the autoplugger. @@ -141,11 +149,3 @@ The type of the autoplugger. @Returns: - - - - - -@gstautoplug: the object which received the signal. -@arg1: - diff --git a/docs/gst/tmpl/gstbuffer.sgml b/docs/gst/tmpl/gstbuffer.sgml index 824c1e5b1e..c9474ec5a5 100644 --- a/docs/gst/tmpl/gstbuffer.sgml +++ b/docs/gst/tmpl/gstbuffer.sgml @@ -262,6 +262,7 @@ The basic structure of a buffer. @timestamp: @duration: @offset: +@offset_end: @pool: @pool_private: diff --git a/docs/gst/tmpl/gstcaps.sgml b/docs/gst/tmpl/gstcaps.sgml index 65f1399c44..8cb1606a5d 100644 --- a/docs/gst/tmpl/gstcaps.sgml +++ b/docs/gst/tmpl/gstcaps.sgml @@ -406,24 +406,6 @@ The name used for tracing @Returns: - - - - - -@caps: -@type_id: - - - - - - - -@caps: -@Returns: - - diff --git a/docs/gst/tmpl/gstconfig.sgml b/docs/gst/tmpl/gstconfig.sgml index 26c2e33861..99b80335de 100644 --- a/docs/gst/tmpl/gstconfig.sgml +++ b/docs/gst/tmpl/gstconfig.sgml @@ -108,13 +108,6 @@ If this is defined, the debugging subsystem - - - - - - - diff --git a/docs/gst/tmpl/gstelement.sgml b/docs/gst/tmpl/gstelement.sgml index c06cdbd907..e978c80481 100644 --- a/docs/gst/tmpl/gstelement.sgml +++ b/docs/gst/tmpl/gstelement.sgml @@ -880,14 +880,6 @@ Queries if the Element is decoupled. @obj: a #GstElement to query - - -Query wether this element is in the End Of Stream state. - - -@obj: a #GstElement to query - - Query wether this element can handle events. @@ -989,6 +981,15 @@ Is triggered whenever an error occured. @arg1: the error message @arg2: + + + + + +@gstelement: the object which received the signal. +@arg1: +@arg2: + Is triggered whenever a new pad is added to an element. diff --git a/docs/gst/tmpl/gstelementfactory.sgml b/docs/gst/tmpl/gstelementfactory.sgml index eddebe8f0c..6e6cfe15c2 100644 --- a/docs/gst/tmpl/gstelementfactory.sgml +++ b/docs/gst/tmpl/gstelementfactory.sgml @@ -62,22 +62,8 @@ describes the element, mostly for the benefit of editors. @longname: @klass: -@license: @description: -@version: @author: -@copyright: - - - - - - -@name: -@type: -@details: -@Returns: - @@ -88,15 +74,6 @@ describes the element, mostly for the benefit of editors. @Returns: - - - - - -@elementfactory: -@templ: - - @@ -137,51 +114,3 @@ describes the element, mostly for the benefit of editors. @Returns: - - - - - -@factoryname: -@name: -@Returns: - - - - - - - -@factory: -@rank: - - - - -The element is only marginally usefull for autoplugging - - - - - - -The plugin may not be used in autoplugging - - - - - - -The plugin is well suited for autoplugging - - - - - - -The plugin is suited for autoplugging but only as a second -candidate. - - - - diff --git a/docs/gst/tmpl/gstevent.sgml b/docs/gst/tmpl/gstevent.sgml index a32604f5c2..11467fecd0 100644 --- a/docs/gst/tmpl/gstevent.sgml +++ b/docs/gst/tmpl/gstevent.sgml @@ -48,6 +48,7 @@ The different major types of events. @GST_EVENT_INTERRUPT: mainly used by _get based elements when they were interrupted while waiting for a buffer. @GST_EVENT_NAVIGATION: +@GST_EVENT_TAG: diff --git a/docs/gst/tmpl/gstinfo.sgml b/docs/gst/tmpl/gstinfo.sgml index e2650f43c2..3ae7489d62 100644 --- a/docs/gst/tmpl/gstinfo.sgml +++ b/docs/gst/tmpl/gstinfo.sgml @@ -233,21 +233,6 @@ default. If you want to define a default category, do it like this: @Varargs: - - - - - -@category: -@level: -@file: -@function: -@line: -@object: -@format: -@args: - - diff --git a/docs/gst/tmpl/gstplugin.sgml b/docs/gst/tmpl/gstplugin.sgml index bd8e9ba321..30dc50fc7f 100644 --- a/docs/gst/tmpl/gstplugin.sgml +++ b/docs/gst/tmpl/gstplugin.sgml @@ -56,20 +56,19 @@ The plugin loading errors @GST_PLUGIN_ERROR_MODULE: The plugin could not be loaded @GST_PLUGIN_ERROR_DEPENDENCIES: The plugin has unresolved dependencies +@GST_PLUGIN_ERROR_NAME_MISMATCH: The plugin object -@name: -@longname: +@desc: @filename: @features: @numfeatures: @manager: @module: -@init_called: @@ -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. -@module: The GModule 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. + +@module: The GModule it was loaded from @@ -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. - - - -A handy macro to define a plugin description. This macro handles with all the issues -involved with the different linking methods for this plugin. - - -@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. - - - - -The macro used to define dynamically loaded plugins. - - -@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. - - - - -A macro used to define a statically linked plugin. - - -@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. - - - - - - - -@filename: -@Returns: - +@plugin_exit: +@version: +@license: +@copyright: +@package: +@origin: @@ -163,15 +127,6 @@ A macro used to define a statically linked plugin. @Returns: - - - - - -@plugin: -@longname: - - @@ -210,16 +165,6 @@ A macro used to define a statically linked plugin. @Returns: - - - - - -@plugin: -@error: -@Returns: - - diff --git a/docs/gst/tmpl/gstreamer-unused.sgml b/docs/gst/tmpl/gstreamer-unused.sgml index 2b293643a2..ecad921fed 100644 --- a/docs/gst/tmpl/gstreamer-unused.sgml +++ b/docs/gst/tmpl/gstreamer-unused.sgml @@ -196,6 +196,142 @@ GstAudioSink GstAudioSrc + + +GstAutoplug is an abstract class that is used for constructing and +linking elements. Two types of autopluggers exist: renderer ones and non +renderer ones. The renderer autopluggers will not have any src pads while the +non renderer ones do. + + + +You first need to create a suitable autoplugger with gst_autoplug_factory_make() +(see #GstAutoplugFactory). +The name of the autoplugger must be one of the registered autopluggers +(see #GstStaticAutoplug and #GstStaticAutoplugRender). + + +If the autoplugger supports the RENDERER API, use gst_autoplug_to_renderers() to +create a bin that links the src caps to the specified renderer elements. You can +then add the bin to a pipeline and run it. + + + GstAutoplug *autoplug; + GstElement *element; + GstElement *sink; + + /* create a static autoplugger */ + autoplug = gst_autoplug_factory_make ("staticrender"); + + /* create an osssink */ + sink = gst_element_factory_make ("osssink", "our_sink"); + + /* create an element that can play audio/mp3 through osssink */ + element = gst_autoplug_to_renderers (autoplug, + gst_caps_new ( + "sink_audio_caps", + "audio/mp3", + NULL + ), + sink, + NULL); + + /* add the element to a bin and link the sink pad */ + ... + + + +If the autoplugger supports the CAPS API, use gst_autoplug_to_caps() to +link the src caps to the destination caps. The created bin will have src caps +compatible with the provided sink caps. + + + GstAutoplug *autoplug; + GstElement *element; + + /* create a static autoplugger */ + autoplug = gst_autoplug_factory_make ("static"); + + /* create an element that converts audio/mp3 to audio/raw */ + element = gst_autoplug_to_caps (autoplug, + gst_caps_new ( + "sink_audio_caps", + "audio/mp3", + NULL + ), + gst_caps_new ( + "src_audio_caps", + "audio/raw", + NULL + ), + NULL); + + /* add the element to a bin and link the src/sink pads */ + ... + + + + +Optionally you can get a notification when a new object is added to the created +pipeline with a g_signal_connect to the "new_object" signal. + + + +Use the regular gst_object_destroy() call to destroy the autoplugger. + + + + + +#GstStaticAutoplug, #GstStaticAutoplugRender + + + + +Automatically create and link elements + + + +GstAutoplug + + + + +An autoplugfactory is used to create instances of an autoplugger. It +can be added to a #GstPlugin as it extends #GstPluginFeature. + + +Use gst_autoplug_factory_new() to create a new autoplugger which can be registered +to a plugin with gst_plugin_add_feature(). + + +Use gst_autoplug_factory_find() to find the named autoplugfactory. +or use gst_autoplug_factory_get_list() to get a list of all available autopluggers. + + +Once an autoplugfactory has been obtained use gst_autoplug_factory_create() to +instantiate a real autoplugger. Optionally gst_autoplug_factory_make() to create +a autoplugger from the named factory. + + +Use gst_autoplug_factory_destroy() to remove the factory from the global list. + + + + + +#GstAutoplug, #GstPlugin, #GstPluginFeature. + + + + +Create autopluggers from a factory. + + + +GstAutoplugFactory + + @@ -994,6 +1130,48 @@ The start point of a filter graph GstSrc + + +This autoplugger will create a non threaded element before running the +pipeline. + + + + + + + + + + +A static autoplugger. + + + +GstStaticAutoplug + + + + +this autoplugger will create a threaded element that can be used +in media players. + + + + + + + + + + +An autoplugger made for media playback + + + +GstStaticAutoplugRender + + The plugin doesn't alter the data but provides statistics about @@ -1056,27 +1234,6 @@ Cache time and byteoffsets. GstTimeCache - - -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. - - - - - - - - - - -Detect the mime type of a media stream - - - -GstTypeFind - - @@ -1835,6 +1992,12 @@ to the current function, i.e. "('element')" @format: printf-style format string @args...: printf arguments + + + + + + @@ -1898,6 +2061,13 @@ Queries whether the cothread holding this element needs to be stopped. @obj: The element to query + + +Query wether this element is in the End Of Stream state. + + +@obj: a #GstElement to query + Query whether this object has multiple input pads. @@ -1906,6 +2076,31 @@ Query whether this object has multiple input pads. @obj: Element to query for multiple input pads. + + +The element is only marginally usefull for autoplugging + + + + + +The plugin may not be used in autoplugging + + + + + +The plugin is well suited for autoplugging + + + + + +The plugin is suited for autoplugging but only as a second +candidate. + + + @@ -2769,6 +2964,37 @@ Get the flag indicating the properties are fixed from the template. @plugin: + + +A handy macro to define a plugin description. This macro handles with all the issues +involved with the different linking methods for this plugin. + + +@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. + + + +The macro used to define dynamically loaded plugins. + + +@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. + + + +A macro used to define a statically linked plugin. + + +@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. + @@ -4242,6 +4468,35 @@ The frequency. + + +The autoplug object + + + + + + + + +@gstautoplug: the object which received the signal. +@arg1: + + + +The autoplugfactory object + + + + + +The type of the autoplugger. + + +@GST_AUTOPLUG_TO_CAPS: +@GST_AUTOPLUG_TO_RENDERER: +@GST_AUTOPLUG_FLAG_LAST: + @@ -7144,6 +7399,29 @@ must be defined to activate the tracing functionality. @factories: @Returns: + + + + + +@factory: +@Returns: + + + + + + +@factory: + + + + + + +@name: +@Returns: + @@ -7189,6 +7467,24 @@ must be defined to activate the tracing functionality. @parent: @Returns: + + + + + +@name: +@Returns: + + + + + + +@name: +@longdesc: +@type: +@Returns: + @@ -7212,6 +7508,14 @@ must be defined to activate the tracing functionality. @fac: + + + + + +@autoplug: +@object: + @@ -7222,6 +7526,28 @@ must be defined to activate the tracing functionality. @factories: @Returns: + + + + + +@autoplug: +@srccaps: +@sinkcaps: +@Varargs: +@Returns: + + + + + + +@autoplug: +@srccaps: +@target: +@Varargs: +@Returns: + @@ -7704,6 +8030,14 @@ safely be modified. @caps: + + + + + +@caps: +@Returns: + @@ -7741,6 +8075,14 @@ safely be modified. @Returns: @count: + + + + + +@caps: +@type_id: + @@ -7915,6 +8257,20 @@ safely be modified. @data: @Returns: + + + + + +@category: +@level: +@file: +@function: +@line: +@object: +@format: +@args: + @@ -7998,6 +8354,14 @@ of an element he doesn't need anymore. @a: @b: + + + + + +@elementfactory: +@templ: + @@ -8054,6 +8418,25 @@ of an element he doesn't need anymore. @parent: @Returns: + + + + + +@factoryname: +@name: +@Returns: + + + + + + +@name: +@type: +@details: +@Returns: + @@ -8070,6 +8453,14 @@ of an element he doesn't need anymore. @parent: @Returns: + + + + + +@factory: +@rank: + @@ -9294,6 +9685,15 @@ Destroys the pipeline. @name: @Returns: + + + + + +@plugin: +@error: +@Returns: + @@ -9308,6 +9708,14 @@ Destroys the pipeline. @mime: + + + + + +@filename: +@Returns: + @@ -9316,6 +9724,14 @@ Destroys the pipeline. @parent: @Returns: + + + + + +@plugin: +@longname: + @@ -10040,6 +10456,19 @@ Destroy the scheduler + + + + + +@plugin: +@name: +@rank: +@func: +@extensions: +@possible_caps: +@data: + @@ -10088,6 +10517,15 @@ Destroy the scheduler @parent: @Returns: + + + + + +@handler: +@name: +@Returns: + @@ -10095,6 +10533,43 @@ Destroy the scheduler @handler: + + + + + +@name: +@Returns: + + + + + + +@uri: +@Returns: + + + + + + +@uri: +@name: +@Returns: + + + + + + +@name: +@uri: +@longdesc: +@element: +@property: +@Returns: + diff --git a/docs/gst/tmpl/gsttypefind.sgml b/docs/gst/tmpl/gsttypefind.sgml index 10ae8f64bd..6cd2b8bb88 100644 --- a/docs/gst/tmpl/gsttypefind.sgml +++ b/docs/gst/tmpl/gsttypefind.sgml @@ -98,17 +98,3 @@ gst_type_find_factory_register() @Returns: - - - - - -@plugin: -@name: -@rank: -@func: -@extensions: -@possible_caps: -@data: - - diff --git a/docs/gst/tmpl/gsturi.sgml b/docs/gst/tmpl/gsturi.sgml index 603da6477a..1488c3db79 100644 --- a/docs/gst/tmpl/gsturi.sgml +++ b/docs/gst/tmpl/gsturi.sgml @@ -15,54 +15,3 @@ and the element property that can handle a given URI. - - - - - -@name: -@uri: -@longdesc: -@element: -@property: -@Returns: - - - - - - - -@name: -@Returns: - - - - - - - -@uri: -@Returns: - - - - - - - -@handler: -@name: -@Returns: - - - - - - - -@uri: -@name: -@Returns: - - diff --git a/docs/gst/tmpl/gstxml.sgml b/docs/gst/tmpl/gstxml.sgml index 08450b21b9..32d00bc1f9 100644 --- a/docs/gst/tmpl/gstxml.sgml +++ b/docs/gst/tmpl/gstxml.sgml @@ -110,10 +110,6 @@ All GstElements can be serialized to an XML presentation and subsequently loaded -@: -@: -@: - @gstxml: the object which received the signal. @arg1: @arg2: @@ -123,7 +119,7 @@ All GstElements can be serialized to an XML presentation and subsequently loaded -@gstxml: the object which received the signal. -@arg1: -@arg2: +@: +@: +@: diff --git a/docs/htmlinstall.mak b/docs/htmlinstall.mak index f0e24c61fd..0d2d6ecff2 100644 --- a/docs/htmlinstall.mak +++ b/docs/htmlinstall.mak @@ -2,6 +2,7 @@ # I really don't like this hack, but automake doesn't seem to want to # install directory trees :( +if DOC_HTML install-data-local: html mkdir -p $(docdir) cp -pr $(HTML_DAT) $(docdir) @@ -9,3 +10,7 @@ install-data-local: html uninstall-local: for part in $(HTML_DAT); do rm -rf $(docdir)/$$part; done rmdir $(docdir) +else +install-data-local: +uninstall-local: +endif diff --git a/docs/libs/.gitignore b/docs/libs/.gitignore index 30446aa263..c20d3bb023 100644 --- a/docs/libs/.gitignore +++ b/docs/libs/.gitignore @@ -1,12 +1,15 @@ -Makefile -Makefile.in +*.stamp html xml -gstreamer-libs-unused.txt -gstreamer-libs-undocumented.txt +Makefile +Makefile.in gstreamer-libs-decl.txt gstreamer-libs-decl-list.txt -*.stamp +gstreamer-libs-presed-scan.c +gstreamer-libs-undocumented.txt +gstreamer-libs-unused.txt gstreamer-libs.args gstreamer-libs.hierarchy +gstreamer-libs.interfaces +gstreamer-libs.prerequisites gstreamer-libs.signals diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index c5836b6ca2..7d636e73c4 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -72,7 +72,7 @@ extra_files = # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib # contains GtkObjects/GObjects and you want to document signals and properties. -GTKDOC_CFLAGS = $(GST_CFLAGS) +GTKDOC_CFLAGS = $(GST_CFLAGS) -I$(top_builddir) GTKDOC_LIBS = $(GST_LIBS) $(SCANOBJ_DEPS) GTKDOC_CC=$(LIBTOOL) --mode=compile $(CC) @@ -126,14 +126,17 @@ scan-build.stamp: $(HFILE_GLOB) $(SCANOBJ_DEPS) $(basefiles) @echo '*** Scanning header files ***' if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null ; then \ CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" $(GTK_DOC_SCANOBJ) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE).types . ; \ + fi ; \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" $(GTK_DOC_SCANOBJ) --module=$(DOC_MODULE) ; \ else \ cd $(srcdir) ; \ for i in $(SCANOBJ_FILES) ; do \ test -f $$i || touch $$i ; \ done \ fi - cd $(srcdir) && \ - gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) + gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) touch scan-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp @@ -143,7 +146,11 @@ $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) @echo '*** Rebuilding template files ***' - cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE)-decl.txt . ; \ + cp $(srcdir)/$(DOC_MODULE)-sections.txt . ; \ + fi + gtkdoc-mktmpl --module=$(DOC_MODULE) touch tmpl-build.stamp tmpl.stamp: tmpl-build.stamp @@ -153,7 +160,6 @@ tmpl.stamp: tmpl-build.stamp sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) @echo '*** Building SGML ***' - cd $(srcdir) && \ gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS) touch sgml-build.stamp @@ -167,11 +173,12 @@ sgml.stamp: sgml-build.stamp # use bytes; in gtkdoc-fixxref html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) @echo '*** Building HTML ***' - test -d $(srcdir)/html || mkdir $(srcdir)/html - cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) - test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html ) + test -d html || mkdir html + cd html && gtkdoc-mkhtml $(DOC_MODULE) $(srcdir)/../$(DOC_MAIN_SGML_FILE) + test "x$(HTML_IMAGES)" = "x" || for i in $(HTML_IMAGES) ; do \ + cp $(srcdir)/$$i html ; done @echo '-- Fixing Crossreferences' - cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + LANG=C && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) touch html-build.stamp endif @@ -192,7 +199,18 @@ distclean-local: clean rm -rf tmpl/*.sgml.bak rm -f $(DOC_MODULE).hierarchy rm -f *.stamp || true + if test x"$(srcdir)" != x. ; then \ + rm -f $(DOC_MODULE)-docs.sgml ; \ + rm -f $(DOC_MODULE).types ; \ + rm -f $(DOC_MODULE).interfaces ; \ + rm -f $(DOC_MODULE).prerequisites ; \ + rm -f $(DOC_MODULE)-sections.txt ; \ + rm -rf tmpl/*.sgml ; \ + fi + rm -f *.o + +if DOC_HTML install-data-local: $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) (installfiles=`echo $(srcdir)/html/*.html $(srcdir)/html/*.png`; \ @@ -209,6 +227,26 @@ install-data-local: echo '-- Installing $(srcdir)/html/index.sgml' ; \ $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ fi) +uninstall-local: + (installfiles=`echo $(srcdir)/html/*.html $(srcdir)/html/*.png`; \ + if test "$$installfiles" = '$(srcdir)/html/*.html'; \ + then echo '-- Nothing to uninstall' ; \ + else \ + for i in $$installfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ + fi) + rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) +else +install-data-local: +uninstall-local: +endif # # Require gtk-doc when making dist diff --git a/docs/manual/appendix-quotes.xml b/docs/manual/appendix-quotes.xml index cc88ad101d..30ad944316 100644 --- a/docs/manual/appendix-quotes.xml +++ b/docs/manual/appendix-quotes.xml @@ -11,6 +11,22 @@ + + 23 Nov 2003 + + + Uraeus: ah yes, the sleeping part, my mind + is not multitasking so I was still thinking about exercise + + + dolphy: Uraeus: your mind is multitasking + + + dolphy: Uraeus: you just miss low latency patches + + + + 14 Sep 2002 diff --git a/docs/manual/quotes.xml b/docs/manual/quotes.xml index cc88ad101d..30ad944316 100644 --- a/docs/manual/quotes.xml +++ b/docs/manual/quotes.xml @@ -11,6 +11,22 @@ + + 23 Nov 2003 + + + Uraeus: ah yes, the sleeping part, my mind + is not multitasking so I was still thinking about exercise + + + dolphy: Uraeus: your mind is multitasking + + + dolphy: Uraeus: you just miss low latency patches + + + + 14 Sep 2002 diff --git a/docs/manuals.mak b/docs/manuals.mak index af54e9fc0b..07e116a264 100644 --- a/docs/manuals.mak +++ b/docs/manuals.mak @@ -89,7 +89,7 @@ $(BUILDDIR)/$(MAIN): $(XML) $(CSS) @-mkdir -p $(BUILDDIR) @for a in $(XML); do cp $(srcdir)/$$a $(BUILDDIR); done @for a in $(CSS); do cp $(srcdir)/$$a $(BUILDDIR); done - @cp $(srcdir)/../version.entities $(BUILDDIR) + @cp ../version.entities $(BUILDDIR) html/index.html: $(BUILDDIR)/$(MAIN) $(PNG_BUILT) $(FIG_SRC) @echo "*** Generating HTML output ***" @@ -120,7 +120,7 @@ $(DOC).pdf: $(DOC).ps # @export LC_PAPER=$(PAPER_LOCALE) && xmlto pdf $(MAIN) # @rm image.entities -clean: +clean-local: -$(RM) -r $(BUILDDIR) -$(RM) -r html -$(RM) $(DOC).ps @@ -165,8 +165,8 @@ $(BUILDIMAGESDIR)/%.ps: %.png @cat $< | pngtopnm | pnmtops -noturn > $@ 2> /dev/null # make sure xml validates properly -check-local: - xmllint -noout -valid $(MAIN) +#check-local: +# xmllint -noout -valid $(srcdir)/$(MAIN) ### this is a website upload target diff --git a/docs/random/caps_grammar b/docs/random/caps_grammar index 47eae0e3fb..a2c406214e 100644 --- a/docs/random/caps_grammar +++ b/docs/random/caps_grammar @@ -1,5 +1,14 @@ +Canonical caps/structure strings (those created by gst_caps_to_string() +and gst_structure_to_string()) do not have AUTO_VALUE. +Goals: + - UTF-8 clean + - SIMPLE_STRINGs should cover most simple cases that don't interfere + with other parts of the gst_caps or gst_parse grammar + - forward-parsed grammar + - quoted strings handle backslash escaping as well as XML-style (&ack;) + escaping CAPS = STRUCTURE [ ';' STRUCTURE ]* @@ -27,12 +36,12 @@ STRING = ["][^"]["] | ['][^']['] | SIMPLE_STRING -SIMPLE_STRING = [A-Za-z][A-Za-z0-9]* +SIMPLE_STRING = [A-Za-z0-9_+-:./]+ TYPE = "int" | "i" | "float" | "f" | "double" | "d" | "fourcc" | "4" | "boolean" | "bool" | "b" | GTYPE - + Canonical Examples: diff --git a/examples/Makefile.am b/examples/Makefile.am index 416ebf2f7f..c7d650c31b 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -4,12 +4,35 @@ else GST_LOADSAVE_DIRS = xml typefind endif -SUBDIRS = $(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) -DIST_SUBDIRS = helloworld helloworld2 \ - queue queue2 queue3 queue4 \ - launch thread xml plugins typefind mixer cutter pingpong manual +DIST_SUBDIRS = helloworld \ + queue \ + queue2 \ + queue3 \ + queue4 \ + launch \ + thread \ + plugins \ + mixer \ + cutter \ + pingpong \ + manual \ + xml \ + typefind \ + retag diff --git a/gst/Makefile.am b/gst/Makefile.am index 9b3138523c..f24e33f5ee 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -69,7 +69,7 @@ endif EXTRA_libgstreamer_@GST_MAJORMINOR@_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gstparse.c gsttrace.c -SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . elements schedulers $(GST_INDEX_DIRS) +SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . autoplug elements schedulers $(GST_INDEX_DIRS) DIST_SUBDIRS = autoplug elements parse registries schedulers indexers libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \ @@ -104,6 +104,8 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \ gstscheduler.c \ gststructure.c \ gstsystemclock.c \ + gsttag.c \ + gsttaginterface.c \ gstthread.c \ gstthreaddummy.c \ $(GST_TRACE_SRC) \ @@ -121,11 +123,12 @@ 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) \ -DG_LOG_DOMAIN=g_log_domain_gstreamer \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" \ -DGST_MAJORMINOR=\""$(GST_MAJORMINOR)"\" libgstreamer_@GST_MAJORMINOR@_la_LIBADD = $(LIBGST_LIBS) $(GST_PARSE_LIBADD) $(GST_REGISTRY_LIBADD) libgstreamer_@GST_MAJORMINOR@_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@ @@ -165,6 +168,8 @@ gst_headers = \ gstscheduler.h \ gststructure.h \ gstsystemclock.h \ + gsttag.h \ + gsttaginterface.h \ gstthread.h \ gsttrace.h \ gsttrashstack.h \ @@ -227,12 +232,4 @@ gstenumtypes.c: $(gst_headers) --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ $^ > gstenumtypes.c -# Don't want the generated marshal files in the dist -dist-hook: - rm -f $(distdir)/gstmarshal.c $(distdir)/gstmarshal.h - -# Clean generated files -distclean-local: - rm -f $(top_builddir)/gst/gstmarshal.c $(top_builddir)/gst/gstmarshal.h - EXTRA_DIST = ROADMAP diff --git a/gst/autoplug/gstspideridentity.c b/gst/autoplug/gstspideridentity.c index dd2e14bb5a..7c1e48d609 100644 --- a/gst/autoplug/gstspideridentity.c +++ b/gst/autoplug/gstspideridentity.c @@ -440,7 +440,7 @@ spider_find_suggest (gpointer data, guint probability, const GstCaps2 *caps) GST_INFO ("suggest %u, %s", probability, caps_str); g_free (caps_str); if (probability > find->best_probability) { - gst_caps2_replace (&find->caps, caps); + gst_caps2_replace (&find->caps, gst_caps2_copy (caps)); find->best_probability = probability; } } diff --git a/gst/elements/gstbufferstore.c b/gst/elements/gstbufferstore.c index f399ab4d61..8d38740da5 100644 --- a/gst/elements/gstbufferstore.c +++ b/gst/elements/gstbufferstore.c @@ -119,7 +119,7 @@ gst_buffer_store_class_init (gpointer g_class, gpointer class_data) gst_buffer_store_signals[BUFFER_ADDED] = g_signal_new ("buffer-added", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstBufferStoreClass, buffer_added), continue_accu, NULL, - gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); + gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_BUFFER); store_class->cleared = gst_buffer_store_cleared_func; store_class->buffer_added = gst_buffer_store_add_buffer_func; diff --git a/gst/elements/gstfakesink.c b/gst/elements/gstfakesink.c index 815aadc51e..4f8a6a008c 100644 --- a/gst/elements/gstfakesink.c +++ b/gst/elements/gstfakesink.c @@ -175,8 +175,8 @@ gst_fakesink_class_init (GstFakeSinkClass *klass) gst_fakesink_signals[SIGNAL_HANDOFF] = g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstFakeSinkClass, handoff), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2, + GST_TYPE_BUFFER, GST_TYPE_PAD); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property); diff --git a/gst/elements/gstfakesrc.c b/gst/elements/gstfakesrc.c index 75080a2563..95a0a69b3b 100644 --- a/gst/elements/gstfakesrc.c +++ b/gst/elements/gstfakesrc.c @@ -271,8 +271,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass) gst_fakesrc_signals[SIGNAL_HANDOFF] = g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2, + GST_TYPE_BUFFER, GST_TYPE_PAD); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property); diff --git a/gst/elements/gstfilesink.c b/gst/elements/gstfilesink.c index 5c4c81c84f..fef5d7e8f7 100644 --- a/gst/elements/gstfilesink.c +++ b/gst/elements/gstfilesink.c @@ -69,6 +69,7 @@ GST_PAD_FORMATS_FUNCTION (gst_filesink_get_formats, static void gst_filesink_base_init (gpointer g_class); static void gst_filesink_class_init (GstFileSinkClass *klass); static void gst_filesink_init (GstFileSink *filesink); +static void gst_filesink_dispose (GObject *object); static void gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); @@ -83,6 +84,8 @@ static gboolean gst_filesink_pad_query (GstPad *pad, GstQueryType type, GstFormat *format, gint64 *value); static void gst_filesink_chain (GstPad *pad,GstData *_data); +static void gst_filesink_uri_handler_init (gpointer g_iface, gpointer iface_data); + static GstElementStateReturn gst_filesink_change_state (GstElement *element); static GstElementClass *parent_class = NULL; @@ -105,7 +108,14 @@ gst_filesink_get_type (void) 0, (GInstanceInitFunc)gst_filesink_init, }; + static const GInterfaceInfo urihandler_info = { + gst_filesink_uri_handler_init, + NULL, + NULL + }; filesink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFileSink", &filesink_info, 0); + + g_type_add_interface_static (filesink_type, GST_TYPE_URI_HANDLER, &urihandler_info); GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0, "filesink element"); } @@ -138,8 +148,8 @@ gst_filesink_class_init (GstFileSinkClass *klass) gobject_class->set_property = gst_filesink_set_property; gobject_class->get_property = gst_filesink_get_property; + gobject_class->dispose = gst_filesink_dispose; } - static void gst_filesink_init (GstFileSink *filesink) { @@ -158,7 +168,38 @@ gst_filesink_init (GstFileSink *filesink) filesink->filename = NULL; filesink->file = NULL; } +static void +gst_filesink_dispose (GObject *object) +{ + GstFileSink *sink = GST_FILESINK (object); + G_OBJECT_CLASS (parent_class)->dispose (object); + + g_free (sink->uri); + sink->uri = NULL; + g_free (sink->filename); + sink->filename = NULL; +} +static gboolean +gst_filesink_set_location (GstFileSink *sink, const gchar *location) +{ + /* the element must be stopped or paused in order to do this */ + if (GST_STATE (sink) > GST_STATE_PAUSED) + return FALSE; + if (GST_STATE (sink) == GST_STATE_PAUSED && + GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN)) + return FALSE; + + g_free (sink->filename); + g_free (sink->uri); + sink->filename = g_strdup (location); + sink->uri = gst_uri_construct ("file", location); + + if (GST_STATE (sink) == GST_STATE_PAUSED) + gst_filesink_open_file (sink); + + return TRUE; +} static void gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { @@ -169,16 +210,7 @@ gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value, switch (prop_id) { case ARG_LOCATION: - /* the element must be stopped or paused in order to do this */ - g_return_if_fail (GST_STATE (sink) <= GST_STATE_PAUSED); - if (GST_STATE (sink) == GST_STATE_PAUSED) - g_return_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN)); - - if (sink->filename) - g_free (sink->filename); - sink->filename = g_strdup (g_value_get_string (value)); - if (GST_STATE (sink) == GST_STATE_PAUSED) - gst_filesink_open_file (sink); + gst_filesink_set_location (sink, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -435,3 +467,54 @@ gst_filesink_change_state (GstElement *element) return GST_STATE_SUCCESS; } + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static guint +gst_filesink_uri_get_type (void) +{ + return GST_URI_SINK; +} +static gchar ** +gst_filesink_uri_get_protocols(void) +{ + static gchar *protocols[] = {"file", NULL}; + return protocols; +} +static const gchar * +gst_filesink_uri_get_uri (GstURIHandler *handler) +{ + GstFileSink *sink = GST_FILESINK (handler); + + return sink->uri; +} +static gboolean +gst_filesink_uri_set_uri (GstURIHandler *handler, const gchar *uri) +{ + gchar *protocol, *location; + gboolean ret; + GstFileSink *sink = GST_FILESINK (handler); + + protocol = gst_uri_get_protocol (uri); + if (strcmp (protocol, "file") != 0) { + g_free (protocol); + return FALSE; + } + g_free (protocol); + location = gst_uri_get_location (uri); + ret = gst_filesink_set_location (sink, location); + g_free (location); + + return ret; +} + +static void +gst_filesink_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_filesink_uri_get_type; + iface->get_protocols = gst_filesink_uri_get_protocols; + iface->get_uri = gst_filesink_uri_get_uri; + iface->set_uri = gst_filesink_uri_set_uri; +} diff --git a/gst/elements/gstfilesink.h b/gst/elements/gstfilesink.h index b72551bfe0..bd85a1d012 100644 --- a/gst/elements/gstfilesink.h +++ b/gst/elements/gstfilesink.h @@ -53,6 +53,7 @@ struct _GstFileSink { GstElement element; gchar *filename; + gchar *uri; FILE *file; guint64 data_written; diff --git a/gst/elements/gstfilesrc.c b/gst/elements/gstfilesrc.c index f243d97c27..f2789ec59f 100644 --- a/gst/elements/gstfilesrc.c +++ b/gst/elements/gstfilesrc.c @@ -128,6 +128,7 @@ static void gst_filesrc_set_property (GObject *object, guint prop_id, static void gst_filesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static gboolean gst_filesrc_check_filesize (GstFileSrc *src); static GstData * gst_filesrc_get (GstPad *pad); static gboolean gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event); static gboolean gst_filesrc_srcpad_query (GstPad *pad, GstQueryType type, @@ -135,6 +136,8 @@ static gboolean gst_filesrc_srcpad_query (GstPad *pad, GstQueryType type, static GstElementStateReturn gst_filesrc_change_state (GstElement *element); +static void gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data); + static GstElementClass *parent_class = NULL; /*static guint gst_filesrc_signals[LAST_SIGNAL] = { 0 };*/ @@ -156,8 +159,15 @@ gst_filesrc_get_type(void) 0, (GInstanceInitFunc)gst_filesrc_init, }; + static const GInterfaceInfo urihandler_info = { + gst_filesrc_uri_handler_init, + NULL, + NULL + }; filesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFileSrc", &filesrc_info, 0); - + + g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER, &urihandler_info); + GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element"); } return filesrc_type; @@ -262,8 +272,32 @@ gst_filesrc_dispose (GObject *object) g_mutex_free (src->map_regions_lock); if (src->filename) g_free (src->filename); + if (src->uri) + g_free (src->uri); } +static gboolean +gst_filesrc_set_location (GstFileSrc *src, const gchar *location) +{ + /* the element must be stopped in order to do this */ + if (GST_STATE (src) == GST_STATE_PLAYING) + return FALSE; + + if (src->filename) g_free (src->filename); + if (src->uri) g_free (src->uri); + /* clear the filename if we get a NULL (is that possible?) */ + if (location == NULL) { + src->filename = NULL; + src->uri = NULL; + } else { + src->filename = g_strdup (location); + src->uri = gst_uri_construct ("file", src->filename); + } + g_object_notify (G_OBJECT (src), "location"); + gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri); + + return TRUE; +} static void gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -277,19 +311,7 @@ gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, G switch (prop_id) { case ARG_LOCATION: - /* the element must be stopped in order to do this */ - g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING); - - if (src->filename) g_free (src->filename); - /* clear the filename if we get a NULL (is that possible?) */ - if (g_value_get_string (value) == NULL) { - gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL); - src->filename = NULL; - /* otherwise set the new filename */ - } else { - src->filename = g_strdup (g_value_get_string (value)); - } - g_object_notify (G_OBJECT (src), "location"); + gst_filesrc_set_location (src, g_value_get_string (value)); break; case ARG_BLOCKSIZE: src->block_size = g_value_get_ulong (value); @@ -506,8 +528,10 @@ gst_filesrc_get_mmap (GstFileSrc *src) /* check to see if we're going to overflow the end of the file */ if (readend > src->filelen) { - readsize = src->filelen - src->curoffset; - readend = src->curoffset + readsize; + if (!gst_filesrc_check_filesize (src) || readend > src->filelen) { + readsize = src->filelen - src->curoffset; + readend = src->curoffset + readsize; + } } GST_LOG ("attempting to read %08lx, %08lx, %08lx, %08lx", @@ -599,7 +623,7 @@ gst_filesrc_get_mmap (GstFileSrc *src) /* subbuffer it */ buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - nextmap, readsize); - GST_BUFFER_OFFSET (buf) = mapstart + src->curoffset - nextmap; + GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET (src->mapbuf) + src->curoffset - nextmap; } } } @@ -613,6 +637,7 @@ gst_filesrc_get_mmap (GstFileSrc *src) } /* we're done, return the buffer */ + g_assert (src->curoffset == GST_BUFFER_OFFSET (buf)); src->curoffset += GST_BUFFER_SIZE(buf); return buf; } @@ -626,7 +651,9 @@ gst_filesrc_get_read (GstFileSrc *src) readsize = src->block_size; if (src->curoffset + readsize > src->filelen) { - readsize = src->filelen - src->curoffset; + if (!gst_filesrc_check_filesize (src) || src->curoffset + readsize > src->filelen) { + readsize = src->filelen - src->curoffset; + } } buf = gst_buffer_new_and_alloc (readsize); @@ -675,11 +702,14 @@ gst_filesrc_get (GstPad *pad) } /* check for EOF */ + g_assert (src->curoffset <= src->filelen); if (src->curoffset == src->filelen) { - GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT" %" G_GINT64_FORMAT, - src->curoffset, src->filelen); - gst_element_set_eos (GST_ELEMENT (src)); - return GST_DATA (gst_event_new (GST_EVENT_EOS)); + if (!gst_filesrc_check_filesize (src) || src->curoffset >= src->filelen) { + GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT" %" G_GINT64_FORMAT, + src->curoffset, src->filelen); + gst_element_set_eos (GST_ELEMENT (src)); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } } if (src->using_mmap){ @@ -689,6 +719,22 @@ gst_filesrc_get (GstPad *pad) } } +/* TRUE if the filesize of the file was updated */ +static gboolean +gst_filesrc_check_filesize (GstFileSrc *src) +{ + struct stat stat_results; + + g_return_val_if_fail (GST_FLAG_IS_SET (src ,GST_FILESRC_OPEN), FALSE); + + fstat(src->fd, &stat_results); + GST_DEBUG_OBJECT (src, "checked filesize on %s (was %"G_GUINT64_FORMAT", is %"G_GUINT64_FORMAT")", + src->filename, src->filelen, (guint64) stat_results.st_size); + if (src->filelen == (guint64) stat_results.st_size) + return FALSE; + src->filelen = stat_results.st_size; + return TRUE; +} /* open the file and mmap it, necessary to go to READY state */ static gboolean gst_filesrc_open_file (GstFileSrc *src) @@ -799,6 +845,7 @@ gst_filesrc_srcpad_query (GstPad *pad, GstQueryType type, if (*format != GST_FORMAT_BYTES) { return FALSE; } + gst_filesrc_check_filesize (src); *value = src->filelen; break; case GST_QUERY_POSITION: @@ -842,20 +889,25 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event) switch (GST_EVENT_SEEK_METHOD (event)) { case GST_SEEK_METHOD_SET: - if (offset > src->filelen) - goto error; + if (offset > src->filelen && (!gst_filesrc_check_filesize (src) || offset > src->filelen)) { + goto error; + } src->curoffset = offset; GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT, src->curoffset); break; case GST_SEEK_METHOD_CUR: if (offset + src->curoffset > src->filelen) - goto error; + if (!gst_filesrc_check_filesize (src) || offset + src->curoffset > src->filelen) + goto error; src->curoffset += offset; GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT, src->curoffset); break; case GST_SEEK_METHOD_END: - if (ABS (offset) > src->filelen) + if (ABS (offset) > src->filelen) { + if (!gst_filesrc_check_filesize (src) || ABS (offset) > src->filelen) + goto error; goto error; + } src->curoffset = src->filelen - ABS (offset); GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT, src->curoffset); break; @@ -888,3 +940,55 @@ error: gst_event_unref (event); return FALSE; } + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static guint +gst_filesrc_uri_get_type (void) +{ + return GST_URI_SRC; +} +static gchar ** +gst_filesrc_uri_get_protocols(void) +{ + static gchar *protocols[] = {"file", NULL}; + return protocols; +} +static const gchar * +gst_filesrc_uri_get_uri (GstURIHandler *handler) +{ + GstFileSrc *src = GST_FILESRC (handler); + + return src->uri; +} +static gboolean +gst_filesrc_uri_set_uri (GstURIHandler *handler, const gchar *uri) +{ + gchar *protocol, *location; + gboolean ret; + GstFileSrc *src = GST_FILESRC (handler); + + protocol = gst_uri_get_protocol (uri); + if (strcmp (protocol, "file") != 0) { + g_free (protocol); + return FALSE; + } + g_free (protocol); + location = gst_uri_get_location (uri); + ret = gst_filesrc_set_location (src, location); + g_free (location); + + return ret; +} + +static void +gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_filesrc_uri_get_type; + iface->get_protocols = gst_filesrc_uri_get_protocols; + iface->get_uri = gst_filesrc_uri_get_uri; + iface->set_uri = gst_filesrc_uri_set_uri; +} + diff --git a/gst/elements/gstfilesrc.h b/gst/elements/gstfilesrc.h index 23b6ddeef5..1f584be387 100644 --- a/gst/elements/gstfilesrc.h +++ b/gst/elements/gstfilesrc.h @@ -58,6 +58,7 @@ struct _GstFileSrc { guint pagesize; /* system page size*/ gchar *filename; /* filename */ + gchar *uri; /* caching the URI */ gint fd; /* open file descriptor*/ off_t filelen; /* what's the file length?*/ diff --git a/gst/elements/gstidentity.c b/gst/elements/gstidentity.c index c40ef162eb..4dc25af3e8 100644 --- a/gst/elements/gstidentity.c +++ b/gst/elements/gstidentity.c @@ -145,8 +145,8 @@ gst_identity_class_init (GstIdentityClass *klass) gst_identity_signals[SIGNAL_HANDOFF] = g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstIdentityClass, handoff), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, + GST_TYPE_BUFFER); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property); diff --git a/gst/gst.c b/gst/gst.c index 814f6b3695..a5dff6b697 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -85,11 +85,13 @@ debug_log_handler (const gchar *log_domain, enum { ARG_VERSION=1, ARG_FATAL_WARNINGS, +#ifndef GST_DISABLE_GST_DEBUG ARG_DEBUG_LEVEL, ARG_DEBUG, ARG_DEBUG_DISABLE, ARG_DEBUG_NO_COLOR, ARG_DEBUG_HELP, +#endif ARG_DISABLE_CPU_OPT, ARG_PLUGIN_SPEW, ARG_PLUGIN_PATH, @@ -390,9 +392,11 @@ init_pre (void) } /* we need threading to be enabled right here */ _gst_debug_init(); - + +#ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, GST_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +#endif /* ENABLE_NLS */ #ifndef GST_DISABLE_REGISTRY { @@ -529,6 +533,7 @@ init_post (void) _gst_plugin_initialize (); _gst_event_initialize (); _gst_buffer_initialize (); + _gst_tag_initialize (); #ifndef GST_DISABLE_REGISTRY if (!_gst_registry_fixed) { @@ -572,20 +577,48 @@ init_post (void) return TRUE; } +#ifndef GST_DISABLE_GST_DEBUG +static gint +sort_by_category_name (gconstpointer a, gconstpointer b) +{ + return strcmp (gst_debug_category_get_name ((GstDebugCategory *) a), + gst_debug_category_get_name ((GstDebugCategory *) b)); +} static void gst_debug_help (void) { - GSList *cats, *walk; + GSList *list, *walk; + GList *list2, *walk2; + + if (!init_post ()) + exit (1); + + walk2 = list2 = gst_registry_pool_plugin_list (); + while (walk2) { + GstPlugin *plugin = GST_PLUGIN (walk2->data); + walk2 = g_list_next (walk2); + + if (!gst_plugin_is_loaded (plugin)) { +#ifndef GST_DISABLE_REGISTRY + if (GST_IS_REGISTRY (plugin->manager)) { + GST_CAT_LOG (GST_CAT_PLUGIN_LOADING, "loading plugin %s", plugin->desc.name); + if (gst_registry_load_plugin (GST_REGISTRY (plugin->manager), plugin) != GST_REGISTRY_OK) + GST_CAT_WARNING (GST_CAT_PLUGIN_LOADING, "loading plugin %s failed", plugin->desc.name); + } +#endif /* GST_DISABLE_REGISTRY */ + } + } + g_list_free (list2); + + list = gst_debug_get_all_categories (); + walk = list = g_slist_sort (list, sort_by_category_name); - walk = cats = gst_debug_get_all_categories (); - g_print ("\n"); g_print ("name level description\n"); g_print ("---------------------+--------+--------------------------------\n"); while (walk) { - /* unused when debugging is disabled */ - G_GNUC_UNUSED GstDebugCategory *cat = (GstDebugCategory *) walk->data; + GstDebugCategory *cat = (GstDebugCategory *) walk->data; if (gst_debug_is_colored ()) { gchar *color = gst_debug_construct_term_color (cat->color); @@ -605,9 +638,10 @@ gst_debug_help (void) } walk = g_slist_next (walk); } + g_slist_free (list); g_print ("\n"); } - +#endif static void init_popt_callback (poptContext context, enum poptCallbackReason reason, @@ -631,6 +665,7 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason, fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; g_log_set_always_fatal (fatal_mask); break; +#ifndef GST_DISABLE_GST_DEBUG case ARG_DEBUG_LEVEL: { gint tmp = 0; tmp = strtol (arg, NULL, 0); @@ -651,6 +686,7 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason, case ARG_DEBUG_HELP: gst_debug_help (); exit (0); +#endif case ARG_DISABLE_CPU_OPT: _gst_enable_cpu_opt = FALSE; break; diff --git a/gst/gst.h b/gst/gst.h index 8bfa201628..7892c2893f 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -27,40 +27,42 @@ #include #include -#include +#include #include +#include -#include -#include -#include +#include #include #include +#include +#include #include #include -#include +#include #include +#include +#include +#include +#include #include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include #include #include #include -#include /* API compatibility stuff */ #include diff --git a/gst/gstbin.c b/gst/gstbin.c index a012b4d709..bec55ec430 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -135,11 +135,11 @@ gst_bin_class_init (GstBinClass * klass) gst_bin_signals[ELEMENT_ADDED] = g_signal_new ("element_added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL, NULL, - gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); gst_bin_signals[ELEMENT_REMOVED] = g_signal_new ("element_removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL, NULL, - gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); gst_bin_signals[ITERATE] = g_signal_new ("iterate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstBinClass, iterate), diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c index 6df3cf8cb8..3a01d34dd2 100644 --- a/gst/gstbuffer.c +++ b/gst/gstbuffer.c @@ -167,6 +167,7 @@ gst_buffer_default_copy (GstBuffer *buffer) GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer); GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer); GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer); + GST_BUFFER_OFFSET_END (copy) = GST_BUFFER_OFFSET_END (buffer); GST_BUFFER_BUFFERPOOL (copy) = NULL; GST_BUFFER_POOL_PRIVATE (copy) = NULL; @@ -204,6 +205,7 @@ gst_buffer_new (void) GST_BUFFER_TIMESTAMP (newbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (newbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE; + GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_BUFFERPOOL (newbuf) = NULL; GST_BUFFER_POOL_PRIVATE (newbuf) = NULL; @@ -335,8 +337,9 @@ gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size) GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE; } - GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE; /* make sure nobody overwrites data as it would overwrite in the parent. * data in parent cannot be overwritten because we hold a ref */ GST_DATA_FLAG_SET (parent, GST_DATA_READONLY); @@ -453,13 +456,17 @@ gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len) /* if we completely merged the two buffers (appended), we can * calculate the duration too. Also make sure we's not messing with * invalid DURATIONS */ - if (offset == 0 && buf1->size + buf2->size == len && - GST_BUFFER_DURATION_IS_VALID (buf1) && - GST_BUFFER_DURATION_IS_VALID (buf2)) - { - /* add duration */ - GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf1) + - GST_BUFFER_DURATION (buf2); + if (offset == 0 && buf1->size + buf2->size == len) { + if (GST_BUFFER_DURATION_IS_VALID (buf1) && + GST_BUFFER_DURATION_IS_VALID (buf2)) { + /* add duration */ + GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf1) + + GST_BUFFER_DURATION (buf2); + } + if (GST_BUFFER_OFFSET_END_IS_VALID (buf2)) { + /* add offset_end */ + GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_END (buf2); + } } return newbuf; diff --git a/gst/gstbuffer.h b/gst/gstbuffer.h index 4191f7bdc7..ab19247bf1 100644 --- a/gst/gstbuffer.h +++ b/gst/gstbuffer.h @@ -63,6 +63,7 @@ extern GType _gst_buffer_pool_type; #define GST_BUFFER_DURATION(buf) (GST_BUFFER(buf)->duration) #define GST_BUFFER_FORMAT(buf) (GST_BUFFER(buf)->format) #define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset) +#define GST_BUFFER_OFFSET_END(buf) (GST_BUFFER(buf)->offset_end) #define GST_BUFFER_BUFFERPOOL(buf) (GST_BUFFER(buf)->pool) #define GST_BUFFER_POOL_PRIVATE(buf) (GST_BUFFER(buf)->pool_private) @@ -72,6 +73,7 @@ extern GType _gst_buffer_pool_type; #define GST_BUFFER_DURATION_IS_VALID(buffer) (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) #define GST_BUFFER_TIMESTAMP_IS_VALID(buffer) (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) #define GST_BUFFER_OFFSET_IS_VALID(buffer) (GST_BUFFER_OFFSET (buffer) != GST_BUFFER_OFFSET_NONE) +#define GST_BUFFER_OFFSET_END_IS_VALID(buffer) (GST_BUFFER_OFFSET_END (buffer) != GST_BUFFER_OFFSET_NONE) #define GST_BUFFER_MAXSIZE_IS_VALID(buffer) (GST_BUFFER_MAXSIZE (buffer) != GST_BUFFER_MAXSIZE_NONE) typedef enum { @@ -101,8 +103,11 @@ struct _GstBuffer { * for video frames, this could be the number of frames, * for audio data, this could be the number of audio samples, * for file data or compressed data, this could be the number of bytes + * offset_end is the last offset contained in the buffer. The format specifies + * the meaning of both of them exactly. */ guint64 offset; + guint64 offset_end; /* this is a pointer to the buffer pool (if any) */ GstBufferPool *pool; diff --git a/gst/gstcaps.c b/gst/gstcaps.c index 7d7b456003..69ea7a5f0f 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -86,10 +86,13 @@ gst_caps_to_string (GstCaps *caps) g_value_set_boxed (&value, caps->properties); props = g_strdup_value_contents (&value); - g_value_unset (&value); - g_string_append (result, ", "); - g_string_append (result, props); - g_free (props); + /* this happens with empty (but existing) caps->properties */ + if (props[0] != '\0') { + g_value_unset (&value); + g_string_append (result, ", "); + g_string_append (result, props); + g_free (props); + } } caps = caps->next; diff --git a/gst/gstelement.c b/gst/gstelement.c index 0b39579f7d..ed41f2c02b 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -39,6 +39,8 @@ enum { PAD_REMOVED, ERROR, EOS, + FOUND_TAG, + /* add more above */ LAST_SIGNAL }; @@ -65,6 +67,7 @@ static void gst_element_dispose (GObject *object); static GstElementStateReturn gst_element_change_state (GstElement *element); static void gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg); +static void gst_element_found_tag_func (GstElement* element, GstElement *source, GstTagList *tag_list); #ifndef GST_DISABLE_LOADSAVE static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent); @@ -127,11 +130,16 @@ gst_element_class_init (GstElementClass *klass) g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL, gst_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2, - G_TYPE_OBJECT, G_TYPE_STRING); + GST_TYPE_ELEMENT, G_TYPE_STRING); gst_element_signals[EOS] = g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL, + G_STRUCT_OFFSET (GstElementClass, eos), NULL, NULL, gst_marshal_VOID__VOID, G_TYPE_NONE, 0); + gst_element_signals[FOUND_TAG] = + g_signal_new ("found-tag", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstElementClass, found_tag), NULL, NULL, + gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2, + GST_TYPE_ELEMENT, G_TYPE_POINTER); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_real_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_real_get_property); @@ -145,6 +153,7 @@ gst_element_class_init (GstElementClass *klass) klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state); klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func); + klass->found_tag = GST_DEBUG_FUNCPTR (gst_element_found_tag_func); klass->padtemplates = NULL; klass->numpadtemplates = 0; @@ -931,7 +940,9 @@ gst_element_remove_pad (GstElement *element, GstPad *pad) /* FIXME: what if someone calls _remove_pad instead of _remove_ghost_pad? */ if (GST_IS_REAL_PAD (pad)) { - g_return_if_fail (GST_RPAD_PEER (pad) == NULL); + if (GST_RPAD_PEER (pad) != NULL) { + gst_pad_unlink (pad, GST_PAD (GST_RPAD_PEER (pad))); + } } /* remove it from the list */ @@ -1178,12 +1189,16 @@ void gst_element_class_add_pad_template (GstElementClass *klass, GstPadTemplate *templ) { + GstPadTemplate *templ_copy; + g_return_if_fail (klass != NULL); g_return_if_fail (GST_IS_ELEMENT_CLASS (klass)); g_return_if_fail (templ != NULL); g_return_if_fail (GST_IS_PAD_TEMPLATE (templ)); - klass->padtemplates = g_list_append (klass->padtemplates, templ); + templ_copy = g_memdup(templ, sizeof(GstPadTemplate)); + + klass->padtemplates = g_list_append (klass->padtemplates, templ_copy); klass->numpadtemplates++; } @@ -1204,11 +1219,63 @@ gst_element_class_set_details (GstElementClass *klass, GstElementDetails *detail __gst_element_details_set (&klass->details, details); } +/** + * gst_element_class_get_pad_template_list: + * @element: a #GstElementClass to get pad templates of. + * + * Retrieves a list of the pad templates associated with the element. + * + * Returns: the #GList of padtemplates. + */ +GList* +gst_element_class_get_pad_template_list (GstElementClass *element_class) +{ + g_return_val_if_fail (element_class != NULL, NULL); + g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); + + return element_class->padtemplates; +} + +/** + * gst_element_class_get_pad_template: + * @element: a #GstElementClass to get the pad template of. + * @name: the name of the #GstPadTemplate to get. + * + * Retrieves a padtemplate from this element with the + * given name. + * + * Returns: the #GstPadTemplate with the given name, or NULL if none was found. + * No unreferencing is necessary. + */ +GstPadTemplate* +gst_element_class_get_pad_template (GstElementClass *element_class, const gchar *name) +{ + GList *padlist; + + g_return_val_if_fail (element_class != NULL, NULL); + g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL); + g_return_val_if_fail (name != NULL, NULL); + + padlist = gst_element_class_get_pad_template_list (element_class); + + while (padlist) { + GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data; + + if (strcmp (padtempl->name_template, name) == 0) + return padtempl; + + padlist = g_list_next (padlist); + } + + return NULL; +} + /** * gst_element_get_pad_template_list: * @element: a #GstElement to get pad templates of. * * Retrieves a list of the pad templates associated with the element. + * (FIXME: Should be deprecated in favor of gst_element_class_get_pad_template_list). * * Returns: the #GList of padtemplates. */ @@ -1228,6 +1295,7 @@ gst_element_get_pad_template_list (GstElement *element) * * Retrieves a padtemplate from this element with the * given name. + * (FIXME: Should be deprecated in favor of gst_element_class_get_pad_template). * * Returns: the #GstPadTemplate with the given name, or NULL if none was found. * No unreferencing is necessary. @@ -1582,7 +1650,7 @@ gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname, srctempl = (GstPadTemplate*) srctempls->data; if (srctempl->presence == GST_PAD_REQUEST) { for (l=desttempls; l; l=l->next) { - desttempl = (GstPadTemplate*) desttempls->data; + desttempl = (GstPadTemplate*) l->data; if (desttempl->presence == GST_PAD_REQUEST && desttempl->direction != srctempl->direction) { if (gst_caps2_is_always_compatible (gst_pad_template_get_caps (srctempl), @@ -1598,7 +1666,9 @@ gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname, GST_DEBUG_PAD_NAME (destpad)); return TRUE; } - /* FIXME: we have extraneous request pads lying around */ + /* it failed, so we release the request pads */ + gst_element_release_request_pad (src, srcpad); + gst_element_release_request_pad (dest, destpad); } } } @@ -2011,7 +2081,10 @@ gst_element_query (GstElement *element, GstQueryType type, if (oclass->query) return oclass->query (element, type, format, value); else { - GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK); + GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SRC); + if (pad) + return gst_pad_query (pad, type, format, value); + pad = gst_element_get_random_pad (element, GST_PAD_SINK); if (pad) return gst_pad_query (GST_PAD_PEER (pad), type, format, value); } @@ -2863,6 +2936,71 @@ gst_element_set_loop_function (GstElement *element, } } } +static inline void +gst_element_emit_found_tag (GstElement* element, GstElement *source, GstTagList *tag_list) +{ + gst_object_ref (GST_OBJECT (element)); + g_signal_emit (element, gst_element_signals[FOUND_TAG], 0, source, tag_list); + gst_object_unref (GST_OBJECT (element)); +} +static void +gst_element_found_tag_func (GstElement* element, GstElement *source, GstTagList *tag_list) +{ + /* tell the parent */ + if (GST_OBJECT_PARENT (element)) { + GST_CAT_LOG_OBJECT (GST_CAT_EVENT, element, "forwarding tag event to %s", + GST_OBJECT_NAME (GST_OBJECT_PARENT (element))); + gst_element_emit_found_tag (GST_ELEMENT (GST_OBJECT_PARENT (element)), source, tag_list); + } +} +/** + * gst_element_found_tags: + * @element: the element that found the tags + * @tag_list: the found tags + * + * This function emits the found_tags signal. This is a recursive signal, so + * every parent will emit that signal, too, before this function returns. + * Only emit this signal, when you extracted these tags out of the data stream, + * not when you handle an event. + */ +void +gst_element_found_tags (GstElement *element, GstTagList *tag_list) +{ + gst_element_emit_found_tag (element, element, tag_list); +} +/** + * gst_element_found_tags_for_pad: + * @element: element that found the tag + * @pad: src pad the tags correspond to + * @timestamp: time the tags were found + * @list: the taglist + * + * This is a convenience routine for tag finding. Most of the time you only + * want to push the found tags down one pad, in that case this function is for + * you. It takes ownership of the taglist, emits the found-tag signal and pushes + * a tag event down the pad. + */ +void +gst_element_found_tags_for_pad (GstElement *element, GstPad *pad, GstClockTime timestamp, + GstTagList *list) +{ + GstEvent *tag_event; + + g_return_if_fail (GST_IS_ELEMENT (element)); + g_return_if_fail (GST_IS_REAL_PAD (pad)); + g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC); + g_return_if_fail (element == GST_PAD_PARENT (pad)); + g_return_if_fail (list != NULL); + + tag_event = gst_event_new_tag (list); + GST_EVENT_TIMESTAMP (tag_event) = timestamp; + gst_element_found_tags (element, gst_event_tag_get_list (tag_event)); + if (GST_PAD_IS_USABLE (pad)) { + gst_pad_push (pad, GST_DATA (tag_event)); + } else { + gst_data_unref (GST_DATA (tag_event)); + } +} static inline void gst_element_set_eos_recursive (GstElement *element) diff --git a/gst/gstelement.h b/gst/gstelement.h index aa44820952..6ad5c04c16 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -32,6 +32,7 @@ #include #include #include +#include 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); @@ -315,6 +315,8 @@ GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad); GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad, const GstCaps2 *filtercaps); +GstPadTemplate* gst_element_class_get_pad_template (GstElementClass *element_class, const gchar *name); +GList* gst_element_class_get_pad_template_list (GstElementClass *element_class); GstPadTemplate* gst_element_get_pad_template (GstElement *element, const gchar *name); GList* gst_element_get_pad_template_list (GstElement *element); GstPadTemplate* gst_element_get_compatible_pad_template (GstElement *element, GstPadTemplate *compattempl); @@ -348,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, ...); @@ -392,6 +398,12 @@ struct _GstElementFactory { GList * padtemplates; guint numpadtemplates; + /* URI interface stuff */ + guint uri_type; + gchar ** uri_protocols; + + GList * interfaces; /* interfaces this element implements */ + GST_OBJECT_PADDING }; @@ -417,6 +429,8 @@ G_CONST_RETURN gchar * gst_element_factory_get_version (GstElementFactory G_CONST_RETURN gchar * gst_element_factory_get_author (GstElementFactory *factory); guint gst_element_factory_get_num_padtemplates (GstElementFactory *factory); G_CONST_RETURN GList * gst_element_factory_get_padtemplates (GstElementFactory *factory); +guint gst_element_factory_get_uri_type (GstElementFactory *factory); +gchar ** gst_element_factory_get_uri_protocols (GstElementFactory *factory); GstElement* gst_element_factory_create (GstElementFactory *factory, const gchar *name); @@ -429,6 +443,8 @@ gboolean gst_element_factory_can_sink_caps (GstElementFactory *factory, void __gst_element_factory_add_pad_template (GstElementFactory *elementfactory, GstPadTemplate *templ); +void __gst_element_factory_add_interface (GstElementFactory *elementfactory, + const gchar *interfacename); G_END_DECLS diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c index 8a9ce839a6..529100e0ca 100644 --- a/gst/gstelementfactory.c +++ b/gst/gstelementfactory.c @@ -26,6 +26,7 @@ #include "gstelement.h" #include "gstregistrypool.h" #include "gstinfo.h" +#include "gsturi.h" GST_DEBUG_CATEGORY_STATIC (element_factory_debug); #define GST_CAT_DEFAULT element_factory_debug @@ -84,6 +85,11 @@ gst_element_factory_init (GstElementFactory *factory) { factory->padtemplates = NULL; factory->numpadtemplates = 0; + + factory->uri_type = GST_URI_UNKNOWN; + factory->uri_protocols = NULL; + + factory->interfaces = NULL; } /** * gst_element_factory_find: @@ -148,6 +154,15 @@ gst_element_factory_cleanup (GstElementFactory *factory) g_list_free (factory->padtemplates); factory->padtemplates = NULL; factory->numpadtemplates = 0; + factory->uri_type = GST_URI_UNKNOWN; + if (factory->uri_protocols) { + g_strfreev (factory->uri_protocols); + factory->uri_protocols = NULL; + } + + g_list_foreach (factory->interfaces, (GFunc) g_free, NULL); + g_list_free (factory->interfaces); + factory->interfaces = NULL; } /** * gst_element_register: @@ -165,6 +180,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,11 +207,34 @@ 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; - gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), rank); + /* special stuff for URI handling */ + if (g_type_is_a (type, GST_TYPE_URI_HANDLER)) { + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) + g_type_interface_peek (klass, GST_TYPE_URI_HANDLER); + if (!iface || !iface->get_type || !iface->get_protocols) + goto error; + factory->uri_type = iface->get_type (); + if (!GST_URI_TYPE_IS_VALID (factory->uri_type)) + goto error; + factory->uri_protocols = g_strdupv (iface->get_protocols ()); + if (!factory->uri_protocols) + goto error; + } + 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)); return TRUE; + +error: + gst_element_factory_cleanup (factory); + return FALSE; } /** * gst_element_factory_create: @@ -373,35 +413,84 @@ gst_element_factory_get_author (GstElementFactory *factory) return factory->details.author; } /** - * gst_element_factory_get_num_padtemplates: + * gst_element_factory_get_num_pad_templates: * @factory: a #GstElementFactory * - * Gets the number of padtemplates in this factory. + * Gets the number of pad_templates in this factory. * - * Returns: the number of padtemplates + * Returns: the number of pad_templates */ guint -gst_element_factory_get_num_padtemplates (GstElementFactory *factory) +gst_element_factory_get_num_pad_templates (GstElementFactory *factory) { g_return_val_if_fail (GST_IS_ELEMENT_FACTORY (factory), 0); return factory->numpadtemplates; } /** - * gst_element_factory_get_padtemplates: + * __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 * - * Gets the #Glist of padtemplates for this factory. + * Gets the #GList of padtemplates for this factory. * * Returns: the padtemplates */ G_CONST_RETURN GList * -gst_element_factory_get_padtemplates (GstElementFactory *factory) +gst_element_factory_get_pad_templates (GstElementFactory *factory) { g_return_val_if_fail (GST_IS_ELEMENT_FACTORY (factory), NULL); return factory->padtemplates; } +/** + * gst_element_factory_get_uri_type: + * @factory: a #GstElementFactory + * + * Gets the type of URIs the element supports or GST_URI_UNKNOWN if none. + * + * Returns: type of URIs this element supports + */ +guint +gst_element_factory_get_uri_type (GstElementFactory *factory) +{ + g_return_val_if_fail (GST_IS_ELEMENT_FACTORY (factory), GST_URI_UNKNOWN); + + return factory->uri_type; +} +/** + * gst_element_factory_get_uri_protocols: + * @factory: a #GstElementFactory + * + * Gets a NULL-terminated array of protocols this element supports or NULL, if + * no protocols are supported. You may not change the contents of the returned + * array as it is still ownt by the element factory. Use g_strdupv() if you want to. + * + * Returns: the supported protocols or NULL + */ +gchar ** +gst_element_factory_get_uri_protocols (GstElementFactory *factory) +{ + g_return_val_if_fail (GST_IS_ELEMENT_FACTORY (factory), NULL); + + return factory->uri_protocols; +} /** * gst_element_factory_can_src_caps : * @factory: factory to query diff --git a/gst/gstevent.c b/gst/gstevent.c index a213e8a7b6..ad63b78148 100644 --- a/gst/gstevent.c +++ b/gst/gstevent.c @@ -29,6 +29,8 @@ #include "gstmemchunk.h" #include "gstevent.h" #include "gstlog.h" +#include "gsttag.h" + #ifndef GST_DISABLE_TRACE /* #define GST_WITH_ALLOC_TRACE */ #include "gsttrace.h" @@ -70,6 +72,12 @@ _gst_event_copy (GstEvent *event) memcpy (copy, event, sizeof (GstEvent)); /* FIXME copy/ref additional fields */ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG: + copy->event_data.structure.structure = gst_structure_copy (event->event_data.structure.structure); + default: + break; + } return copy; } @@ -83,6 +91,8 @@ _gst_event_free (GstEvent* event) gst_object_unref (GST_EVENT_SRC (event)); } switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG: + gst_tag_list_free (event->event_data.structure.structure); default: break; } diff --git a/gst/gstevent.h b/gst/gstevent.h index 45b2eab024..a060dc9dca 100644 --- a/gst/gstevent.h +++ b/gst/gstevent.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include G_BEGIN_DECLS @@ -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; @@ -181,8 +182,8 @@ struct _GstEvent { gdouble value; } rate; struct { - GstCaps2 *caps; - } caps; + GstStructure *structure; + } structure; } event_data; GST_STRUCT_PADDING diff --git a/gst/gstindex.c b/gst/gstindex.c index 2fee10915f..23f6ce74a3 100644 --- a/gst/gstindex.c +++ b/gst/gstindex.c @@ -88,6 +88,20 @@ gst_index_resolver_get_type (void) return index_resolver_type; } +GType +gst_index_entry_get_type (void) +{ + static GType index_entry_type = 0; + + if (!index_entry_type) { + index_entry_type = g_boxed_type_register_static ("GstIndexEntry", + (GBoxedCopyFunc) gst_index_entry_copy, + (GBoxedFreeFunc) gst_index_entry_free); + } + return index_entry_type; +} + + GType gst_index_get_type (void) { static GType index_type = 0; @@ -381,6 +395,18 @@ gst_index_set_resolver (GstIndex *index, index->method = GST_INDEX_RESOLVER_CUSTOM; } +/** + * gst_index_entry_copy: + * @entry: the entry to copy + * + * Copies an entry and returns the result. + */ +GstIndexEntry * +gst_index_entry_copy (GstIndexEntry *entry) +{ + return g_memdup(entry, sizeof(*entry)); +} + /** * gst_index_entry_free: * @entry: the entry to free diff --git a/gst/gstindex.h b/gst/gstindex.h index aa05ace801..fa6231b50b 100644 --- a/gst/gstindex.h +++ b/gst/gstindex.h @@ -229,6 +229,7 @@ GstIndexEntry* gst_index_get_assoc_entry_full (GstIndex *index, gint id, gpointer user_data); /* working with index entries */ +GstIndexEntry * gst_index_entry_copy (GstIndexEntry *entry); void gst_index_entry_free (GstIndexEntry *entry); gboolean gst_index_entry_assoc_map (GstIndexEntry *entry, GstFormat format, gint64 *value); diff --git a/gst/gstinfo.c b/gst/gstinfo.c index 843a31fdb9..2fefe85059 100644 --- a/gst/gstinfo.c +++ b/gst/gstinfo.c @@ -258,11 +258,11 @@ void gst_debug_log (GstDebugCategory *category, GstDebugLevel level, va_list var_args; va_start (var_args, format); - gst_debug_logv (category, level, file, function, line, object, format, var_args); + gst_debug_log_valist (category, level, file, function, line, object, format, var_args); va_end (var_args); } /** - * gst_debug_logv: + * gst_debug_log_valist: * @category: category to log * @level: level of the message is in * @file: the file that emitted the message, usually the __FILE__ identifier @@ -274,9 +274,9 @@ void gst_debug_log (GstDebugCategory *category, GstDebugLevel level, * * Logs the given message using the currently registered debugging handlers. */ -void gst_debug_logv (GstDebugCategory *category, GstDebugLevel level, - const gchar *file, const gchar *function, gint line, - GObject *object, gchar *format, va_list args) +void gst_debug_log_valist (GstDebugCategory *category, GstDebugLevel level, + const gchar *file, const gchar *function, gint line, + GObject *object, gchar *format, va_list args) { gchar *message; LogFuncEntry *entry; diff --git a/gst/gstinfo.h b/gst/gstinfo.h index 17ab30544d..a1a91e8a99 100644 --- a/gst/gstinfo.h +++ b/gst/gstinfo.h @@ -162,7 +162,7 @@ void gst_debug_log (GstDebugCategory * category, GObject * object, gchar * format, ...) G_GNUC_PRINTF (7, 8) G_GNUC_NO_INSTRUMENT; -void gst_debug_logv (GstDebugCategory * category, +void gst_debug_log_valist (GstDebugCategory * category, GstDebugLevel level, const gchar * file, const gchar * function, @@ -388,7 +388,7 @@ const gchar* _gst_debug_nameof_funcptr (void * ptr); #ifdef __GNUC__ # pragma GCC poison gst_debug_log -# pragma GCC poison gst_debug_logv +# pragma GCC poison gst_debug_log_valist # pragma GCC poison gst_debug_log_default # pragma GCC poison _gst_debug_category_new #endif diff --git a/gst/gstinterface.c b/gst/gstinterface.c index d91d605d22..fe099e9a7d 100644 --- a/gst/gstinterface.c +++ b/gst/gstinterface.c @@ -54,6 +54,9 @@ gst_interface_get_type (void) gst_interface_type = g_type_register_static (G_TYPE_INTERFACE, "GstInterface", &gst_interface_info, 0); + + g_type_interface_add_prerequisite (gst_interface_type, + GST_TYPE_ELEMENT); } return gst_interface_type; diff --git a/gst/gstmarshal.list b/gst/gstmarshal.list index 0340c85f76..fabedd9c6f 100644 --- a/gst/gstmarshal.list +++ b/gst/gstmarshal.list @@ -3,6 +3,7 @@ VOID:BOOLEAN VOID:INT VOID:STRING VOID:POINTER +VOID:POINTER,OBJECT VOID:OBJECT VOID:OBJECT,PARAM VOID:OBJECT,POINTER diff --git a/gst/gstobject.c b/gst/gstobject.c index f45648c4d0..d6ea419175 100644 --- a/gst/gstobject.c +++ b/gst/gstobject.c @@ -139,6 +139,7 @@ gst_object_class_init (GstObjectClass *klass) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); #ifndef GST_DISABLE_LOADSAVE_REGISTRY + /* FIXME This should be the GType of xmlNodePtr instead of G_TYPE_POINTER */ gst_object_signals[OBJECT_SAVED] = g_signal_new ("object_saved", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, object_saved), NULL, NULL, diff --git a/gst/gstpad.c b/gst/gstpad.c index eb6fca0ceb..b5320bb5c4 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -173,17 +173,17 @@ gst_real_pad_class_init (GstRealPadClass *klass) g_signal_new ("caps_nego_failed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRealPadClass, caps_nego_failed), NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + GST_TYPE_CAPS2); gst_real_pad_signals[REAL_LINKED] = g_signal_new ("linked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRealPadClass, linked), NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + GST_TYPE_PAD); gst_real_pad_signals[REAL_UNLINKED] = g_signal_new ("unlinked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRealPadClass, unlinked), NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + GST_TYPE_PAD); /* gtk_object_add_arg_type ("GstRealPad::active", G_TYPE_BOOLEAN, */ /* GTK_ARG_READWRITE, REAL_ARG_ACTIVE); */ @@ -865,11 +865,11 @@ gst_pad_unlink (GstPad *srcpad, g_return_if_fail ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) && (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK)); - if (GST_RPAD_UNLINKFUNC (srcpad)) { - GST_RPAD_UNLINKFUNC (srcpad) (srcpad); + if (GST_RPAD_UNLINKFUNC (realsrc)) { + GST_RPAD_UNLINKFUNC (realsrc) (GST_PAD_CAST (realsrc)); } - if (GST_RPAD_UNLINKFUNC (sinkpad)) { - GST_RPAD_UNLINKFUNC (sinkpad) (sinkpad); + if (GST_RPAD_UNLINKFUNC (realsink)) { + GST_RPAD_UNLINKFUNC (realsink) (GST_PAD_CAST (realsink)); } /* get the schedulers before we unlink */ diff --git a/gst/gstplugin.c b/gst/gstplugin.c index a39987bc09..597cf34d11 100644 --- a/gst/gstplugin.c +++ b/gst/gstplugin.c @@ -63,6 +63,26 @@ static void gst_plugin_desc_copy (GstPluginDesc *dest, static GstPlugin * gst_plugin_register_func (GstPlugin *plugin, GModule *module, GstPluginDesc *desc); + +static GstPlugin * +gst_plugin_copy (GstPlugin *plugin) +{ + return g_memdup(plugin, sizeof(*plugin)); +} + +GType +gst_plugin_get_type (void) +{ + static GType plugin_type; + + if (plugin_type == 0) { + plugin_type = g_boxed_type_register_static ("GstPlugin", + (GBoxedCopyFunc) gst_plugin_copy, g_free); + } + + return plugin_type; +} + GQuark gst_plugin_error_quark (void) { @@ -248,6 +268,16 @@ gst_plugin_load_file (const gchar *filename, GError **error) } GST_LOG ("Plugin %p for file \"%s\" prepared, calling entry function...", plugin, filename); + if (g_module_symbol (module, "plugin_init", &ptr)) { + g_print ("plugin %p from file \"%s\" exports a symbol named plugin_init\n", + plugin, plugin->filename); + g_set_error (error, + GST_PLUGIN_ERROR, + GST_PLUGIN_ERROR_NAME_MISMATCH, + "plugin \"%s\" exports a symbol named plugin_init", + desc->name); + } + if (gst_plugin_register_func (plugin, module, desc)) { GST_INFO ("plugin \"%s\" loaded", plugin->filename); return plugin; diff --git a/gst/gstplugin.h b/gst/gstplugin.h index 8c189af46e..d976783964 100644 --- a/gst/gstplugin.h +++ b/gst/gstplugin.h @@ -120,10 +120,13 @@ _gst_plugin_static_init__ ##init (void) \ #define GST_LICENSE_UNKNOWN "unknown" + /* function for filters */ typedef gboolean (*GstPluginFilter) (GstPlugin *plugin, gpointer user_data); +#define GST_TYPE_PLUGIN (gst_plugin_get_type()) +GType gst_plugin_get_type (void); void _gst_plugin_initialize (void); void _gst_plugin_register_static (GstPluginDesc *desc); diff --git a/gst/gstpluginfeature.c b/gst/gstpluginfeature.c index 5c8afed0a2..788222f67f 100644 --- a/gst/gstpluginfeature.c +++ b/gst/gstpluginfeature.c @@ -147,7 +147,7 @@ gst_plugin_feature_type_name_filter (GstPluginFeature *feature, * the most appropriate feature. */ void -gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank) +gst_plugin_feature_set_rank (GstPluginFeature *feature, guint rank) { g_return_if_fail (feature != NULL); g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature)); @@ -155,7 +155,7 @@ gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank) feature->rank = rank; } /** - * gst_plugin_feature_set_rank: + * gst_plugin_feature_set_name: * @feature: a feature * @name: the name to set * @@ -175,4 +175,34 @@ gst_plugin_feature_set_name (GstPluginFeature *feature, const gchar *name) feature->name = g_strdup (name); } } +/** + * gst_plugin_feature_get rank: + * @feature: a feature + * + * Gets the rank of a plugin feature. + * + * Returns: The rank of the feature + */ +guint +gst_plugin_feature_get_rank (GstPluginFeature *feature) +{ + g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), GST_RANK_NONE); + + return feature->rank; +} +/** + * gst_plugin_feature_set_name: + * @feature: a feature + * + * Gets the name of a pluginfeature. + * + * Returns: the name + */ +G_CONST_RETURN gchar * +gst_plugin_feature_get_name (GstPluginFeature *feature) +{ + g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), NULL); + + return feature->name; +} diff --git a/gst/gstpluginfeature.h b/gst/gstpluginfeature.h index a543f669af..760214ccc3 100644 --- a/gst/gstpluginfeature.h +++ b/gst/gstpluginfeature.h @@ -44,10 +44,10 @@ typedef struct _GstPluginFeatureClass GstPluginFeatureClass; struct _GstPluginFeature { GObject object; + /*< private >*/ gchar *name; - gint rank; + guint rank; - /* --- private --- */ gpointer manager; GST_OBJECT_PADDING @@ -79,8 +79,10 @@ void gst_plugin_feature_unload_thyself (GstPluginFeature *feature); gboolean gst_plugin_feature_type_name_filter (GstPluginFeature *feature, GstTypeNameData *data); -void gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank); +void gst_plugin_feature_set_rank (GstPluginFeature *feature, guint rank); void gst_plugin_feature_set_name (GstPluginFeature *feature, const gchar *name); +guint gst_plugin_feature_get_rank (GstPluginFeature *feature); +G_CONST_RETURN gchar *gst_plugin_feature_get_name (GstPluginFeature *feature); G_END_DECLS diff --git a/gst/gstprops.c b/gst/gstprops.c index 49f922c9d9..ee6549ebc4 100644 --- a/gst/gstprops.c +++ b/gst/gstprops.c @@ -2391,7 +2391,16 @@ G_STMT_START { \ GST_PROPS_FLAG_UNSET ((props), GST_PROPS_FIXED); \ props->properties = g_list_prepend ((props)->properties, toadd); \ } G_STMT_END +static gint +compare_props_entry (gconstpointer one, gconstpointer two) +{ + GstPropsEntry *a = (GstPropsEntry *) one; + GstPropsEntry *b = (GstPropsEntry *) two; + if (a->propid > b->propid) return 1; + if (a->propid < b->propid) return -1; + return 0; +} /** * gst_props_intersect: * @props1: a property @@ -2417,6 +2426,9 @@ gst_props_intersect (GstProps *props1, GstProps *props2) intersection = gst_props_empty_new (); + props1->properties = g_list_sort (props1->properties, compare_props_entry); + props2->properties = g_list_sort (props2->properties, compare_props_entry); + props1list = props1->properties; props2list = props2->properties; @@ -2445,6 +2457,8 @@ gst_props_intersect (GstProps *props1, GstProps *props2) entry2 = (GstPropsEntry *)props2list->data; } + if (entry1->propid < entry2->propid) + continue; /* at this point we are talking about the same property */ iprops = gst_props_entry_intersect (entry1, entry2); if (!iprops) { diff --git a/gst/gstqueue.c b/gst/gstqueue.c index 68dcc93b80..a9ed47a3a1 100644 --- a/gst/gstqueue.c +++ b/gst/gstqueue.c @@ -223,6 +223,7 @@ gst_queue_init (GTypeInstance *instance, gpointer g_class) gst_pad_set_bufferpool_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_get_bufferpool)); gst_pad_set_link_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_link)); gst_pad_set_getcaps_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps)); + gst_pad_set_active (queue->sinkpad, TRUE); queue->srcpad = gst_pad_new ("src", GST_PAD_SRC); gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get)); @@ -230,6 +231,7 @@ gst_queue_init (GTypeInstance *instance, gpointer g_class) gst_pad_set_link_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_link)); gst_pad_set_getcaps_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps)); gst_pad_set_event_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_handle_src_event)); + gst_pad_set_active (queue->srcpad, TRUE); queue->leaky = GST_QUEUE_NO_LEAK; queue->queue = NULL; @@ -695,6 +697,10 @@ gst_queue_change_state (GstElement *element) } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); + /* this is an ugly hack to make sure our pads are always active. Reason for this is that + * pad activation for the queue element depends on 2 schedulers (ugh) */ + gst_pad_set_active (queue->sinkpad, TRUE); + gst_pad_set_active (queue->srcpad, TRUE); error: g_mutex_unlock (queue->qlock); diff --git a/gst/gststructure.c b/gst/gststructure.c index 2fd56fb83b..763ead55fc 100644 --- a/gst/gststructure.c +++ b/gst/gststructure.c @@ -585,7 +585,7 @@ gst_structure_remove_all_fields(GstStructure *structure) g_return_if_fail(structure != NULL); - for (i = structure->fields->len - 1; i >= 0; i++ ) { + for (i = structure->fields->len - 1; i >= 0; i-- ) { field = GST_STRUCTURE_FIELD(structure, i); if (G_IS_VALUE (&field->value)) { diff --git a/gst/gststructure.h b/gst/gststructure.h index 9208beb0ad..15967c8c5b 100644 --- a/gst/gststructure.h +++ b/gst/gststructure.h @@ -73,7 +73,8 @@ void gst_structure_set_value(GstStructure *structure, const gchar *field, void gst_structure_set(GstStructure *structure, const gchar *field, ...); void gst_structure_set_valist(GstStructure *structure, const gchar *field, va_list varargs); -G_CONST_RETURN GValue *gst_structure_get_value(const GstStructure *structure, const gchar *field); +G_CONST_RETURN 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(const GstStructure *structure, diff --git a/gst/gsttag.c b/gst/gsttag.c new file mode 100644 index 0000000000..558939b039 --- /dev/null +++ b/gst/gsttag.c @@ -0,0 +1,831 @@ +/* GStreamer + * Copyright (C) 2003 Benjamin Otte + * + * 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 +#include + +#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_set_string_take_ownership (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_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_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_TYPE_LIST) { + GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag)); + /* must be there or lists aren't allowed */ + g_assert (info->merge_func); + info->merge_func (dest, src); + } else { + g_value_init (dest, G_VALUE_TYPE (src)); + g_value_copy (src, dest); + } + return TRUE; +} + +/***** evil macros to get all the gst_tag_list_get_*() functions right *****/ + +#define TAG_MERGE_FUNCS(name,type) \ +gboolean \ +gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag, \ + type *value) \ +{ \ + GValue v = { 0, }; \ + \ + g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \ + g_return_val_if_fail (tag != NULL, FALSE); \ + g_return_val_if_fail (value != NULL, FALSE); \ + \ + if (!gst_tag_list_copy_value (&v, list, tag)) \ + return FALSE; \ + *value = COPY_FUNC (g_value_get_ ## name (&v)); \ + g_value_unset (&v); \ + return TRUE; \ +} \ + \ +gboolean \ +gst_tag_list_get_ ## name ## _index (const GstTagList *list, const gchar *tag, \ + guint index, type *value) \ +{ \ + const GValue *v; \ + \ + g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \ + g_return_val_if_fail (tag != NULL, FALSE); \ + g_return_val_if_fail (value != NULL, FALSE); \ + \ + if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL) \ + return FALSE; \ + *value = COPY_FUNC (g_value_get_ ## name (v)); \ + return TRUE; \ +} + +#define COPY_FUNC /**/ +TAG_MERGE_FUNCS (char, gchar) +TAG_MERGE_FUNCS (uchar, guchar) +TAG_MERGE_FUNCS (boolean, gboolean) +TAG_MERGE_FUNCS (int, gint) +TAG_MERGE_FUNCS (uint, guint) +TAG_MERGE_FUNCS (long, glong) +TAG_MERGE_FUNCS (ulong, gulong) +TAG_MERGE_FUNCS (int64, gint64) +TAG_MERGE_FUNCS (uint64, guint64) +TAG_MERGE_FUNCS (float, gfloat) +TAG_MERGE_FUNCS (double, gdouble) +#undef COPY_FUNC + +#define COPY_FUNC g_strdup +TAG_MERGE_FUNCS (string, gchar *) + + + + diff --git a/gst/gsttaglist.c b/gst/gsttaglist.c new file mode 100644 index 0000000000..558939b039 --- /dev/null +++ b/gst/gsttaglist.c @@ -0,0 +1,831 @@ +/* GStreamer + * Copyright (C) 2003 Benjamin Otte + * + * 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 +#include + +#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_set_string_take_ownership (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_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_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_TYPE_LIST) { + GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag)); + /* must be there or lists aren't allowed */ + g_assert (info->merge_func); + info->merge_func (dest, src); + } else { + g_value_init (dest, G_VALUE_TYPE (src)); + g_value_copy (src, dest); + } + return TRUE; +} + +/***** evil macros to get all the gst_tag_list_get_*() functions right *****/ + +#define TAG_MERGE_FUNCS(name,type) \ +gboolean \ +gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag, \ + type *value) \ +{ \ + GValue v = { 0, }; \ + \ + g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \ + g_return_val_if_fail (tag != NULL, FALSE); \ + g_return_val_if_fail (value != NULL, FALSE); \ + \ + if (!gst_tag_list_copy_value (&v, list, tag)) \ + return FALSE; \ + *value = COPY_FUNC (g_value_get_ ## name (&v)); \ + g_value_unset (&v); \ + return TRUE; \ +} \ + \ +gboolean \ +gst_tag_list_get_ ## name ## _index (const GstTagList *list, const gchar *tag, \ + guint index, type *value) \ +{ \ + const GValue *v; \ + \ + g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); \ + g_return_val_if_fail (tag != NULL, FALSE); \ + g_return_val_if_fail (value != NULL, FALSE); \ + \ + if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL) \ + return FALSE; \ + *value = COPY_FUNC (g_value_get_ ## name (v)); \ + return TRUE; \ +} + +#define COPY_FUNC /**/ +TAG_MERGE_FUNCS (char, gchar) +TAG_MERGE_FUNCS (uchar, guchar) +TAG_MERGE_FUNCS (boolean, gboolean) +TAG_MERGE_FUNCS (int, gint) +TAG_MERGE_FUNCS (uint, guint) +TAG_MERGE_FUNCS (long, glong) +TAG_MERGE_FUNCS (ulong, gulong) +TAG_MERGE_FUNCS (int64, gint64) +TAG_MERGE_FUNCS (uint64, guint64) +TAG_MERGE_FUNCS (float, gfloat) +TAG_MERGE_FUNCS (double, gdouble) +#undef COPY_FUNC + +#define COPY_FUNC g_strdup +TAG_MERGE_FUNCS (string, gchar *) + + + + diff --git a/gst/gsturi.c b/gst/gsturi.c index e198998fc9..17f60d034d 100644 --- a/gst/gsturi.c +++ b/gst/gsturi.c @@ -20,17 +20,22 @@ * Boston, MA 02111-1307, USA. */ -#include "gst_private.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "gsturi.h" -#include "gstregistrypool.h" #include "gstinfo.h" +#include "gstregistrypool.h" +#include "gstmarshal.h" -static void gst_uri_handler_class_init (GstURIHandlerClass *klass); -static void gst_uri_handler_init (GstURIHandler *factory); +#include +#include -static GstPluginFeatureClass *parent_class = NULL; -/* static guint gst_uri_handler_signals[LAST_SIGNAL] = { 0 }; */ +GST_DEBUG_CATEGORY_STATIC (gst_uri_handler_debug); +#define GST_CAT_DEFAULT gst_uri_handler_debug + +static void gst_uri_handler_base_init (gpointer g_class); GType gst_uri_handler_get_type (void) @@ -39,222 +44,346 @@ gst_uri_handler_get_type (void) if (!urihandler_type) { static const GTypeInfo urihandler_info = { - sizeof (GstURIHandlerClass), + sizeof (GstURIHandlerInterface), + gst_uri_handler_base_init, NULL, NULL, - (GClassInitFunc) gst_uri_handler_class_init, NULL, NULL, - sizeof(GstURIHandler), 0, - (GInstanceInitFunc) gst_uri_handler_init, + 0, + NULL, NULL }; - urihandler_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, - "GstURIHandler", &urihandler_info, 0); + urihandler_type = g_type_register_static (G_TYPE_INTERFACE, + "GstURIHandler", &urihandler_info, 0); + + GST_DEBUG_CATEGORY_INIT (gst_uri_handler_debug, "GST_URI", GST_DEBUG_BOLD, "handling of URIs"); } return urihandler_type; } +static void +gst_uri_handler_base_init (gpointer g_class) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + g_signal_new ("new_uri", GST_TYPE_URI_HANDLER, G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstURIHandlerInterface, new_uri), NULL, NULL, + gst_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); + initialized = TRUE; + } +} + static void -gst_uri_handler_class_init (GstURIHandlerClass *klass) +gst_uri_protocol_check_internal (const gchar *uri, gchar **endptr) { - GObjectClass *gobject_class; - GstObjectClass *gstobject_class; - GstPluginFeatureClass *gstpluginfeature_class; + gchar *check = (gchar *) uri; + + g_assert (uri != NULL); + g_assert (endptr != NULL); - gobject_class = (GObjectClass*)klass; - gstobject_class = (GstObjectClass*)klass; - gstpluginfeature_class = (GstPluginFeatureClass*) klass; + if (isalpha (*check)) { + check++; + while (isalnum (*check)) check++; + } - parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE); + *endptr = check; } - -static void -gst_uri_handler_init (GstURIHandler *factory) -{ -} - /** - * gst_uri_handler_new: - * @name: the name of the feature - * @uri: the uri to register - * @longdesc: a description for this uri - * @element: an element that can handle the uri - * @property: the property on the element to set the uri + * gst_uri_protocol_is_valid: + * @protocol: string to check * - * Creates a plugin feature to register an element that can - * handle the given uri on the given property. + * Tests if the given string is a valid protocol identifier. Protocols + * must consist of alphanumeric characters and not start with a number. * - * Returns: the new urihandler - */ -GstURIHandler* -gst_uri_handler_new (const gchar *name, - const gchar *uri, const gchar *longdesc, - const gchar *element, gchar *property) -{ - GstURIHandler *factory; - - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (uri != NULL, NULL); - g_return_val_if_fail (element != NULL, NULL); - g_return_val_if_fail (property != NULL, NULL); - - factory = gst_uri_handler_find (name); - - if (!factory) { - factory = GST_URI_HANDLER (g_object_new (GST_TYPE_URI_HANDLER, NULL)); - } - - GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name); - factory->uri = g_strdup (uri); - factory->longdesc = g_strdup (longdesc); - factory->element = g_strdup (element); - factory->property = g_strdup (property); - - return factory; -} - -/** - * gst_uri_handler_find: - * @name: the name of the urihandler to find - * - * Return the URIHandler with the given name. - * - * Returns: a GstURIHandler with the given name; - */ -GstURIHandler* -gst_uri_handler_find (const gchar *name) -{ - GstPluginFeature *feature; - - g_return_val_if_fail (name != NULL, NULL); - - feature = gst_registry_pool_find_feature (name, GST_TYPE_URI_HANDLER); - if (feature) - return GST_URI_HANDLER (feature); - - return NULL; -} - -/* - * this is a straight copy from glib 2.2 - * remove this function when glib 2.2 is sufficiently widespread and - * then change to using the regular g_str_has_prefix - */ -static gboolean -g_str_has_prefix_glib22 (gchar *haystack, gchar *needle) -{ - if (haystack == NULL && needle == NULL) { - return TRUE; - } - if (haystack == NULL || needle == NULL) { - return FALSE; - } - if (strncmp (haystack, needle, strlen (needle)) == 0) { - return TRUE; - } - return FALSE; -} - -/** - * gst_uri_handler_uri_filter: - * @feature: the feature to inspect - * @uri: the name of the uri to match - * - * Check if the given pluginfeature is a uri hanler and that - * it can handle the given uri. - * - * Returns: TRUE if the feature can handle the uri. + * Returns: TRUE if the string is a valid protocol identifier */ gboolean -gst_uri_handler_uri_filter (GstPluginFeature *feature, const gchar *uri) +gst_uri_protocol_is_valid (const gchar *protocol) { - if (G_OBJECT_TYPE (feature) == GST_TYPE_URI_HANDLER) { - GstURIHandler *handler = GST_URI_HANDLER (feature); + gchar *endptr; - if (g_str_has_prefix_glib22 ((gchar *) uri, handler->uri)) { + g_return_val_if_fail (protocol != NULL, FALSE); + + gst_uri_protocol_check_internal (protocol, &endptr); + + return *endptr == '\0' && endptr != protocol; +} +/** + * gst_uri_is_valid: + * @protocol: string to check + * + * Tests if the given string is a valid URI identifier. URIs start with a valid + * protocol followed by "://" and a string identifying the location. + * + * Returns: TRUE if the string is a valid URI + */ +gboolean +gst_uri_is_valid (const gchar *uri) +{ + gchar *endptr; + + g_return_val_if_fail (uri != NULL, FALSE); + + gst_uri_protocol_check_internal (uri, &endptr); + + return (*endptr == ':' && + *(endptr + 1) == '/' && + *(endptr + 2) == '/'); +} +/** + * gst_uri_get_protocol: + * @uri: URI to get protocol from + * + * Extracts the protocol out of a given valid URI. The returned string must be + * freed using g_free(). + * + * Returns: The protocol for this URI. + */ +gchar * +gst_uri_get_protocol (const gchar *uri) +{ + gchar *colon; + + g_return_val_if_fail (uri != NULL, NULL); + g_return_val_if_fail (gst_uri_is_valid (uri), NULL); + + colon = strstr (uri, "://"); + + return g_strndup (uri, colon - uri); +} +/** + * gst_uri_get_location: + * @uri: URI to get the location from + * + * Extracts the location out of a given valid URI. So the protocol and "://" + * are stripped from the URI. The returned string must be freed using + * g_free(). + * + * Returns: The location for this URI. + */ +gchar * +gst_uri_get_location (const gchar *uri) +{ + gchar *colon; + + g_return_val_if_fail (uri != NULL, NULL); + g_return_val_if_fail (gst_uri_is_valid (uri), NULL); + + colon = strstr (uri, "://"); + + return g_strdup (colon + 3); +} +/** + * gst_uri_construct: + * @protocol: protocol for URI + * @location: location for URI + * + * Constructs a URI for a given valid protocol and location. + * + * Returns: a new string for this URI + */ +gchar * +gst_uri_construct (const gchar *protocol, const gchar *location) +{ + g_return_val_if_fail (gst_uri_protocol_is_valid (protocol), NULL); + g_return_val_if_fail (location != NULL, NULL); + + return g_strdup_printf ("%s://%s", protocol, location); +} +typedef struct{ + GstURIType type; + gchar * protocol; +} SearchEntry; +static gboolean +search_by_entry (GstPluginFeature *feature, gpointer search_entry) +{ + gchar **protocols; + GstElementFactory *factory; + SearchEntry *entry = (SearchEntry *) search_entry; + + if (!GST_IS_ELEMENT_FACTORY (feature)) + return FALSE; + factory = GST_ELEMENT_FACTORY (feature); + + if (gst_element_factory_get_uri_type (factory) != entry->type) + return FALSE; + + protocols = gst_element_factory_get_uri_protocols (factory); + /* must be set when uri type is valid */ + g_assert (protocols); + while (*protocols != NULL) { + if (strcmp (*protocols, entry->protocol) == 0) return TRUE; - } + protocols++; } return FALSE; } - -/** - * gst_uri_handler_find_by_uri: - * @uri: the uri to find a handler for - * - * Find a URIHandler for the given uri. - * - * Returns: a GstURIHandler that can handle the given uri. - */ -GstURIHandler* -gst_uri_handler_find_by_uri (const gchar *uri) +static gint +sort_by_rank (gconstpointer a, gconstpointer b) { - GList *walk; - GstURIHandler *result = NULL; - - g_return_val_if_fail (uri != NULL, NULL); + GstPluginFeature *first = GST_PLUGIN_FEATURE (a); + GstPluginFeature *second = GST_PLUGIN_FEATURE (b); - walk = gst_registry_pool_feature_filter ( - (GstPluginFeatureFilter) gst_uri_handler_uri_filter, TRUE, (gpointer) uri); + return gst_plugin_feature_get_rank (second) - gst_plugin_feature_get_rank (first); +} +/** + * gst_element_make_from_uri: + * @type: wether to create a source or a sink + * @uri: URI to create element for + * @elementname: optional name of created element + * + * Creates an element for handling the given URI. + * + * Returns: a new element or NULL if none could be created + */ +GstElement * +gst_element_make_from_uri (const GstURIType type, const gchar *uri, const gchar *elementname) +{ + GList *possibilities, *walk; + SearchEntry entry; + GstElement *ret = NULL; - if (walk) { - result = GST_URI_HANDLER (walk->data); + g_return_val_if_fail (GST_URI_TYPE_IS_VALID (type), NULL); + g_return_val_if_fail (gst_uri_is_valid (uri), NULL); + + entry.type = type; + entry.protocol = gst_uri_get_protocol (uri); + possibilities = gst_registry_pool_feature_filter (search_by_entry, FALSE, &entry); + g_free (entry.protocol); + + if (!possibilities) { + GST_DEBUG ("No %s for URI '%s'", type == GST_URI_SINK ? "sink" : "source", uri); + return NULL; } - g_list_free (walk); - - return result; -} - -/** - * gst_uri_handler_create: - * @handler: the uri handler to use - * @name: the name of the element - * - * Create an element with the given name from the given handler. - * - * Returns: a new element associated with the handler. - */ -GstElement* -gst_uri_handler_create (GstURIHandler *handler, const gchar *name) -{ - GstElement *element = NULL; - - g_return_val_if_fail (handler != NULL, NULL); - - element = gst_element_factory_make (handler->element, name); - - return element; -} - -/** - * gst_uri_handler_make_by_uri: - * @uri: the uri - * @name: the name of the element - * - * Create an element with the given name that can handle the given - * uri. This function will also use set the uri on the element. - * - * Returns: a new element that can handle the uri. - */ -GstElement* -gst_uri_handler_make_by_uri (const gchar *uri, const gchar *name) -{ - GstElement *element = NULL; - GstURIHandler *handler; - - g_return_val_if_fail (uri != NULL, NULL); - - handler = gst_uri_handler_find_by_uri (uri); - if (handler) { - element = gst_uri_handler_create (handler, name); - if (element) { - g_object_set (G_OBJECT (element), handler->property, uri, NULL); + + possibilities = g_list_sort (possibilities, sort_by_rank); + walk = possibilities; + while (walk) { + if ((ret = gst_element_factory_create (GST_ELEMENT_FACTORY (walk->data), + elementname)) != NULL) { + GstURIHandler *handler = GST_URI_HANDLER (ret); + if (gst_uri_handler_set_uri (handler, uri)) + break; + g_object_unref (ret); + ret = NULL; } } - return element; + g_list_free (possibilities); + + GST_LOG_OBJECT (ret, "created %s for URL '%s'", type == GST_URI_SINK ? "sink" : "source", uri); + return ret; } +/** + * gst_uri_handler_get_uri_type: + * @handler: Handler to query type of + * + * Gets the type of a URI handler + * + * Returns: the type of the URI handler + */ +guint +gst_uri_handler_get_uri_type (GstURIHandler *handler) +{ + GstURIHandlerInterface *iface; + guint ret; + + g_return_val_if_fail (GST_IS_URI_HANDLER (handler), GST_URI_UNKNOWN); + iface = GST_URI_HANDLER_GET_INTERFACE (handler); + g_return_val_if_fail (iface != NULL, GST_URI_UNKNOWN); + g_return_val_if_fail (iface->get_type != NULL, GST_URI_UNKNOWN); + ret = iface->get_type (); + g_return_val_if_fail (GST_URI_TYPE_IS_VALID (ret), GST_URI_UNKNOWN); + return ret; +} +/** + * gst_uri_handler_get_protocols: + * @handler: Handler to get protocols for + * + * Gets the list of supported protocols for this handler. This list may not be + * modified. + * + * Returns: the supported protocols + */ +gchar ** +gst_uri_handler_get_protocols (GstURIHandler *handler) +{ + GstURIHandlerInterface *iface; + gchar **ret; + + g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL); + iface = GST_URI_HANDLER_GET_INTERFACE (handler); + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (iface->get_protocols != NULL, NULL); + ret = iface->get_protocols (); + g_return_val_if_fail (ret != NULL, NULL); + + return ret; +} +/** + * gst_uri_handler_get_uri: + * @handler: handler to query URI of + * + * Gets the currently handled URI of the handler or NULL, if none is set. + * + * Returns: the URI + */ +G_CONST_RETURN gchar * +gst_uri_handler_get_uri (GstURIHandler *handler) +{ + GstURIHandlerInterface *iface; + const gchar *ret; + + g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL); + + iface = GST_URI_HANDLER_GET_INTERFACE (handler); + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (iface->get_uri != NULL, NULL); + ret = iface->get_uri (handler); + if (ret != NULL) + g_return_val_if_fail (gst_uri_is_valid (ret), NULL); + + return ret; +} +/** + * gst_uri_handler_set_uri: + * @handler: handler to set URI of + * @uri: URI to set + * + * Tries to set the URI of the given handler and returns TRUE if it succeeded. + * + * Returns: TRUE, if the URI was set successfully + */ +gboolean +gst_uri_handler_set_uri (GstURIHandler *handler, const gchar *uri) +{ + GstURIHandlerInterface *iface; + + g_return_val_if_fail (GST_IS_URI_HANDLER (handler), FALSE); + g_return_val_if_fail (gst_uri_is_valid (uri), FALSE); + + iface = GST_URI_HANDLER_GET_INTERFACE (handler); + g_return_val_if_fail (iface != NULL, FALSE); + g_return_val_if_fail (iface->set_uri != NULL, FALSE); + return iface->set_uri (handler, uri); +} +/** + * gst_uri_handler_new_uri: + * @handler: handler with a new URI + * @uri: new URI or NULL if it was unset + * + * Emits the new-uri event for a given handler, when that handler has a new URI. + * This function should only be called by URI handlers themselves. + */ +void +gst_uri_handler_new_uri (GstURIHandler *handler, const gchar *uri) +{ + g_return_if_fail (GST_IS_URI_HANDLER (handler)); + + g_signal_emit_by_name (handler, "new-uri", uri); +} diff --git a/gst/gsturi.h b/gst/gsturi.h index 2662b47b0c..0d0a1093f6 100644 --- a/gst/gsturi.h +++ b/gst/gsturi.h @@ -30,50 +30,76 @@ G_BEGIN_DECLS +typedef enum { + GST_URI_UNKNOWN, + GST_URI_SINK, + GST_URI_SRC +} GstURIType; + +#define GST_URI_TYPE_IS_VALID(type) ((type) == GST_URI_SRC || (type) == GST_URI_SINK) + /* uri handler functions */ #define GST_TYPE_URI_HANDLER (gst_uri_handler_get_type ()) #define GST_URI_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_URI_HANDLER, GstURIHandler)) #define GST_IS_URI_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_URI_HANDLER)) -#define GST_URI_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_URI_HANDLER, GstURIHandlerClass)) -#define GST_IS_URI_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_URI_HANDLER)) -#define GST_URI_HANDLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_URI_HANDLER, GstURIHandlerClass)) +#define GST_URI_HANDLER_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GST_TYPE_URI_HANDLER, GstURIHandlerInterface)) +#define GST_URI_HANDLER_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GST_TYPE_URI_HANDLER, GstURIHandler)) typedef struct _GstURIHandler GstURIHandler; -typedef struct _GstURIHandlerClass GstURIHandlerClass; +typedef struct _GstURIHandlerInterface GstURIHandlerInterface; -struct _GstURIHandler { - GstPluginFeature feature; +struct _GstURIHandlerInterface { + GTypeInterface parent; - /* --- public ---- */ - gchar *uri; /* The uri that is described */ - gchar *longdesc; /* description of the uri */ - gchar *element; /* The element that can handle this uri */ - gchar *property; /* The property on the element to set the uri */ + /* signals */ + void (* new_uri) (GstURIHandler * handler, + const gchar * uri); + /* idea for the future ? + gboolean (* require_password) (GstURIHandler * handler, + gchar ** username, + gchar ** password); + */ - GST_OBJECT_PADDING -}; + /* vtable */ -struct _GstURIHandlerClass { - GstPluginFeatureClass parent; + /* querying capabilities */ + GstURIType (* get_type) (void); + gchar ** (* get_protocols) (void); + + /* using the interface */ + G_CONST_RETURN gchar *(* get_uri) (GstURIHandler * handler); + gboolean (* set_uri) (GstURIHandler * handler, + const gchar * uri); + + /* we might want to add functions here to query features, someone with gnome-vfs knowledge go ahead */ GST_CLASS_PADDING }; -GType gst_uri_handler_get_type (void); +/* general URI functions */ -GstURIHandler* gst_uri_handler_new (const gchar *name, - const gchar *uri, const gchar *longdesc, - const gchar *element, gchar *property); +gboolean gst_uri_protocol_is_valid (const gchar * protocol); +gboolean gst_uri_is_valid (const gchar * uri); +gchar * gst_uri_get_protocol (const gchar * uri); +gchar * gst_uri_get_location (const gchar * uri); +gchar * gst_uri_construct (const gchar * protocol, + const gchar * location); -GstURIHandler* gst_uri_handler_find (const gchar *name); -GstURIHandler* gst_uri_handler_find_by_uri (const gchar *uri); +GstElement * gst_element_make_from_uri (const GstURIType type, + const gchar * uri, + const gchar * elementname); -GstElement* gst_uri_handler_create (GstURIHandler *handler, const gchar *name); -GstElement* gst_uri_handler_make_by_uri (const gchar *uri, const gchar *name); +/* accessing the interface */ +GType gst_uri_handler_get_type (void); -/* filters */ -gboolean gst_uri_handler_uri_filter (GstPluginFeature *feature, const gchar *uri); +guint gst_uri_handler_get_uri_type (GstURIHandler * handler); +gchar ** gst_uri_handler_get_protocols (GstURIHandler * handler); +G_CONST_RETURN gchar * gst_uri_handler_get_uri (GstURIHandler * handler); +gboolean gst_uri_handler_set_uri (GstURIHandler * handler, + const gchar * uri); +void gst_uri_handler_new_uri (GstURIHandler * handler, + const gchar * uri); G_END_DECLS -#endif /* __GST_URI_H */ +#endif /* __GST_URI_H__ */ diff --git a/gst/gstvalue.c b/gst/gstvalue.c index c3b7a20c5d..78bcba6b27 100644 --- a/gst/gstvalue.c +++ b/gst/gstvalue.c @@ -205,6 +205,53 @@ gst_value_union_lists (GValue *dest, const GValue *value1, const GValue *value2) return TRUE; } +/** + * 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_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_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 diff --git a/gst/gstvalue.h b/gst/gstvalue.h index ead3f9bfc7..a6cc2a4d8c 100644 --- a/gst/gstvalue.h +++ b/gst/gstvalue.h @@ -21,6 +21,7 @@ #define __GST_VALUE_H__ #include +#include G_BEGIN_DECLS @@ -76,6 +77,12 @@ double gst_value_get_double_range_max (const GValue *value); const GstCaps2 *gst_value_get_caps (const GValue *value); void gst_value_set_caps (GValue *calue, const GstCaps2 *caps); +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); diff --git a/gst/gstxml.c b/gst/gstxml.c index 4d413a5841..833008ae86 100644 --- a/gst/gstxml.c +++ b/gst/gstxml.c @@ -71,6 +71,7 @@ gst_xml_class_init (GstXMLClass *klass) parent_class = g_type_class_ref (GST_TYPE_OBJECT); + /* FIXME G_TYPE_POINTER should be GType of xmlNodePtr */ gst_xml_signals[OBJECT_LOADED] = g_signal_new ("object_loaded", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstXMLClass, object_loaded), NULL, NULL, diff --git a/gst/parse/grammar.y b/gst/parse/grammar.y index 068cd142ad..2dfe5a8b4c 100644 --- a/gst/parse/grammar.y +++ b/gst/parse/grammar.y @@ -7,8 +7,10 @@ #include "../gst_private.h" +#include "../gstconfig.h" #include "../gstparse.h" #include "../gstinfo.h" +#include "../gsturi.h" #include "types.h" #define YYERROR_VERBOSE 1 @@ -97,7 +99,7 @@ typedef struct { } \ }G_STMT_END #define ERROR(type, ...) SET_ERROR (((graph_t *) graph)->error, (type), __VA_ARGS__ ) -#ifdef GST_DEBUG_ENABLED +#ifndef GST_DISABLE_GST_DEBUG # define YYDEBUG 1 /* bison 1.35 calls this macro with side effects, we need to make sure the side effects work - crappy bison @@ -122,7 +124,7 @@ typedef struct { } \ }G_STMT_END #define ERROR(type, args...) SET_ERROR (((graph_t *) graph)->error, (type), ## args ) -#ifdef GST_DEBUG_ENABLED +#ifndef GST_DISABLE_GST_DEBUG # define YYDEBUG 1 /* bison 1.35 calls this macro with side effects, we need to make sure the side effects work - crappy bison @@ -147,7 +149,7 @@ typedef struct { } \ }G_STMT_END #define ERROR(type, ...) SET_ERROR (((graph_t *) graph)->error, (type), "error while parsing") -#ifdef GST_DEBUG_ENABLED +#ifndef GST_DISABLE_GST_DEBUG # define YYDEBUG 1 #endif @@ -210,23 +212,6 @@ typedef struct { MAKE_LINK (link, NULL, _src, pads, NULL, NULL, NULL); \ }G_STMT_END -static inline void gst_parse_unescape (gchar *str) -{ - gchar *walk; - - g_return_if_fail (str != NULL); - - walk = str; - - while (*walk) { - if (*walk == '\\') - walk++; - *str = *walk; - str++; - walk++; - } - *str = '\0'; -} static void gst_parse_element_set (gchar *value, GstElement *element, graph_t *graph) { @@ -532,6 +517,7 @@ static int yyerror (const char *s); graph_t *g; } +%token PARSE_URL %token IDENTIFIER %left REF PADREF BINREF %token ASSIGNMENT @@ -542,7 +528,7 @@ static int yyerror (const char *s); %type reference %type linkpart link %type

linklist -%type element +%type element %type

padlist pads assignments %left '{' '}' '(' ')' @@ -566,12 +552,11 @@ element: IDENTIFIER { $$ = gst_element_factory_make ($1, NULL); $$ = $1; } ; - assignments: /* NOP */ { $$ = NULL; } | assignments ASSIGNMENT { $$ = g_slist_prepend ($1, $2); } ; -bin: '{' assignments chain '}' { GST_BIN_MAKE ($$, "thread", $3, $2); } - | '(' assignments chain ')' { GST_BIN_MAKE ($$, "bin", $3, $2); } +bin: '{' assignments chain '}' { GST_BIN_MAKE ($$, "thread", $3, $2); } + | '(' assignments chain ')' { GST_BIN_MAKE ($$, "bin", $3, $2); } | BINREF assignments chain ')' { GST_BIN_MAKE ($$, $1, $3, $2); gst_parse_strfree ($1); } @@ -668,21 +653,6 @@ chain: element { $$ = gst_parse_chain_new (); gst_parse_chain_free ($2); $$ = $1; } - | link chain { if ($2->front) { - if (!$2->front->src_name) { - ERROR (GST_PARSE_ERROR_LINK, "link without source element"); - gst_parse_free_link ($2->front); - } else { - ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $2->front); - } - } - if (!$1->sink_name) { - $1->sink = $2->first; - } - $2->front = $1; - $$ = $2; - } - | chain linklist { GSList *walk; if ($1->back) { $2 = g_slist_prepend ($2, $1->back); @@ -714,8 +684,60 @@ chain: element { $$ = gst_parse_chain_new (); $$ = $1; } | chain error { $$ = $1; } + | link chain { if ($2->front) { + if (!$2->front->src_name) { + ERROR (GST_PARSE_ERROR_LINK, "link without source element"); + gst_parse_free_link ($2->front); + } else { + ((graph_t *) graph)->links = g_slist_prepend (((graph_t *) graph)->links, $2->front); + } + } + if (!$1->sink_name) { + $1->sink = $2->first; + } + $2->front = $1; + $$ = $2; + } + | PARSE_URL chain { $$ = $2; + if ($$->front) { + GstElement *element = + gst_element_make_from_uri (GST_URI_SRC, $1, NULL); + if (!element) { + ERROR (GST_PARSE_ERROR_NO_SUCH_ELEMENT, + "No source element for URI \"%s\"", $1); + } else { + $$->front->src = element; + ((graph_t *) graph)->links = g_slist_prepend ( + ((graph_t *) graph)->links, $$->front); + $$->front = NULL; + $$->elements = g_slist_prepend ($$->elements, element); + } + } else { + ERROR (GST_PARSE_ERROR_LINK, + "No element to link URI \"%s\" to", $1); + } + g_free ($1); + } + | link PARSE_URL { GstElement *element = + gst_element_make_from_uri (GST_URI_SINK, $2, NULL); + if (!element) { + ERROR (GST_PARSE_ERROR_NO_SUCH_ELEMENT, + "No sink element for URI \"%s\"", $2); + YYERROR; + } else if ($1->sink_name || $1->sink_pads) { + ERROR (GST_PARSE_ERROR_LINK, + "could not link sink element for URI \"%s\"", $2); + YYERROR; + } else { + $$ = gst_parse_chain_new (); + $$->first = $$->last = element; + $$->front = $1; + $$->front->sink = element; + $$->elements = g_slist_prepend (NULL, element); + } + g_free ($2); + } ; - graph: /* NOP */ { ERROR (GST_PARSE_ERROR_EMPTY, "Empty pipeline not allowed"); $$ = (graph_t *) graph; } @@ -783,7 +805,7 @@ _gst_parse_launch (const gchar *str, GError **error) dstr = g_strdup (str); _gst_parse_yy_scan_string (dstr); -#ifdef GST_DEBUG_ENABLED +#ifndef GST_DISABLE_GST_DEBUG yydebug = 1; #endif diff --git a/gst/parse/parse.l b/gst/parse/parse.l index 021d13b738..95fb0c5ff8 100644 --- a/gst/parse/parse.l +++ b/gst/parse/parse.l @@ -7,6 +7,7 @@ #include "types.h" #include "../gstinfo.h" +#include "../gsturi.h" #include "grammar.tab.h" #ifdef G_HAVE_ISO_VARARGS @@ -29,6 +30,9 @@ _string {_char}+|("\""([^\"]|"\\\"")*"\"")|("'"([^']|"\\\"")*"'") _comma [[:space:]]*","[[:space:]]* _assign [[:space:]]*"="[[:space:]]* +_protocol [[:alpha:]][[:alnum:]+-\.]* +_url {_protocol}"://"{_string}|["."{_identifier}]?"/"{_string} + /* we must do this here, because nearly everything matches a {_string} */ _assignment {_identifier}{_assign}{_string} @@ -106,6 +110,17 @@ _link ("!"[[:space:]]*{_caps}([[:space:]]*";"[[:space:]]*{_caps})*[[:space:]]*"! BEGIN (INITIAL); return LINK; } +{_url} { + PRINT ("URL: %s\n", yytext); + if (gst_uri_is_valid (yytext)) { + lvalp->s = g_strdup (yytext); + } else { + lvalp->s = gst_uri_construct ("file", yytext); + } + gst_parse_unescape (lvalp->s); + BEGIN (INITIAL); + return PARSE_URL; +} {_operator} { PRINT ("OPERATOR: [%s]\n", yytext); return *yytext; } diff --git a/gst/parse/types.h b/gst/parse/types.h index 6496c48ab9..6b5f92233a 100644 --- a/gst/parse/types.h +++ b/gst/parse/types.h @@ -66,4 +66,23 @@ void __gst_parse_chain_free (chain_t *data); # define gst_parse_chain_free g_free #endif /* __GST_PARSE_TRACE */ +static inline void +gst_parse_unescape (gchar *str) +{ + gchar *walk; + + g_return_if_fail (str != NULL); + + walk = str; + + while (*walk) { + if (*walk == '\\') + walk++; + *str = *walk; + str++; + walk++; + } + *str = '\0'; +} + #endif /* __GST_PARSE_TYPES_H__ */ diff --git a/gst/registries/gstxmlregistry.c b/gst/registries/gstxmlregistry.c index 9271311b78..5c80f25f05 100644 --- a/gst/registries/gstxmlregistry.c +++ b/gst/registries/gstxmlregistry.c @@ -679,6 +679,26 @@ gst_xml_registry_parse_plugin (GMarkupParseContext *context, const gchar *tag, c return TRUE; } +static void +add_to_char_array (gchar ***array, gchar *value) +{ + gchar **new; + gchar **old = *array; + gint i = 0; + + /* expensive, but cycles are cheap... */ + if (old) + while (old[i]) i++; + new = g_new0 (gchar *, i + 2); + new[i] = value; + while (i > 0) { + i--; + new[i] = old[i]; + } + g_free (old); + *array = new; +} + static gboolean gst_xml_registry_parse_element_factory (GMarkupParseContext *context, const gchar *tag, const gchar *text, gsize text_len, GstXMLRegistry *registry, GError **error) @@ -686,8 +706,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); @@ -708,12 +729,26 @@ 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, "uri_type")) { + if (strncasecmp (text, "sink", 4) == 0) { + factory->uri_type = GST_URI_SINK; + } else if (strncasecmp (text, "source", 5) == 0) { + factory->uri_type = GST_URI_SRC; + } + } else if (!strcmp (tag, "uri_protocol")) { + add_to_char_array (&factory->uri_protocols, g_strndup (text, text_len)); } - + else if (!strcmp(tag, "interface")) { + gchar *tmp = g_strndup (text, text_len); + __gst_element_factory_add_interface (factory, tmp); + g_free (tmp); + } + return TRUE; } @@ -739,21 +774,7 @@ gst_xml_registry_parse_type_find_factory (GMarkupParseContext *context, const gc factory->caps = g_strndup (text, text_len); }*/ else if (!strcmp(tag, "extension")) { - gchar **new; - gchar **old = factory->extensions; - gint i = 0; - - /* expensive, but cycles are cheap... */ - if (old) - while (old[i]) i++; - new = g_new0 (gchar *, i + 2); - new[i] = g_strndup (text, text_len); - while (i > 0) { - i--; - new[i] = old[i]; - } - g_free (old); - factory->extensions = new; + add_to_char_array (&factory->extensions, g_strndup (text, text_len)); } return TRUE; @@ -806,30 +827,6 @@ gst_xml_registry_parse_index_factory (GMarkupParseContext *context, const gchar return TRUE; } -static gboolean -gst_xml_registry_parse_uri_handler (GMarkupParseContext *context, const gchar *tag, const gchar *text, - gsize text_len, GstXMLRegistry *registry, GError **error) -{ - GstURIHandler *handler = GST_URI_HANDLER (registry->current_feature); - - if (!strcmp (tag, "name")) { - registry->current_feature->name = g_strndup (text, text_len); - } - else if (!strcmp (tag, "uri")) { - handler->uri = g_strndup (text, text_len); - } - else if (!strcmp (tag, "longdesc")) { - handler->longdesc = g_strndup (text, text_len); - } - else if (!strcmp (tag, "element")) { - handler->element = g_strndup (text, text_len); - } - else if (!strcmp (tag, "property")) { - handler->property = g_strndup (text, text_len); - } - return TRUE; -} - static gboolean gst_xml_registry_parse_padtemplate (GMarkupParseContext *context, const gchar *tag, const gchar *text, gsize text_len, GstXMLRegistry *registry, GError **error) @@ -948,9 +945,6 @@ gst_xml_registry_start_element (GMarkupParseContext *context, else if (GST_IS_INDEX_FACTORY (feature)) { xmlregistry->parser = gst_xml_registry_parse_index_factory; } - else if (GST_IS_URI_HANDLER (feature)) { - xmlregistry->parser = gst_xml_registry_parse_uri_handler; - } else { g_warning ("unkown feature type"); } @@ -1490,23 +1484,41 @@ 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, "\n"); gst_xml_registry_save_pad_template (xmlregistry, template); CLASS (xmlregistry)->save_func (xmlregistry, "\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); + } + + if (GST_URI_TYPE_IS_VALID (factory->uri_type)) { + gchar **protocol; + + PUT_ESCAPED ("uri_type", factory->uri_type == GST_URI_SINK ? "sink" : "source"); + g_assert (factory->uri_protocols); + protocol = factory->uri_protocols; + while (*protocol) { + PUT_ESCAPED ("uri_protocol", *protocol); + protocol++; + } } } else if (GST_IS_TYPE_FIND_FACTORY (feature)) { @@ -1535,18 +1547,9 @@ gst_xml_registry_save_feature (GstXMLRegistry *xmlregistry, GstPluginFeature *fe else if (GST_IS_INDEX_FACTORY (feature)) { PUT_ESCAPED ("longdesc", GST_INDEX_FACTORY (feature)->longdesc); } - else if (GST_IS_URI_HANDLER (feature)) { - GstURIHandler *handler = GST_URI_HANDLER (feature); - - PUT_ESCAPED ("uri", handler->uri); - PUT_ESCAPED ("longdesc", handler->longdesc); - PUT_ESCAPED ("element", handler->element); - PUT_ESCAPED ("property", handler->property); - } return TRUE; } - static gboolean gst_xml_registry_save_plugin (GstXMLRegistry *xmlregistry, GstPlugin *plugin) { diff --git a/gst/schedulers/gstbasicscheduler.c b/gst/schedulers/gstbasicscheduler.c index 06c80392f1..fba3fb8401 100644 --- a/gst/schedulers/gstbasicscheduler.c +++ b/gst/schedulers/gstbasicscheduler.c @@ -314,6 +314,7 @@ gst_basic_scheduler_loopfunc_wrapper (int argc, char **argv) static int gst_basic_scheduler_chain_wrapper (int argc, char **argv) { + GSList *already_iterated = NULL; GstElement *element = GST_ELEMENT_CAST (argv); G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); @@ -323,39 +324,47 @@ gst_basic_scheduler_chain_wrapper (int argc, char **argv) gst_object_ref (GST_OBJECT (element)); do { - GList *pads = element->pads; + GList *pads; + do { + pads = element->pads; - while (pads) { - GstPad *pad = GST_PAD (pads->data); - GstRealPad *realpad; + while (pads) { + GstPad *pad = GST_PAD (pads->data); + GstRealPad *realpad; - pads = g_list_next (pads); - if (!GST_IS_REAL_PAD (pad)) - continue; + if (!GST_IS_REAL_PAD (pad)) + continue; - realpad = GST_REAL_PAD_CAST (pad); + realpad = GST_REAL_PAD (pad); - if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SINK && - GST_PAD_IS_LINKED (realpad)) { - GstData *data; + if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SINK && + GST_PAD_IS_LINKED (realpad) && + g_slist_find (already_iterated, pad) == NULL) { + GstData *data; - GST_CAT_DEBUG (debug_dataflow, "pulling data from %s:%s", name, + GST_CAT_DEBUG (debug_dataflow, "pulling data from %s:%s", name, GST_PAD_NAME (pad)); - data = gst_pad_pull (pad); - if (data) { - if (GST_IS_EVENT (data) && !GST_ELEMENT_IS_EVENT_AWARE (element)) { - gst_pad_send_event (pad, GST_EVENT (data)); - } - else { - GST_CAT_DEBUG (debug_dataflow, "calling chain function of %s:%s %p", - name, GST_PAD_NAME (pad), data); - GST_RPAD_CHAINFUNC (realpad) (pad, data); - GST_CAT_DEBUG (debug_dataflow, - "calling chain function of element %s done", name); + data = gst_pad_pull (pad); + if (data) { + if (GST_IS_EVENT (data) && !GST_ELEMENT_IS_EVENT_AWARE (element)) { + gst_pad_send_event (pad, GST_EVENT (data)); + } + else { + GST_CAT_DEBUG (debug_dataflow, "calling chain function of %s:%s %p", + name, GST_PAD_NAME (pad), data); + GST_RPAD_CHAINFUNC (realpad) (pad, data); + GST_CAT_DEBUG (debug_dataflow, + "calling chain function of element %s done", name); + } } + already_iterated = g_slist_prepend (already_iterated, pad); + break; } + pads = g_list_next (pads); } - } + } while (pads != NULL); + g_slist_free (already_iterated); + already_iterated = NULL; } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); diff --git a/gstreamer.spec.in b/gstreamer.spec.in index d1b9416918..0f5320bc32 100644 --- a/gstreamer.spec.in +++ b/gstreamer.spec.in @@ -147,11 +147,11 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la %{_libdir}/gstreamer-%{majorminor}/libgstbasicgthreadscheduler*.so %{_libdir}/gstreamer-%{majorminor}/libgstoptgthreadscheduler*.so %{_libdir}/gstreamer-%{majorminor}/libgstelements*.so* -%{_libdir}/gstreamer-%{majorminor}/libgsttypes*.so* %{_libdir}/gstreamer-%{majorminor}/libgststaticautoplug*.so* %{_libdir}/gstreamer-%{majorminor}/libgstgetbits*.so* %{_libdir}/gstreamer-%{majorminor}/libgstspider*.so* -%{_libdir}/gstreamer-%{majorminor}/libgstindexers.so +%{_libdir}/gstreamer-%{majorminor}/libgstindexers.so* +%{_libdir}/gstreamer-%{majorminor}/libgstbytestream.so %{_datadir}/locale/* %files tools @@ -184,6 +184,7 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la %{_includedir}/%{name}-%{majorminor}/gst/control/*.h %dir %{_includedir}/%{name}-%{majorminor}/gst/getbits %{_includedir}/%{name}-%{majorminor}/gst/getbits/getbits.h +%{_includedir}/%{name}-%{majorminor}/gst/bytestream/bytestream.h # %{_libdir}/libgstreamer.a %{_libdir}/libgstreamer-%{majorminor}.so %{_libdir}/libgstcontrol-%{majorminor}.so @@ -195,19 +196,21 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la # we list all of the files we really need to trap incomplete doc builds # then we catch the rest with *, you can safely ignore the errors from this ## gstreamer API -# %dir %{_datadir}/gtk-doc/html/%{name}-%{majorminor} # %{_datadir}/gtk-doc/html/%{name}-%{majorminor}/%{name}-%{majorminor}.devhelp # %{_datadir}/gtk-doc/html/%{name}-%{majorminor}/element-types.html # %{_datadir}/gtk-doc/html/%{name}-%{majorminor}/gstreamer.html -# %{_datadir}/gtk-doc/html/%{name}-%{majorminor}/index.sgml +%{_datadir}/gtk-doc/html/%{name}-%{majorminor}/* ## gstreamer-libs API # %dir %{_datadir}/gtk-doc/html/%{name}-libs-%{majorminor} -# %{_datadir}/gtk-doc/html/%{name}-libs-%{majorminor}/index.sgml +%{_datadir}/gtk-doc/html/%{name}-libs-%{majorminor}/* ## this catches all of the rest of the docs we might have forgotten # %{_datadir}/gtk-doc/html/* %changelog +* Sun Nov 09 2003 Christian Schaller +- Fix spec to handle new bytestream library + * Sun Aug 17 2003 Christian Schaller - Remove docs build from RPM as the build is broken - Fix stuff since more files are versioned now diff --git a/libs/gst/Makefile.am b/libs/gst/Makefile.am index 3bd8a76a39..fa04c8f2b6 100644 --- a/libs/gst/Makefile.am +++ b/libs/gst/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = control getbits bytestream +SUBDIRS = bytestream control getbits -DIST_SUBDIRS = control getbits bytestream +DIST_SUBDIRS = bytestream control getbits diff --git a/libs/gst/control/dparammanager.c b/libs/gst/control/dparammanager.c index 207fb61655..463e4cc07e 100644 --- a/libs/gst/control/dparammanager.c +++ b/libs/gst/control/dparammanager.c @@ -465,7 +465,6 @@ gst_dpman_register_mode (GstDParamManagerClass *klass, mode->teardownfunc = teardownfunc; g_hash_table_insert(klass->modes, modename, mode); - GST_DEBUG ("mode '%s' registered", modename); } /** diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index a294dc11cf..3aa752edad 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -1,10 +1,10 @@ ### all of the standard pc files we need to generate -pcfiles = \ - gstreamer-@GST_MAJORMINOR@.pc \ +pcfiles = \ + gstreamer-@GST_MAJORMINOR@.pc \ gstreamer-control-@GST_MAJORMINOR@.pc -pcfiles_uninstalled = \ - gstreamer-@GST_MAJORMINOR@-uninstalled.pc \ +pcfiles_uninstalled = \ + gstreamer-@GST_MAJORMINOR@-uninstalled.pc \ gstreamer-control-@GST_MAJORMINOR@-uninstalled.pc all-local: $(pcfiles) $(pcfiles_uninstalled) @@ -18,10 +18,10 @@ $(pcfiles_uninstalled): %-@GST_MAJORMINOR@-uninstalled.pc: %-uninstalled.pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) -EXTRA_DIST = \ - gstreamer.pc.in \ - gstreamer-uninstalled.pc.in \ - gstreamer-control.pc.in \ +EXTRA_DIST = \ + gstreamer.pc.in \ + gstreamer-uninstalled.pc.in \ + gstreamer-control.pc.in \ gstreamer-control-uninstalled.pc.in CLEANFILES = $(pcfiles) $(pcfiles_uninstalled) diff --git a/plugins/elements/gstbufferstore.c b/plugins/elements/gstbufferstore.c index f399ab4d61..8d38740da5 100644 --- a/plugins/elements/gstbufferstore.c +++ b/plugins/elements/gstbufferstore.c @@ -119,7 +119,7 @@ gst_buffer_store_class_init (gpointer g_class, gpointer class_data) gst_buffer_store_signals[BUFFER_ADDED] = g_signal_new ("buffer-added", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstBufferStoreClass, buffer_added), continue_accu, NULL, - gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); + gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_BUFFER); store_class->cleared = gst_buffer_store_cleared_func; store_class->buffer_added = gst_buffer_store_add_buffer_func; diff --git a/plugins/elements/gstfakesink.c b/plugins/elements/gstfakesink.c index 815aadc51e..4f8a6a008c 100644 --- a/plugins/elements/gstfakesink.c +++ b/plugins/elements/gstfakesink.c @@ -175,8 +175,8 @@ gst_fakesink_class_init (GstFakeSinkClass *klass) gst_fakesink_signals[SIGNAL_HANDOFF] = g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstFakeSinkClass, handoff), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2, + GST_TYPE_BUFFER, GST_TYPE_PAD); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property); diff --git a/plugins/elements/gstfakesrc.c b/plugins/elements/gstfakesrc.c index 75080a2563..95a0a69b3b 100644 --- a/plugins/elements/gstfakesrc.c +++ b/plugins/elements/gstfakesrc.c @@ -271,8 +271,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass) gst_fakesrc_signals[SIGNAL_HANDOFF] = g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2, + GST_TYPE_BUFFER, GST_TYPE_PAD); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property); diff --git a/plugins/elements/gstfilesink.c b/plugins/elements/gstfilesink.c index 5c4c81c84f..fef5d7e8f7 100644 --- a/plugins/elements/gstfilesink.c +++ b/plugins/elements/gstfilesink.c @@ -69,6 +69,7 @@ GST_PAD_FORMATS_FUNCTION (gst_filesink_get_formats, static void gst_filesink_base_init (gpointer g_class); static void gst_filesink_class_init (GstFileSinkClass *klass); static void gst_filesink_init (GstFileSink *filesink); +static void gst_filesink_dispose (GObject *object); static void gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); @@ -83,6 +84,8 @@ static gboolean gst_filesink_pad_query (GstPad *pad, GstQueryType type, GstFormat *format, gint64 *value); static void gst_filesink_chain (GstPad *pad,GstData *_data); +static void gst_filesink_uri_handler_init (gpointer g_iface, gpointer iface_data); + static GstElementStateReturn gst_filesink_change_state (GstElement *element); static GstElementClass *parent_class = NULL; @@ -105,7 +108,14 @@ gst_filesink_get_type (void) 0, (GInstanceInitFunc)gst_filesink_init, }; + static const GInterfaceInfo urihandler_info = { + gst_filesink_uri_handler_init, + NULL, + NULL + }; filesink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFileSink", &filesink_info, 0); + + g_type_add_interface_static (filesink_type, GST_TYPE_URI_HANDLER, &urihandler_info); GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0, "filesink element"); } @@ -138,8 +148,8 @@ gst_filesink_class_init (GstFileSinkClass *klass) gobject_class->set_property = gst_filesink_set_property; gobject_class->get_property = gst_filesink_get_property; + gobject_class->dispose = gst_filesink_dispose; } - static void gst_filesink_init (GstFileSink *filesink) { @@ -158,7 +168,38 @@ gst_filesink_init (GstFileSink *filesink) filesink->filename = NULL; filesink->file = NULL; } +static void +gst_filesink_dispose (GObject *object) +{ + GstFileSink *sink = GST_FILESINK (object); + G_OBJECT_CLASS (parent_class)->dispose (object); + + g_free (sink->uri); + sink->uri = NULL; + g_free (sink->filename); + sink->filename = NULL; +} +static gboolean +gst_filesink_set_location (GstFileSink *sink, const gchar *location) +{ + /* the element must be stopped or paused in order to do this */ + if (GST_STATE (sink) > GST_STATE_PAUSED) + return FALSE; + if (GST_STATE (sink) == GST_STATE_PAUSED && + GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN)) + return FALSE; + + g_free (sink->filename); + g_free (sink->uri); + sink->filename = g_strdup (location); + sink->uri = gst_uri_construct ("file", location); + + if (GST_STATE (sink) == GST_STATE_PAUSED) + gst_filesink_open_file (sink); + + return TRUE; +} static void gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { @@ -169,16 +210,7 @@ gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value, switch (prop_id) { case ARG_LOCATION: - /* the element must be stopped or paused in order to do this */ - g_return_if_fail (GST_STATE (sink) <= GST_STATE_PAUSED); - if (GST_STATE (sink) == GST_STATE_PAUSED) - g_return_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN)); - - if (sink->filename) - g_free (sink->filename); - sink->filename = g_strdup (g_value_get_string (value)); - if (GST_STATE (sink) == GST_STATE_PAUSED) - gst_filesink_open_file (sink); + gst_filesink_set_location (sink, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -435,3 +467,54 @@ gst_filesink_change_state (GstElement *element) return GST_STATE_SUCCESS; } + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static guint +gst_filesink_uri_get_type (void) +{ + return GST_URI_SINK; +} +static gchar ** +gst_filesink_uri_get_protocols(void) +{ + static gchar *protocols[] = {"file", NULL}; + return protocols; +} +static const gchar * +gst_filesink_uri_get_uri (GstURIHandler *handler) +{ + GstFileSink *sink = GST_FILESINK (handler); + + return sink->uri; +} +static gboolean +gst_filesink_uri_set_uri (GstURIHandler *handler, const gchar *uri) +{ + gchar *protocol, *location; + gboolean ret; + GstFileSink *sink = GST_FILESINK (handler); + + protocol = gst_uri_get_protocol (uri); + if (strcmp (protocol, "file") != 0) { + g_free (protocol); + return FALSE; + } + g_free (protocol); + location = gst_uri_get_location (uri); + ret = gst_filesink_set_location (sink, location); + g_free (location); + + return ret; +} + +static void +gst_filesink_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_filesink_uri_get_type; + iface->get_protocols = gst_filesink_uri_get_protocols; + iface->get_uri = gst_filesink_uri_get_uri; + iface->set_uri = gst_filesink_uri_set_uri; +} diff --git a/plugins/elements/gstfilesink.h b/plugins/elements/gstfilesink.h index b72551bfe0..bd85a1d012 100644 --- a/plugins/elements/gstfilesink.h +++ b/plugins/elements/gstfilesink.h @@ -53,6 +53,7 @@ struct _GstFileSink { GstElement element; gchar *filename; + gchar *uri; FILE *file; guint64 data_written; diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index f243d97c27..f2789ec59f 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -128,6 +128,7 @@ static void gst_filesrc_set_property (GObject *object, guint prop_id, static void gst_filesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static gboolean gst_filesrc_check_filesize (GstFileSrc *src); static GstData * gst_filesrc_get (GstPad *pad); static gboolean gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event); static gboolean gst_filesrc_srcpad_query (GstPad *pad, GstQueryType type, @@ -135,6 +136,8 @@ static gboolean gst_filesrc_srcpad_query (GstPad *pad, GstQueryType type, static GstElementStateReturn gst_filesrc_change_state (GstElement *element); +static void gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data); + static GstElementClass *parent_class = NULL; /*static guint gst_filesrc_signals[LAST_SIGNAL] = { 0 };*/ @@ -156,8 +159,15 @@ gst_filesrc_get_type(void) 0, (GInstanceInitFunc)gst_filesrc_init, }; + static const GInterfaceInfo urihandler_info = { + gst_filesrc_uri_handler_init, + NULL, + NULL + }; filesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFileSrc", &filesrc_info, 0); - + + g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER, &urihandler_info); + GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element"); } return filesrc_type; @@ -262,8 +272,32 @@ gst_filesrc_dispose (GObject *object) g_mutex_free (src->map_regions_lock); if (src->filename) g_free (src->filename); + if (src->uri) + g_free (src->uri); } +static gboolean +gst_filesrc_set_location (GstFileSrc *src, const gchar *location) +{ + /* the element must be stopped in order to do this */ + if (GST_STATE (src) == GST_STATE_PLAYING) + return FALSE; + + if (src->filename) g_free (src->filename); + if (src->uri) g_free (src->uri); + /* clear the filename if we get a NULL (is that possible?) */ + if (location == NULL) { + src->filename = NULL; + src->uri = NULL; + } else { + src->filename = g_strdup (location); + src->uri = gst_uri_construct ("file", src->filename); + } + g_object_notify (G_OBJECT (src), "location"); + gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri); + + return TRUE; +} static void gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -277,19 +311,7 @@ gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, G switch (prop_id) { case ARG_LOCATION: - /* the element must be stopped in order to do this */ - g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING); - - if (src->filename) g_free (src->filename); - /* clear the filename if we get a NULL (is that possible?) */ - if (g_value_get_string (value) == NULL) { - gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL); - src->filename = NULL; - /* otherwise set the new filename */ - } else { - src->filename = g_strdup (g_value_get_string (value)); - } - g_object_notify (G_OBJECT (src), "location"); + gst_filesrc_set_location (src, g_value_get_string (value)); break; case ARG_BLOCKSIZE: src->block_size = g_value_get_ulong (value); @@ -506,8 +528,10 @@ gst_filesrc_get_mmap (GstFileSrc *src) /* check to see if we're going to overflow the end of the file */ if (readend > src->filelen) { - readsize = src->filelen - src->curoffset; - readend = src->curoffset + readsize; + if (!gst_filesrc_check_filesize (src) || readend > src->filelen) { + readsize = src->filelen - src->curoffset; + readend = src->curoffset + readsize; + } } GST_LOG ("attempting to read %08lx, %08lx, %08lx, %08lx", @@ -599,7 +623,7 @@ gst_filesrc_get_mmap (GstFileSrc *src) /* subbuffer it */ buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - nextmap, readsize); - GST_BUFFER_OFFSET (buf) = mapstart + src->curoffset - nextmap; + GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET (src->mapbuf) + src->curoffset - nextmap; } } } @@ -613,6 +637,7 @@ gst_filesrc_get_mmap (GstFileSrc *src) } /* we're done, return the buffer */ + g_assert (src->curoffset == GST_BUFFER_OFFSET (buf)); src->curoffset += GST_BUFFER_SIZE(buf); return buf; } @@ -626,7 +651,9 @@ gst_filesrc_get_read (GstFileSrc *src) readsize = src->block_size; if (src->curoffset + readsize > src->filelen) { - readsize = src->filelen - src->curoffset; + if (!gst_filesrc_check_filesize (src) || src->curoffset + readsize > src->filelen) { + readsize = src->filelen - src->curoffset; + } } buf = gst_buffer_new_and_alloc (readsize); @@ -675,11 +702,14 @@ gst_filesrc_get (GstPad *pad) } /* check for EOF */ + g_assert (src->curoffset <= src->filelen); if (src->curoffset == src->filelen) { - GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT" %" G_GINT64_FORMAT, - src->curoffset, src->filelen); - gst_element_set_eos (GST_ELEMENT (src)); - return GST_DATA (gst_event_new (GST_EVENT_EOS)); + if (!gst_filesrc_check_filesize (src) || src->curoffset >= src->filelen) { + GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT" %" G_GINT64_FORMAT, + src->curoffset, src->filelen); + gst_element_set_eos (GST_ELEMENT (src)); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } } if (src->using_mmap){ @@ -689,6 +719,22 @@ gst_filesrc_get (GstPad *pad) } } +/* TRUE if the filesize of the file was updated */ +static gboolean +gst_filesrc_check_filesize (GstFileSrc *src) +{ + struct stat stat_results; + + g_return_val_if_fail (GST_FLAG_IS_SET (src ,GST_FILESRC_OPEN), FALSE); + + fstat(src->fd, &stat_results); + GST_DEBUG_OBJECT (src, "checked filesize on %s (was %"G_GUINT64_FORMAT", is %"G_GUINT64_FORMAT")", + src->filename, src->filelen, (guint64) stat_results.st_size); + if (src->filelen == (guint64) stat_results.st_size) + return FALSE; + src->filelen = stat_results.st_size; + return TRUE; +} /* open the file and mmap it, necessary to go to READY state */ static gboolean gst_filesrc_open_file (GstFileSrc *src) @@ -799,6 +845,7 @@ gst_filesrc_srcpad_query (GstPad *pad, GstQueryType type, if (*format != GST_FORMAT_BYTES) { return FALSE; } + gst_filesrc_check_filesize (src); *value = src->filelen; break; case GST_QUERY_POSITION: @@ -842,20 +889,25 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event) switch (GST_EVENT_SEEK_METHOD (event)) { case GST_SEEK_METHOD_SET: - if (offset > src->filelen) - goto error; + if (offset > src->filelen && (!gst_filesrc_check_filesize (src) || offset > src->filelen)) { + goto error; + } src->curoffset = offset; GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT, src->curoffset); break; case GST_SEEK_METHOD_CUR: if (offset + src->curoffset > src->filelen) - goto error; + if (!gst_filesrc_check_filesize (src) || offset + src->curoffset > src->filelen) + goto error; src->curoffset += offset; GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT, src->curoffset); break; case GST_SEEK_METHOD_END: - if (ABS (offset) > src->filelen) + if (ABS (offset) > src->filelen) { + if (!gst_filesrc_check_filesize (src) || ABS (offset) > src->filelen) + goto error; goto error; + } src->curoffset = src->filelen - ABS (offset); GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT, src->curoffset); break; @@ -888,3 +940,55 @@ error: gst_event_unref (event); return FALSE; } + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static guint +gst_filesrc_uri_get_type (void) +{ + return GST_URI_SRC; +} +static gchar ** +gst_filesrc_uri_get_protocols(void) +{ + static gchar *protocols[] = {"file", NULL}; + return protocols; +} +static const gchar * +gst_filesrc_uri_get_uri (GstURIHandler *handler) +{ + GstFileSrc *src = GST_FILESRC (handler); + + return src->uri; +} +static gboolean +gst_filesrc_uri_set_uri (GstURIHandler *handler, const gchar *uri) +{ + gchar *protocol, *location; + gboolean ret; + GstFileSrc *src = GST_FILESRC (handler); + + protocol = gst_uri_get_protocol (uri); + if (strcmp (protocol, "file") != 0) { + g_free (protocol); + return FALSE; + } + g_free (protocol); + location = gst_uri_get_location (uri); + ret = gst_filesrc_set_location (src, location); + g_free (location); + + return ret; +} + +static void +gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_filesrc_uri_get_type; + iface->get_protocols = gst_filesrc_uri_get_protocols; + iface->get_uri = gst_filesrc_uri_get_uri; + iface->set_uri = gst_filesrc_uri_set_uri; +} + diff --git a/plugins/elements/gstfilesrc.h b/plugins/elements/gstfilesrc.h index 23b6ddeef5..1f584be387 100644 --- a/plugins/elements/gstfilesrc.h +++ b/plugins/elements/gstfilesrc.h @@ -58,6 +58,7 @@ struct _GstFileSrc { guint pagesize; /* system page size*/ gchar *filename; /* filename */ + gchar *uri; /* caching the URI */ gint fd; /* open file descriptor*/ off_t filelen; /* what's the file length?*/ diff --git a/plugins/elements/gstidentity.c b/plugins/elements/gstidentity.c index c40ef162eb..4dc25af3e8 100644 --- a/plugins/elements/gstidentity.c +++ b/plugins/elements/gstidentity.c @@ -145,8 +145,8 @@ gst_identity_class_init (GstIdentityClass *klass) gst_identity_signals[SIGNAL_HANDOFF] = g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstIdentityClass, handoff), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); + gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, + GST_TYPE_BUFFER); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property); diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index 68dcc93b80..a9ed47a3a1 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -223,6 +223,7 @@ gst_queue_init (GTypeInstance *instance, gpointer g_class) gst_pad_set_bufferpool_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_get_bufferpool)); gst_pad_set_link_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_link)); gst_pad_set_getcaps_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps)); + gst_pad_set_active (queue->sinkpad, TRUE); queue->srcpad = gst_pad_new ("src", GST_PAD_SRC); gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get)); @@ -230,6 +231,7 @@ gst_queue_init (GTypeInstance *instance, gpointer g_class) gst_pad_set_link_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_link)); gst_pad_set_getcaps_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps)); gst_pad_set_event_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_handle_src_event)); + gst_pad_set_active (queue->srcpad, TRUE); queue->leaky = GST_QUEUE_NO_LEAK; queue->queue = NULL; @@ -695,6 +697,10 @@ gst_queue_change_state (GstElement *element) } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); + /* this is an ugly hack to make sure our pads are always active. Reason for this is that + * pad activation for the queue element depends on 2 schedulers (ugh) */ + gst_pad_set_active (queue->sinkpad, TRUE); + gst_pad_set_active (queue->srcpad, TRUE); error: g_mutex_unlock (queue->qlock); diff --git a/po/Makefile.in.in b/po/Makefile.in.in index 80b7aa368e..343b743fe8 100644 --- a/po/Makefile.in.in +++ b/po/Makefile.in.in @@ -282,11 +282,11 @@ clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES *.mo + rm -f stamp-po $(GMOFILES) maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." - rm -f stamp-po $(GMOFILES) dist distdir: $(MAKE) update-po diff --git a/po/de.po b/po/de.po index 3a0cade814..a4b91f39e9 100644 --- a/po/de.po +++ b/po/de.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gstreamer-0.7 0.7.0.1\n" "Report-Msgid-Bugs-To: \"http://bugzilla.gnome.org\"\n" -"POT-Creation-Date: 2003-10-08 15:36-0700\n" +"POT-Creation-Date: 2003-11-22 17:49+0100\n" "PO-Revision-Date: 2003-10-08 15:36-0700\n" "Last-Translator: David Schleef \n" "Language-Team: Gnome Translators \n" @@ -15,74 +15,71 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: gst/gst.c:113 +#: gst/gst.c:112 msgid "Print the GStreamer version" msgstr "druck die GStreamer Version" -#: gst/gst.c:114 +#: gst/gst.c:113 msgid "Make all warnings fatal" msgstr "macht alle Achtunge toedlich" -#: gst/gst.c:116 +#: gst/gst.c:115 msgid "" "default debug level from 1 (only error) to 5 (anything) or 0 for no output" msgstr "" -#: gst/gst.c:117 +#: gst/gst.c:116 msgid "" "colon-seperated list of category_name=level pairs to set specific levels for " "the individual categories.\n" "Example:GST_AUTOPLUG=5:GST_ELEMENT_*=3" msgstr "" -#: gst/gst.c:118 +#: gst/gst.c:117 msgid "disable color debugging output" msgstr "abschalt Farbe in Fehlersucheausgabe" -#: gst/gst.c:119 +#: gst/gst.c:118 msgid "disable debugging" msgstr "abschalt die Fehlersuche" -#: gst/gst.c:120 +#: gst/gst.c:119 msgid "print available debug categories and exit" msgstr "" -#: gst/gst.c:122 +#: gst/gst.c:121 msgid "Disable accelerated CPU instructions" msgstr "" -#: gst/gst.c:123 +#: gst/gst.c:122 msgid "enable verbose plugin loading diagnostics" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'--separated path list for loading plugins" msgstr "" -#: gst/gst.c:125 +#: gst/gst.c:124 msgid "" "comma-separated list of plugins to preload in addition to the list stored in " "env variable GST_PLUGIN_PATH" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "scheduler to use ('" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "' is the default)" msgstr "" -#: gst/gst.c:127 +#: gst/gst.c:126 msgid "registry to use" msgstr "" #~ msgid "This is a test\n" #~ msgstr "moo\n" - - - diff --git a/po/es.po b/po/es.po index 1ec8cef4e0..8b01f72a37 100644 --- a/po/es.po +++ b/po/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: GStreamer 0.7.0.1\n" "Report-Msgid-Bugs-To: \"http://bugzilla.gnome.org\"\n" -"POT-Creation-Date: 2003-10-08 16:20-0700\n" +"POT-Creation-Date: 2003-11-22 17:49+0100\n" "PO-Revision-Date: 2003-10-09 14:10-0700\n" "Last-Translator: David Schleef \n" "Language-Team: translators \n" @@ -15,68 +15,68 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: gst/gst.c:113 +#: gst/gst.c:112 msgid "Print the GStreamer version" msgstr "" -#: gst/gst.c:114 +#: gst/gst.c:113 msgid "Make all warnings fatal" msgstr "" -#: gst/gst.c:116 +#: gst/gst.c:115 msgid "" "default debug level from 1 (only error) to 5 (anything) or 0 for no output" msgstr "" -#: gst/gst.c:117 +#: gst/gst.c:116 msgid "" "colon-seperated list of category_name=level pairs to set specific levels for " "the individual categories.\n" "Example:GST_AUTOPLUG=5:GST_ELEMENT_*=3" msgstr "" -#: gst/gst.c:118 +#: gst/gst.c:117 msgid "disable color debugging output" msgstr "" -#: gst/gst.c:119 +#: gst/gst.c:118 msgid "disable debugging" msgstr "" -#: gst/gst.c:120 +#: gst/gst.c:119 msgid "print available debug categories and exit" msgstr "" -#: gst/gst.c:122 +#: gst/gst.c:121 msgid "Disable accelerated CPU instructions" msgstr "" -#: gst/gst.c:123 +#: gst/gst.c:122 msgid "enable verbose plugin loading diagnostics" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'--separated path list for loading plugins" msgstr "" -#: gst/gst.c:125 +#: gst/gst.c:124 msgid "" "comma-separated list of plugins to preload in addition to the list stored in " "env variable GST_PLUGIN_PATH" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "scheduler to use ('" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "' is the default)" msgstr "" -#: gst/gst.c:127 +#: gst/gst.c:126 msgid "registry to use" msgstr "" diff --git a/po/nl.po b/po/nl.po index 1ec8cef4e0..8b01f72a37 100644 --- a/po/nl.po +++ b/po/nl.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: GStreamer 0.7.0.1\n" "Report-Msgid-Bugs-To: \"http://bugzilla.gnome.org\"\n" -"POT-Creation-Date: 2003-10-08 16:20-0700\n" +"POT-Creation-Date: 2003-11-22 17:49+0100\n" "PO-Revision-Date: 2003-10-09 14:10-0700\n" "Last-Translator: David Schleef \n" "Language-Team: translators \n" @@ -15,68 +15,68 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: gst/gst.c:113 +#: gst/gst.c:112 msgid "Print the GStreamer version" msgstr "" -#: gst/gst.c:114 +#: gst/gst.c:113 msgid "Make all warnings fatal" msgstr "" -#: gst/gst.c:116 +#: gst/gst.c:115 msgid "" "default debug level from 1 (only error) to 5 (anything) or 0 for no output" msgstr "" -#: gst/gst.c:117 +#: gst/gst.c:116 msgid "" "colon-seperated list of category_name=level pairs to set specific levels for " "the individual categories.\n" "Example:GST_AUTOPLUG=5:GST_ELEMENT_*=3" msgstr "" -#: gst/gst.c:118 +#: gst/gst.c:117 msgid "disable color debugging output" msgstr "" -#: gst/gst.c:119 +#: gst/gst.c:118 msgid "disable debugging" msgstr "" -#: gst/gst.c:120 +#: gst/gst.c:119 msgid "print available debug categories and exit" msgstr "" -#: gst/gst.c:122 +#: gst/gst.c:121 msgid "Disable accelerated CPU instructions" msgstr "" -#: gst/gst.c:123 +#: gst/gst.c:122 msgid "enable verbose plugin loading diagnostics" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'--separated path list for loading plugins" msgstr "" -#: gst/gst.c:125 +#: gst/gst.c:124 msgid "" "comma-separated list of plugins to preload in addition to the list stored in " "env variable GST_PLUGIN_PATH" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "scheduler to use ('" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "' is the default)" msgstr "" -#: gst/gst.c:127 +#: gst/gst.c:126 msgid "registry to use" msgstr "" diff --git a/po/no.po b/po/no.po index 1ec8cef4e0..8b01f72a37 100644 --- a/po/no.po +++ b/po/no.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: GStreamer 0.7.0.1\n" "Report-Msgid-Bugs-To: \"http://bugzilla.gnome.org\"\n" -"POT-Creation-Date: 2003-10-08 16:20-0700\n" +"POT-Creation-Date: 2003-11-22 17:49+0100\n" "PO-Revision-Date: 2003-10-09 14:10-0700\n" "Last-Translator: David Schleef \n" "Language-Team: translators \n" @@ -15,68 +15,68 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: gst/gst.c:113 +#: gst/gst.c:112 msgid "Print the GStreamer version" msgstr "" -#: gst/gst.c:114 +#: gst/gst.c:113 msgid "Make all warnings fatal" msgstr "" -#: gst/gst.c:116 +#: gst/gst.c:115 msgid "" "default debug level from 1 (only error) to 5 (anything) or 0 for no output" msgstr "" -#: gst/gst.c:117 +#: gst/gst.c:116 msgid "" "colon-seperated list of category_name=level pairs to set specific levels for " "the individual categories.\n" "Example:GST_AUTOPLUG=5:GST_ELEMENT_*=3" msgstr "" -#: gst/gst.c:118 +#: gst/gst.c:117 msgid "disable color debugging output" msgstr "" -#: gst/gst.c:119 +#: gst/gst.c:118 msgid "disable debugging" msgstr "" -#: gst/gst.c:120 +#: gst/gst.c:119 msgid "print available debug categories and exit" msgstr "" -#: gst/gst.c:122 +#: gst/gst.c:121 msgid "Disable accelerated CPU instructions" msgstr "" -#: gst/gst.c:123 +#: gst/gst.c:122 msgid "enable verbose plugin loading diagnostics" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'" msgstr "" -#: gst/gst.c:124 +#: gst/gst.c:123 msgid "'--separated path list for loading plugins" msgstr "" -#: gst/gst.c:125 +#: gst/gst.c:124 msgid "" "comma-separated list of plugins to preload in addition to the list stored in " "env variable GST_PLUGIN_PATH" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "scheduler to use ('" msgstr "" -#: gst/gst.c:126 +#: gst/gst.c:125 msgid "' is the default)" msgstr "" -#: gst/gst.c:127 +#: gst/gst.c:126 msgid "registry to use" msgstr "" diff --git a/tests/old/examples/Makefile.am b/tests/old/examples/Makefile.am index 416ebf2f7f..c7d650c31b 100644 --- a/tests/old/examples/Makefile.am +++ b/tests/old/examples/Makefile.am @@ -4,12 +4,35 @@ else GST_LOADSAVE_DIRS = xml typefind endif -SUBDIRS = $(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) -DIST_SUBDIRS = helloworld helloworld2 \ - queue queue2 queue3 queue4 \ - launch thread xml plugins typefind mixer cutter pingpong manual +DIST_SUBDIRS = helloworld \ + queue \ + queue2 \ + queue3 \ + queue4 \ + launch \ + thread \ + plugins \ + mixer \ + cutter \ + pingpong \ + manual \ + xml \ + typefind \ + retag diff --git a/tests/old/testsuite/Makefile.am b/tests/old/testsuite/Makefile.am index 94425e696d..10eb0e111a 100644 --- a/tests/old/testsuite/Makefile.am +++ b/tests/old/testsuite/Makefile.am @@ -14,11 +14,11 @@ GST_DEBUG_DIRS = debug endif SUBDIRS = bytestream cleanup dynparams \ - caps caps2 plugin elements clock refcounting threads \ + caps caps2 plugin elements clock refcounting tags threads \ indexers debug $(GST_PARSE_DIRS) $(GST_DEBUG_DIRS) DIST_SUBDIRS = bytestream caps caps2 cleanup clock dynparams elements indexers \ - plugin refcounting threads parse debug + plugin refcounting tags threads parse debug tests_pass = test_gst_init tests_fail = diff --git a/tests/old/testsuite/bytestream/Makefile.am b/tests/old/testsuite/bytestream/Makefile.am index c28cbb0d0e..283ea37d62 100644 --- a/tests/old/testsuite/bytestream/Makefile.am +++ b/tests/old/testsuite/bytestream/Makefile.am @@ -4,5 +4,5 @@ tests_pass = tests_fail = test1 test1_SOURCES = test1.c gstbstest.c -test1_LDFLAGS = -lgstbytestream -L$(top_srcdir)/libs/gst/bytestream +test1_LDFLAGS = $(top_builddir)/libs/gst/bytestream/libgstbytestream.la diff --git a/tests/old/testsuite/caps/.gitignore b/tests/old/testsuite/caps/.gitignore index b8123bb1e4..e1b1bf846a 100644 --- a/tests/old/testsuite/caps/.gitignore +++ b/tests/old/testsuite/caps/.gitignore @@ -11,3 +11,5 @@ intersection normalisation union fixed +string-conversions +intersect2 diff --git a/tests/old/testsuite/cleanup/Makefile.am b/tests/old/testsuite/cleanup/Makefile.am index cb1ff56b4a..28369a5aaa 100644 --- a/tests/old/testsuite/cleanup/Makefile.am +++ b/tests/old/testsuite/cleanup/Makefile.am @@ -1,8 +1,10 @@ include ../Rules tests_pass = cleanup1 cleanup2 cleanup4 cleanup5 -tests_fail = -#tests_that_work_sometimes = cleanup3 +tests_fail = + +# cleanup3 fails depending on the machine +tests_ignore = cleanup3 # we have nothing but apps here, we can do this safely cleanup1_LDADD = $(GST_LIBS) diff --git a/tests/old/testsuite/debug/global.c b/tests/old/testsuite/debug/global.c index 68c93b8d83..f878706c93 100644 --- a/tests/old/testsuite/debug/global.c +++ b/tests/old/testsuite/debug/global.c @@ -21,6 +21,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif + #include #define THREAD_COUNT 5 diff --git a/tests/old/testsuite/threads/queue.c b/tests/old/testsuite/threads/queue.c index 2435e31c2f..191ae43f04 100644 --- a/tests/old/testsuite/threads/queue.c +++ b/tests/old/testsuite/threads/queue.c @@ -76,7 +76,7 @@ main (gint argc, gchar *argv[]) gst_element_set_state (thread, GST_STATE_PLAYING); g_print ("SLEEPING 1 sec\n"); sleep (1); - gst_element_set_state (pipeline, GST_STATE_PLAYING); + gst_bin_sync_children_state (GST_BIN (pipeline)); g_print ("SLEEPING 2 sec\n"); sleep (2); diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 94425e696d..10eb0e111a 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -14,11 +14,11 @@ GST_DEBUG_DIRS = debug endif SUBDIRS = bytestream cleanup dynparams \ - caps caps2 plugin elements clock refcounting threads \ + caps caps2 plugin elements clock refcounting tags threads \ indexers debug $(GST_PARSE_DIRS) $(GST_DEBUG_DIRS) DIST_SUBDIRS = bytestream caps caps2 cleanup clock dynparams elements indexers \ - plugin refcounting threads parse debug + plugin refcounting tags threads parse debug tests_pass = test_gst_init tests_fail = diff --git a/testsuite/bytestream/Makefile.am b/testsuite/bytestream/Makefile.am index c28cbb0d0e..283ea37d62 100644 --- a/testsuite/bytestream/Makefile.am +++ b/testsuite/bytestream/Makefile.am @@ -4,5 +4,5 @@ tests_pass = tests_fail = test1 test1_SOURCES = test1.c gstbstest.c -test1_LDFLAGS = -lgstbytestream -L$(top_srcdir)/libs/gst/bytestream +test1_LDFLAGS = $(top_builddir)/libs/gst/bytestream/libgstbytestream.la diff --git a/testsuite/caps/.gitignore b/testsuite/caps/.gitignore index b8123bb1e4..e1b1bf846a 100644 --- a/testsuite/caps/.gitignore +++ b/testsuite/caps/.gitignore @@ -11,3 +11,5 @@ intersection normalisation union fixed +string-conversions +intersect2 diff --git a/testsuite/cleanup/Makefile.am b/testsuite/cleanup/Makefile.am index cb1ff56b4a..28369a5aaa 100644 --- a/testsuite/cleanup/Makefile.am +++ b/testsuite/cleanup/Makefile.am @@ -1,8 +1,10 @@ include ../Rules tests_pass = cleanup1 cleanup2 cleanup4 cleanup5 -tests_fail = -#tests_that_work_sometimes = cleanup3 +tests_fail = + +# cleanup3 fails depending on the machine +tests_ignore = cleanup3 # we have nothing but apps here, we can do this safely cleanup1_LDADD = $(GST_LIBS) diff --git a/testsuite/debug/global.c b/testsuite/debug/global.c index 68c93b8d83..f878706c93 100644 --- a/testsuite/debug/global.c +++ b/testsuite/debug/global.c @@ -21,6 +21,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif + #include #define THREAD_COUNT 5 diff --git a/testsuite/threads/queue.c b/testsuite/threads/queue.c index 2435e31c2f..191ae43f04 100644 --- a/testsuite/threads/queue.c +++ b/testsuite/threads/queue.c @@ -76,7 +76,7 @@ main (gint argc, gchar *argv[]) gst_element_set_state (thread, GST_STATE_PLAYING); g_print ("SLEEPING 1 sec\n"); sleep (1); - gst_element_set_state (pipeline, GST_STATE_PLAYING); + gst_bin_sync_children_state (GST_BIN (pipeline)); g_print ("SLEEPING 2 sec\n"); sleep (2); diff --git a/tools/Makefile.am b/tools/Makefile.am index a69f3bae6f..56f2d4fa7c 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -45,41 +45,32 @@ SUFFIXES = .1 .1.in $< >$@ gst_launch_LDADD = $(GST_LIBS) #-lefence -gst_launch_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_launch_CFLAGS = $(GST_CFLAGS) gst_md5sum_LDADD = $(GST_LIBS) #-lefence -gst_md5sum_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_md5sum_CFLAGS = $(GST_CFLAGS) gst_typefind_LDADD = $(GST_LIBS) #-lefence -gst_typefind_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_typefind_CFLAGS = $(GST_CFLAGS) gst_inspect_LDADD = $(GST_LIBS) ../libs/gst/control/libgstcontrol-@GST_MAJORMINOR@.la -gst_inspect_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_inspect_CFLAGS = $(GST_CFLAGS) gst_xmlinspect_LDADD = $(GST_LIBS) ../libs/gst/control/libgstcontrol-@GST_MAJORMINOR@.la -gst_xmlinspect_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_xmlinspect_CFLAGS = $(GST_CFLAGS) if !GST_DISABLE_REGISTRY gst_register_LDADD = $(GST_LIBS) -gst_register_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_register_CFLAGS = $(GST_CFLAGS) gst_complete_LDADD = $(GST_LIBS) -gst_complete_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_complete_CFLAGS = $(GST_CFLAGS) gst_compprep_LDADD = $(GST_LIBS) -gst_compprep_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_compprep_CFLAGS = $(GST_CFLAGS) gst_xmllaunch_SOURCES = gst-launch.c gst_xmllaunch_LDADD = $(GST_LIBS) -gst_xmllaunch_CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" \ - -DGST_CACHE_DIR=\""$(GST_CACHE_DIR)"\" +gst_xmllaunch_CFLAGS = $(GST_CFLAGS) endif diff --git a/tools/gst-inspect.c b/tools/gst-inspect.c index 0665e65943..26f94c3c34 100644 --- a/tools/gst-inspect.c +++ b/tools/gst-inspect.c @@ -751,16 +751,6 @@ print_element_list (void) g_print ("%s: %s: %s\n", plugin->desc.name, GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc); } -#ifndef GST_DISABLE_URI - else if (GST_IS_URI_HANDLER (feature)) { - GstURIHandler *handler; - - handler = GST_URI_HANDLER (feature); - g_print ("%s: %s: \"%s\" (%s) element \"%s\" property \"%s\"\n", - plugin->desc.name, GST_PLUGIN_FEATURE_NAME (handler), handler->uri, - handler->longdesc, handler->element, handler->property); - } -#endif else { g_print ("%s: %s (%s)\n", plugin->desc.name, GST_PLUGIN_FEATURE_NAME (feature), diff --git a/tools/gst-launch.c b/tools/gst-launch.c index 5eb22d8b19..9dd502574e 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -221,6 +221,39 @@ 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; + + if (gst_tag_get_type (tag) == G_TYPE_STRING) { + g_assert (gst_tag_list_get_string_index (list, tag, i, &str)); + } else { + 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 +319,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 +337,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 +418,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 diff --git a/tools/gst-xmlinspect.c b/tools/gst-xmlinspect.c index 812feecb25..4a5ea991a0 100644 --- a/tools/gst-xmlinspect.c +++ b/tools/gst-xmlinspect.c @@ -753,16 +753,6 @@ print_element_list (void) g_print ("%s: %s: %s\n", plugin->desc.name, GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc); } -#ifndef GST_DISABLE_URI - else if (GST_IS_URI_HANDLER (feature)) { - GstURIHandler *handler; - - handler = GST_URI_HANDLER (feature); - g_print ("%s: %s: \"%s\" (%s) element \"%s\" property \"%s\"\n", - plugin->desc.name, GST_PLUGIN_FEATURE_NAME (handler), handler->uri, - handler->longdesc, handler->element, handler->property); - } -#endif else { g_print ("%s: %s (%s)\n", plugin->desc.name, GST_PLUGIN_FEATURE_NAME (feature),