Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.85161 + umask 022 + cd /usr/src/rpm/BUILD + LANG=C + export LANG + unset DISPLAY + cd /usr/src/rpm/BUILD + rm -rf gstreamer-0.8.11 + /usr/bin/bzip2 -dc /usr/src/rpm/SOURCES/gstreamer-0.8.11.tar.bz2 + tar -xf - + STATUS=0 + '[' 0 -ne 0 ']' + cd gstreamer-0.8.11 ++ /usr/bin/id -u + '[' 500 = 0 ']' ++ /usr/bin/id -u + '[' 500 = 0 ']' + /bin/chmod -Rf a+rX,u+w,g-w,o-w . + echo 'Patch #0 (gstreamer-0.8.11-lib64.patch):' Patch #0 (gstreamer-0.8.11-lib64.patch): + patch -p1 -b --suffix .lib64 -s + echo 'Patch #1 (gstreamer-0.7.5-nops.patch):' Patch #1 (gstreamer-0.7.5-nops.patch): + patch -p1 -b --suffix .nops -s + echo 'Patch #2 (gstreamer-0.8.9-cast-fix.patch):' Patch #2 (gstreamer-0.8.9-cast-fix.patch): + patch -p1 -b --suffix .cast-fix -s + NOCONFIGURE=1 + ./autogen.sh + check for build tools checking for autoconf >= 2.52 ... found 2.59, ok. checking for automake >= 1.6 ... found 1.9.6, ok. checking for autopoint >= 0.11.5 ... found 0.14.5, ok. checking for libtoolize >= 1.5.0 ... found 1.5.20, ok. checking for pkg-config >= 0.8.0 ... found 0.20, ok. + checking for autogen.sh options This autogen script will automatically run ./configure as: ./configure --enable-maintainer-mode --enable-plugin-builddir --enable-failing-tests --enable-poisoning To pass any additional options, please specify them on the ./autogen.sh command line. patching file po/Makefile.in.in + running autopoint --force... Copying file common/m4/codeset.m4 Copying file common/m4/glibc21.m4 Copying file common/m4/intdiv0.m4 Copying file common/m4/inttypes-pri.m4 Copying file common/m4/inttypes.m4 Copying file common/m4/inttypes_h.m4 Copying file common/m4/isc-posix.m4 Copying file common/m4/lcmessage.m4 Copying file common/m4/stdint_h.m4 Copying file common/m4/uintmax_t.m4 Copying file common/m4/ulonglong.m4 Copying file mkinstalldirs patching file po/Makefile.in.in + running aclocal -I common/m4 ... + running libtoolize --copy --force... + running autoheader ... + running autoconf ... + running automake --add-missing --copy... skipping configure stage for package gstreamer, as requested. autogen.sh done. + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.29140 + umask 022 + cd /usr/src/rpm/BUILD + cd gstreamer-0.8.11 + LANG=C + export LANG + unset DISPLAY + CFLAGS='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables' + export CFLAGS + CXXFLAGS='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables' + export CXXFLAGS + FFLAGS='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables' + export FFLAGS ++ find . -name config.guess -o -name config.sub + for i in '$(find . -name config.guess -o -name config.sub)' ++ basename ./config.sub + '[' -f /usr/lib/rpm/redhat/config.sub ']' + /bin/rm -f ./config.sub ++ basename ./config.sub + /bin/cp -fv /usr/lib/rpm/redhat/config.sub ./config.sub `/usr/lib/rpm/redhat/config.sub' -> `./config.sub' + for i in '$(find . -name config.guess -o -name config.sub)' ++ basename ./config.guess + '[' -f /usr/lib/rpm/redhat/config.guess ']' + /bin/rm -f ./config.guess ++ basename ./config.guess + /bin/cp -fv /usr/lib/rpm/redhat/config.guess ./config.guess `/usr/lib/rpm/redhat/config.guess' -> `./config.guess' + ./configure --build=i686-redhat-linux-gnu --host=i686-redhat-linux-gnu --target=i386-redhat-linux-gnu --program-prefix= --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib --libexecdir=/usr/libexec --localstatedir=/var --sharedstatedir=/usr/com --mandir=/usr/share/man --infodir=/usr/share/info --disable-plugin-builddir --disable-tests --disable-examples --with-cachedir=/var/cache/gstreamer-0.8 --enable-docs-build --with-html-dir=/var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html --enable-debug checking build system type... i686-redhat-linux-gnu checking host system type... i686-redhat-linux-gnu checking target system type... i386-redhat-linux-gnu configure: configuring gstreamer for release checking whether to enable maintainer-specific portions of Makefiles... no checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for i686-redhat-linux-gnu-gcc... no checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for style of include used by make... GNU checking dependency style of gcc... gcc3 checking for library containing strerror... none required checking for a sed that does not truncate output... /bin/sed checking for egrep... grep -E checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for /usr/bin/ld option to reload object files... -r checking for BSD-compatible nm... nm checking whether ln -s works... yes checking how to recognise dependent libraries... pass_all checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking dlfcn.h usability... yes checking dlfcn.h presence... yes checking for dlfcn.h... yes checking for i686-redhat-linux-gnu-g++... no checking for i686-redhat-linux-gnu-c++... no checking for i686-redhat-linux-gnu-gpp... no checking for i686-redhat-linux-gnu-aCC... no checking for i686-redhat-linux-gnu-CC... no checking for i686-redhat-linux-gnu-cxx... no checking for i686-redhat-linux-gnu-cc++... no checking for i686-redhat-linux-gnu-cl... no checking for i686-redhat-linux-gnu-FCC... no checking for i686-redhat-linux-gnu-KCC... no checking for i686-redhat-linux-gnu-RCC... no checking for i686-redhat-linux-gnu-xlC_r... no checking for i686-redhat-linux-gnu-xlC... no checking for g++... g++ checking whether we are using the GNU C++ compiler... yes checking whether g++ accepts -g... yes checking dependency style of g++... gcc3 checking how to run the C++ preprocessor... g++ -E checking for i686-redhat-linux-gnu-g77... no checking for i686-redhat-linux-gnu-f77... no checking for i686-redhat-linux-gnu-xlf... no checking for i686-redhat-linux-gnu-frt... no checking for i686-redhat-linux-gnu-pgf77... no checking for i686-redhat-linux-gnu-fort77... no checking for i686-redhat-linux-gnu-fl32... no checking for i686-redhat-linux-gnu-af77... no checking for i686-redhat-linux-gnu-f90... no checking for i686-redhat-linux-gnu-xlf90... no checking for i686-redhat-linux-gnu-pgf90... no checking for i686-redhat-linux-gnu-epcf90... no checking for i686-redhat-linux-gnu-f95... no checking for i686-redhat-linux-gnu-fort... no checking for i686-redhat-linux-gnu-xlf95... no checking for i686-redhat-linux-gnu-ifc... no checking for i686-redhat-linux-gnu-efc... no checking for i686-redhat-linux-gnu-pgf95... no checking for i686-redhat-linux-gnu-lf95... no checking for i686-redhat-linux-gnu-gfortran... no checking for g77... no checking for f77... no checking for xlf... no checking for frt... no checking for pgf77... no checking for fort77... no checking for fl32... no checking for af77... no checking for f90... no checking for xlf90... no checking for pgf90... no checking for epcf90... no checking for f95... no checking for fort... no checking for xlf95... no checking for ifc... no checking for efc... no checking for pgf95... no checking for lf95... no checking for gfortran... no checking whether we are using the GNU Fortran 77 compiler... no checking whether accepts -g... no checking the maximum length of command line arguments... 32768 checking command to parse nm output from gcc object... ok checking for objdir... .libs checking for i686-redhat-linux-gnu-ar... no checking for ar... ar checking for i686-redhat-linux-gnu-ranlib... no checking for ranlib... ranlib checking for i686-redhat-linux-gnu-strip... no checking for strip... strip checking if gcc static flag works... yes checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC checking if gcc PIC flag -fPIC works... yes checking if gcc supports -c -o file.o... yes checking whether the gcc linker (/usr/bin/ld) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... cat: ld.so.conf.d/*.conf: No such file or directory GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking for shl_load... no checking for shl_load in -ldld... no checking for dlopen... no checking for dlopen in -ldl... yes checking whether a program can dlopen itself... yes checking whether a statically linked program can dlopen itself... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes configure: creating libtool appending configuration tag "CXX" to libtool checking for ld used by g++... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking whether the g++ linker (/usr/bin/ld) supports shared libraries... yes checking for g++ option to produce PIC... -fPIC checking if g++ PIC flag -fPIC works... yes checking if g++ supports -c -o file.o... yes checking whether the g++ linker (/usr/bin/ld) supports shared libraries... yes checking dynamic linker characteristics... cat: ld.so.conf.d/*.conf: No such file or directory GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking for shl_load... (cached) no checking for shl_load in -ldld... (cached) no checking for dlopen... (cached) no checking for dlopen in -ldl... (cached) yes checking whether a program can dlopen itself... (cached) yes checking whether a statically linked program can dlopen itself... (cached) yes appending configuration tag "F77" to libtool checking for i686-redhat-linux-gnu-gcc... gcc checking whether we are using the GNU C compiler... (cached) yes checking whether gcc accepts -g... (cached) yes checking for gcc option to accept ANSI C... (cached) none needed checking dependency style of gcc... (cached) gcc3 checking for msgfmt... /usr/bin/msgfmt checking for gmsgfmt... /usr/bin/msgfmt checking for xgettext... /usr/bin/xgettext checking for msgmerge... /usr/bin/msgmerge checking for ld used by GCC... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for shared library run path origin... done checking whether NLS is requested... yes checking for GNU gettext in libc... yes checking to see if compiler understands -Wall... yes checking for ANSI C header files... (cached) yes checking for inline... inline checking for gtkdoc-scangobj... true checking gtk-doc version (1.4) >= 1.0... yes checking for docbook2ps... true checking for docbook2html... true checking for jadetex... true checking for ps2pdf... true checking docbook2html version (DocBook-utils version 0.6.14 (jw version 1.1)) >= 0.6.10... yes checking for xsltproc... xsltproc checking whether xsltproc docbook processing works... yes checking for dvips... true checking for fig2dev... true checking for pngtopnm... true checking for pnmtops... true checking for epstopdf... true configure: Will output HTML documentation configure: Will output PS documentation configure: Will output PDF documentation configure: Looking for Python version >= 2.1 checking for python... /usr/bin/python checking "/usr/bin/python":... okay checking local Python configuration... looks good checking whether byte ordering is bigendian... no checking for perl... /usr/bin/perl checking for gawk... (cached) gawk checking for bison... /usr/bin/bison checking bison version... ok checking for flex... /usr/bin/flex checking for large file support... yes checking for stdlib.h... (cached) yes checking for unistd.h... (cached) yes checking for getpagesize... yes checking for working mmap... yes checking for usable SVR4/SUSv2 makecontext(2)/swapcontext(2)... yes checking whether gcc implements __PRETTY_FUNCTION__... yes checking whether gcc implements __FUNCTION__... yes checking whether gcc implements __func__... yes checking to see if compiler understands -fno-common... yes checking if unaligned memory access works correctly... (whitelisted) yes checking for pkg-config... /usr/bin/pkg-config checking for glib-2.0 >= 2.2 gobject-2.0 gthread-2.0 gmodule-2.0... yes checking GLIB2_CFLAGS... -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include checking GLIB2_LIBS... -pthread -Wl,--export-dynamic -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 checking for glib-2.0 >= 2.2... yes checking GLIB_ONLY_CFLAGS... -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include checking GLIB_ONLY_LIBS... -lglib-2.0 checking for libxml-2.0 >= 2.6.0... yes checking XML_CFLAGS... -I/usr/include/libxml2 checking XML_LIBS... -lxml2 -lz -lm configure: Test xml2 program linked checking for poptStrippedArgv in -lpopt... yes checking popt.h usability... yes checking popt.h presence... yes checking for popt.h... yes configure: Checking for POPT_TABLEEND checking ucontext.h usability... yes checking ucontext.h presence... yes checking for ucontext.h... yes configure: Using /var/cache/gstreamer-0.8 as registry cache dir configure: WARNING: Sissy ! By asking to not build the tests known to fail, you hereby waive your right to customer support. If you do not agree with this EULA, please press Ctrl-C before the next line is printed. By allowing the next line to be printed, you expressly acknowledge your acceptance of this EULA. checking for valgrind > 2.1... checking for sigaction... yes checking for register_printf_function... yes checking for dladdr in -ldl... yes configure: Using GStreamer source release as package name configure: Using http://gstreamer.freedesktop.org/ as package origin configure: Using /usr/lib/gstreamer-0.8 as the plugin install location checking for libgnomeui-2.0... configure: creating ./config.status config.status: creating Makefile config.status: creating include/Makefile config.status: creating gst/Makefile config.status: creating gst/gstconfig.h config.status: creating gst/gstversion.h config.status: creating gst/autoplug/Makefile config.status: creating gst/indexers/Makefile config.status: creating gst/elements/Makefile config.status: creating gst/parse/Makefile config.status: creating gst/schedulers/Makefile config.status: creating gst/registries/Makefile config.status: creating libs/Makefile config.status: creating libs/gst/Makefile config.status: creating libs/gst/bytestream/Makefile config.status: creating libs/gst/control/Makefile config.status: creating libs/gst/dataprotocol/Makefile config.status: creating libs/gst/getbits/Makefile config.status: creating po/Makefile.in config.status: creating tests/Makefile config.status: creating tests/bufspeed/Makefile config.status: creating tests/instantiate/Makefile config.status: creating tests/memchunk/Makefile config.status: creating tests/muxing/Makefile config.status: creating tests/seeking/Makefile config.status: creating tests/sched/Makefile config.status: creating tests/threadstate/Makefile config.status: creating testsuite/Makefile config.status: creating testsuite/bins/Makefile config.status: creating testsuite/bytestream/Makefile config.status: creating testsuite/caps/Makefile config.status: creating testsuite/childproxy/Makefile config.status: creating testsuite/cleanup/Makefile config.status: creating testsuite/clock/Makefile config.status: creating testsuite/debug/Makefile config.status: creating testsuite/dlopen/Makefile config.status: creating testsuite/dynparams/Makefile config.status: creating testsuite/elements/Makefile config.status: creating testsuite/ghostpads/Makefile config.status: creating testsuite/indexers/Makefile config.status: creating testsuite/negotiation/Makefile config.status: creating testsuite/pad/Makefile config.status: creating testsuite/parse/Makefile config.status: creating testsuite/plugin/Makefile config.status: creating testsuite/refcounting/Makefile config.status: creating testsuite/schedulers/Makefile config.status: creating testsuite/states/Makefile config.status: creating testsuite/tags/Makefile config.status: creating testsuite/threads/Makefile config.status: creating examples/Makefile config.status: creating examples/cutter/Makefile config.status: creating examples/helloworld/Makefile config.status: creating examples/launch/Makefile config.status: creating examples/manual/Makefile config.status: creating examples/mixer/Makefile config.status: creating examples/pingpong/Makefile config.status: creating examples/plugins/Makefile config.status: creating examples/queue/Makefile config.status: creating examples/queue2/Makefile config.status: creating examples/queue3/Makefile config.status: creating examples/queue4/Makefile config.status: creating examples/retag/Makefile config.status: creating examples/thread/Makefile config.status: creating examples/typefind/Makefile config.status: creating examples/xml/Makefile config.status: creating tools/Makefile config.status: creating common/Makefile config.status: creating common/m4/Makefile config.status: creating docs/Makefile config.status: creating docs/faq/Makefile config.status: creating docs/gst/Makefile config.status: creating docs/libs/Makefile config.status: creating docs/manual/Makefile config.status: creating docs/plugins/Makefile config.status: creating docs/plugins/gstreamer-plugins.types config.status: creating docs/pwg/Makefile config.status: creating docs/xsl/Makefile config.status: creating docs/version.entities config.status: creating pkgconfig/Makefile config.status: creating stamp.h config.status: creating pkgconfig/gstreamer.pc config.status: creating pkgconfig/gstreamer-uninstalled.pc config.status: creating pkgconfig/gstreamer-control.pc config.status: creating pkgconfig/gstreamer-control-uninstalled.pc config.status: creating gst-element-check.m4 config.status: creating gstreamer.spec config.status: creating config.h config.status: executing depfiles commands config.status: executing default-1 commands config.status: creating po/POTFILES config.status: creating po/Makefile config.status: executing default commands + make -j2 make all-recursive make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' Making all in include make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/include' make[2]: Nothing to be done for `all'. make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/include' Making all in gst make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' glib-mkenums \ --fhead "#ifndef __GST_ENUM_TYPES_H__\n#define __GST_ENUM_TYPES_H__\n\n#include \n\nG_BEGIN_DECLS\n" \ --fprod "/* enumerations from \"@filename@\" */\n" \ --vhead "GType @enum_name@_get_type (void);\n#define GST_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ --ftail "G_END_DECLS\n\n#endif /* __GST_ENUM_TYPES_H__ */" \ gst.h gstatomic.h gstobject.h gstbin.h gstbuffer.h gstcaps.h gstclock.h gstcompat.h gstcpu.h gstdata.h gstelement.h gsterror.h gstevent.h gstfilter.h gstformat.h gstindex.h gstinfo.h gstinterface.h gstmacros.h gstmemchunk.h gstpad.h gstchildproxy.h gstpipeline.h gstplugin.h gstpluginfeature.h gstprobe.h gstqueue.h gstquery.h gstscheduler.h gststructure.h gstsystemclock.h gsttag.h gsttaginterface.h gstthread.h gsttrace.h gsttrashstack.h gsttypefind.h gsttypes.h gsturi.h gsturitype.h gstutils.h gstvalue.h gstregistry.h gstregistrypool.h gstparse.h gstxml.h > gstenumtypes.h glib-genmarshal --header --prefix=gst_marshal ./gstmarshal.list > gstmarshal.h.tmp mv gstmarshal.h.tmp gstmarshal.h glib-mkenums \ --fhead "#include \"gst_private.h\"\n#include " \ --fprod "\n/* enumerations from \"@filename@\" */" \ --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ gst.h gstatomic.h gstobject.h gstbin.h gstbuffer.h gstcaps.h gstclock.h gstcompat.h gstcpu.h gstdata.h gstelement.h gsterror.h gstevent.h gstfilter.h gstformat.h gstindex.h gstinfo.h gstinterface.h gstmacros.h gstmemchunk.h gstpad.h gstchildproxy.h gstpipeline.h gstplugin.h gstpluginfeature.h gstprobe.h gstqueue.h gstquery.h gstscheduler.h gststructure.h gstsystemclock.h gsttag.h gsttaginterface.h gstthread.h gsttrace.h gsttrashstack.h gsttypefind.h gsttypes.h gsturi.h gsturitype.h gstutils.h gstvalue.h gstregistry.h gstregistrypool.h gstparse.h gstxml.h > gstenumtypes.c echo "#include \"gst_private.h\"" > gstmarshal.c.tmp echo "#include \"glib-object.h\"" >> gstmarshal.c.tmp echo "#include \"gstmarshal.h\"" >> gstmarshal.c.tmp glib-genmarshal --body --prefix=gst_marshal ./gstmarshal.list >> gstmarshal.c.tmp mv gstmarshal.c.tmp gstmarshal.c make all-recursive make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' Making all in parse make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/parse' /usr/bin/flex -P_gst_parse_yy parse.l grammar.tab.h /usr/bin/bison -d -v -p_gst_parse__yy ./grammar.y -o grammar.tab.c ./grammar.y: conflicts: 42 shift/reduce, 5 reduce/reduce if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstparse_la-grammar.tab.lo -MD -MP -MF ".deps/libgstparse_la-grammar.tab.Tpo" -c -o libgstparse_la-grammar.tab.lo `test -f 'grammar.tab.c' || echo './'`grammar.tab.c; \ then mv -f ".deps/libgstparse_la-grammar.tab.Tpo" ".deps/libgstparse_la-grammar.tab.Plo"; else rm -f ".deps/libgstparse_la-grammar.tab.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstparse_la-grammar.tab.lo -MD -MP -MF .deps/libgstparse_la-grammar.tab.Tpo -c grammar.tab.c -fPIC -DPIC -o .libs/libgstparse_la-grammar.tab.o if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstparse_la-lex._gst_parse_yy.lo -MD -MP -MF ".deps/libgstparse_la-lex._gst_parse_yy.Tpo" -c -o libgstparse_la-lex._gst_parse_yy.lo `test -f 'lex._gst_parse_yy.c' || echo './'`lex._gst_parse_yy.c; \ then mv -f ".deps/libgstparse_la-lex._gst_parse_yy.Tpo" ".deps/libgstparse_la-lex._gst_parse_yy.Plo"; else rm -f ".deps/libgstparse_la-lex._gst_parse_yy.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstparse_la-lex._gst_parse_yy.lo -MD -MP -MF .deps/libgstparse_la-lex._gst_parse_yy.Tpo -c lex._gst_parse_yy.c -fPIC -DPIC -o .libs/libgstparse_la-lex._gst_parse_yy.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstparse_la-grammar.tab.lo -MD -MP -MF .deps/libgstparse_la-grammar.tab.Tpo -c grammar.tab.c -o libgstparse_la-grammar.tab.o >/dev/null 2>&1 lex._gst_parse_yy.c: In function '_gst_parse_yylex': parse.l:144: warning: ignoring return value of 'fwrite', declared with attribute warn_unused_result gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstparse_la-lex._gst_parse_yy.lo -MD -MP -MF .deps/libgstparse_la-lex._gst_parse_yy.Tpo -c lex._gst_parse_yy.c -o libgstparse_la-lex._gst_parse_yy.o >/dev/null 2>&1 /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstparse.la libgstparse_la-lex._gst_parse_yy.lo libgstparse_la-grammar.tab.lo -lxml2 -lz -lm -pthread -Wl,--export-dynamic -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm ar cru .libs/libgstparse.a .libs/libgstparse_la-lex._gst_parse_yy.o .libs/libgstparse_la-grammar.tab.o ranlib .libs/libgstparse.a creating libgstparse.la (cd .libs && rm -f libgstparse.la && ln -s ../libgstparse.la libgstparse.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/parse' Making all in registries make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/registries' if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstxmlregistry_la-gstlibxmlregistry.lo -MD -MP -MF ".deps/libgstxmlregistry_la-gstlibxmlregistry.Tpo" -c -o libgstxmlregistry_la-gstlibxmlregistry.lo `test -f 'gstlibxmlregistry.c' || echo './'`gstlibxmlregistry.c; \ then mv -f ".deps/libgstxmlregistry_la-gstlibxmlregistry.Tpo" ".deps/libgstxmlregistry_la-gstlibxmlregistry.Plo"; else rm -f ".deps/libgstxmlregistry_la-gstlibxmlregistry.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstxmlregistry_la-gstlibxmlregistry.lo -MD -MP -MF .deps/libgstxmlregistry_la-gstlibxmlregistry.Tpo -c gstlibxmlregistry.c -fPIC -DPIC -o .libs/libgstxmlregistry_la-gstlibxmlregistry.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstxmlregistry_la-gstlibxmlregistry.lo -MD -MP -MF .deps/libgstxmlregistry_la-gstlibxmlregistry.Tpo -c gstlibxmlregistry.c -o libgstxmlregistry_la-gstlibxmlregistry.o >/dev/null 2>&1 /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstxmlregistry.la libgstxmlregistry_la-gstlibxmlregistry.lo -lxml2 -lz -lm -pthread -Wl,--export-dynamic -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm ar cru .libs/libgstxmlregistry.a .libs/libgstxmlregistry_la-gstlibxmlregistry.o ranlib .libs/libgstxmlregistry.a creating libgstxmlregistry.la (cd .libs && rm -f libgstxmlregistry.la && ln -s ../libgstxmlregistry.la libgstxmlregistry.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/registries' Making all in . make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gst.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gst.Tpo" -c -o libgstreamer_0.8_la-gst.lo `test -f 'gst.c' || echo './'`gst.c; \ then mv -f ".deps/libgstreamer_0.8_la-gst.Tpo" ".deps/libgstreamer_0.8_la-gst.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gst.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstobject.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstobject.Tpo" -c -o libgstreamer_0.8_la-gstobject.lo `test -f 'gstobject.c' || echo './'`gstobject.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstobject.Tpo" ".deps/libgstreamer_0.8_la-gstobject.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstobject.Tpo"; exit 1; fi mkdir .libs mkdir .libs mkdir: cannot create directory `.libs': File exists gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gst.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gst.Tpo -c gst.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gst.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstobject.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstobject.Tpo -c gstobject.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstobject.o gstobject.c: In function 'gst_object_set_name_default': gstobject.c:446: warning: type-punning to incomplete type might break strict-aliasing rules gstobject.c:446: warning: dereferencing type-punned pointer will break strict-aliasing rules gstobject.c:457: warning: type-punning to incomplete type might break strict-aliasing rules gstobject.c:457: warning: dereferencing type-punned pointer will break strict-aliasing rules gst.c: In function 'init_post': gst.c:589: warning: statement with no effect gst.c:615: warning: statement with no effect gst.c:617: warning: statement with no effect gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gst.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gst.Tpo -c gst.c -o libgstreamer_0.8_la-gst.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstobject.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstobject.Tpo -c gstobject.c -o libgstreamer_0.8_la-gstobject.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstatomic.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstatomic.Tpo" -c -o libgstreamer_0.8_la-gstatomic.lo `test -f 'gstatomic.c' || echo './'`gstatomic.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstatomic.Tpo" ".deps/libgstreamer_0.8_la-gstatomic.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstatomic.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstbin.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstbin.Tpo" -c -o libgstreamer_0.8_la-gstbin.lo `test -f 'gstbin.c' || echo './'`gstbin.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstbin.Tpo" ".deps/libgstreamer_0.8_la-gstbin.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstbin.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstbin.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstbin.Tpo -c gstbin.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstbin.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstatomic.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstatomic.Tpo -c gstatomic.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstatomic.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstatomic.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstatomic.Tpo -c gstatomic.c -o libgstreamer_0.8_la-gstatomic.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstbuffer.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstbuffer.Tpo" -c -o libgstreamer_0.8_la-gstbuffer.lo `test -f 'gstbuffer.c' || echo './'`gstbuffer.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstbuffer.Tpo" ".deps/libgstreamer_0.8_la-gstbuffer.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstbuffer.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstbuffer.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstbuffer.Tpo -c gstbuffer.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstbuffer.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstbin.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstbin.Tpo -c gstbin.c -o libgstreamer_0.8_la-gstbin.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstbuffer.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstbuffer.Tpo -c gstbuffer.c -o libgstreamer_0.8_la-gstbuffer.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstcaps.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstcaps.Tpo" -c -o libgstreamer_0.8_la-gstcaps.lo `test -f 'gstcaps.c' || echo './'`gstcaps.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstcaps.Tpo" ".deps/libgstreamer_0.8_la-gstcaps.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstcaps.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstcaps.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstcaps.Tpo -c gstcaps.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstcaps.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstclock.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstclock.Tpo" -c -o libgstreamer_0.8_la-gstclock.lo `test -f 'gstclock.c' || echo './'`gstclock.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstclock.Tpo" ".deps/libgstreamer_0.8_la-gstclock.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstclock.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstclock.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstclock.Tpo -c gstclock.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstclock.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstcaps.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstcaps.Tpo -c gstcaps.c -o libgstreamer_0.8_la-gstcaps.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstclock.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstclock.Tpo -c gstclock.c -o libgstreamer_0.8_la-gstclock.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstcpu.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstcpu.Tpo" -c -o libgstreamer_0.8_la-gstcpu.lo `test -f 'gstcpu.c' || echo './'`gstcpu.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstcpu.Tpo" ".deps/libgstreamer_0.8_la-gstcpu.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstcpu.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstdata.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstdata.Tpo" -c -o libgstreamer_0.8_la-gstdata.lo `test -f 'gstdata.c' || echo './'`gstdata.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstdata.Tpo" ".deps/libgstreamer_0.8_la-gstdata.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstdata.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstcpu.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstcpu.Tpo -c gstcpu.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstcpu.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstdata.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstdata.Tpo -c gstdata.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstdata.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstcpu.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstcpu.Tpo -c gstcpu.c -o libgstreamer_0.8_la-gstcpu.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstdata.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstdata.Tpo -c gstdata.c -o libgstreamer_0.8_la-gstdata.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstelement.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstelement.Tpo" -c -o libgstreamer_0.8_la-gstelement.lo `test -f 'gstelement.c' || echo './'`gstelement.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstelement.Tpo" ".deps/libgstreamer_0.8_la-gstelement.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstelement.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstelementfactory.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstelementfactory.Tpo" -c -o libgstreamer_0.8_la-gstelementfactory.lo `test -f 'gstelementfactory.c' || echo './'`gstelementfactory.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstelementfactory.Tpo" ".deps/libgstreamer_0.8_la-gstelementfactory.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstelementfactory.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstelement.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstelement.Tpo -c gstelement.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstelement.o gstelement.c: In function 'gst_element_set_clock': gstelement.c:811: warning: dereferencing type-punned pointer will break strict-aliasing rules gstelement.c: In function 'gst_element_dispose': gstelement.c:3129: warning: dereferencing type-punned pointer will break strict-aliasing rules gstelement.c:3130: warning: dereferencing type-punned pointer will break strict-aliasing rules gstelement.c: In function 'gst_element_set_scheduler': gstelement.c:3324: warning: dereferencing type-punned pointer will break strict-aliasing rules gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstelementfactory.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstelementfactory.Tpo -c gstelementfactory.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstelementfactory.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstelementfactory.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstelementfactory.Tpo -c gstelementfactory.c -o libgstreamer_0.8_la-gstelementfactory.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsterror.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsterror.Tpo" -c -o libgstreamer_0.8_la-gsterror.lo `test -f 'gsterror.c' || echo './'`gsterror.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsterror.Tpo" ".deps/libgstreamer_0.8_la-gsterror.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsterror.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsterror.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsterror.Tpo -c gsterror.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsterror.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsterror.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsterror.Tpo -c gsterror.c -o libgstreamer_0.8_la-gsterror.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstevent.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstevent.Tpo" -c -o libgstreamer_0.8_la-gstevent.lo `test -f 'gstevent.c' || echo './'`gstevent.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstevent.Tpo" ".deps/libgstreamer_0.8_la-gstevent.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstevent.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstelement.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstelement.Tpo -c gstelement.c -o libgstreamer_0.8_la-gstelement.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstevent.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstevent.Tpo -c gstevent.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstevent.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstevent.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstevent.Tpo -c gstevent.c -o libgstreamer_0.8_la-gstevent.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstfilter.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstfilter.Tpo" -c -o libgstreamer_0.8_la-gstfilter.lo `test -f 'gstfilter.c' || echo './'`gstfilter.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstfilter.Tpo" ".deps/libgstreamer_0.8_la-gstfilter.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstfilter.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstfilter.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstfilter.Tpo -c gstfilter.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstfilter.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstfilter.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstfilter.Tpo -c gstfilter.c -o libgstreamer_0.8_la-gstfilter.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstformat.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstformat.Tpo" -c -o libgstreamer_0.8_la-gstformat.lo `test -f 'gstformat.c' || echo './'`gstformat.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstformat.Tpo" ".deps/libgstreamer_0.8_la-gstformat.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstformat.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstformat.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstformat.Tpo -c gstformat.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstformat.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstformat.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstformat.Tpo -c gstformat.c -o libgstreamer_0.8_la-gstformat.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstindex.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstindex.Tpo" -c -o libgstreamer_0.8_la-gstindex.lo `test -f 'gstindex.c' || echo './'`gstindex.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstindex.Tpo" ".deps/libgstreamer_0.8_la-gstindex.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstindex.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstinfo.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstinfo.Tpo" -c -o libgstreamer_0.8_la-gstinfo.lo `test -f 'gstinfo.c' || echo './'`gstinfo.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstinfo.Tpo" ".deps/libgstreamer_0.8_la-gstinfo.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstinfo.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstindex.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstindex.Tpo -c gstindex.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstindex.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstinfo.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstinfo.Tpo -c gstinfo.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstinfo.o gstinfo.c: In function 'gst_debug_add_log_function': gstinfo.c:586: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:586: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:589: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:589: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function 'gst_debug_remove_with_compare_func': gstinfo.c:618: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:618: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:631: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:631: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function 'gst_debug_reset_threshold': gstinfo.c:769: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:769: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:785: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:785: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function 'gst_debug_reset_all_thresholds': gstinfo.c:790: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:790: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:792: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:792: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function 'gst_debug_set_threshold_for_name': gstinfo.c:827: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:827: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:829: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:829: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:830: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:830: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:832: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:832: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function 'gst_debug_unset_threshold_for_name': gstinfo.c:850: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:850: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:864: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:864: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function '_gst_debug_category_new': gstinfo.c:889: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:889: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:891: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:891: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function 'gst_debug_category_free': gstinfo.c:909: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:909: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:911: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:911: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c: In function 'gst_debug_get_all_categories': gstinfo.c:1032: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:1032: warning: dereferencing type-punned pointer will break strict-aliasing rules gstinfo.c:1034: warning: type-punning to incomplete type might break strict-aliasing rules gstinfo.c:1034: warning: dereferencing type-punned pointer will break strict-aliasing rules gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstindex.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstindex.Tpo -c gstindex.c -o libgstreamer_0.8_la-gstindex.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstinfo.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstinfo.Tpo -c gstinfo.c -o libgstreamer_0.8_la-gstinfo.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstinterface.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstinterface.Tpo" -c -o libgstreamer_0.8_la-gstinterface.lo `test -f 'gstinterface.c' || echo './'`gstinterface.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstinterface.Tpo" ".deps/libgstreamer_0.8_la-gstinterface.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstinterface.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstmemchunk.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstmemchunk.Tpo" -c -o libgstreamer_0.8_la-gstmemchunk.lo `test -f 'gstmemchunk.c' || echo './'`gstmemchunk.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstmemchunk.Tpo" ".deps/libgstreamer_0.8_la-gstmemchunk.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstmemchunk.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstinterface.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstinterface.Tpo -c gstinterface.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstinterface.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstinterface.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstinterface.Tpo -c gstinterface.c -o libgstreamer_0.8_la-gstinterface.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstmemchunk.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstmemchunk.Tpo -c gstmemchunk.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstmemchunk.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpad.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstpad.Tpo" -c -o libgstreamer_0.8_la-gstpad.lo `test -f 'gstpad.c' || echo './'`gstpad.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstpad.Tpo" ".deps/libgstreamer_0.8_la-gstpad.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstpad.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstmemchunk.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstmemchunk.Tpo -c gstmemchunk.c -o libgstreamer_0.8_la-gstmemchunk.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpad.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstpad.Tpo -c gstpad.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstpad.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstchildproxy.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstchildproxy.Tpo" -c -o libgstreamer_0.8_la-gstchildproxy.lo `test -f 'gstchildproxy.c' || echo './'`gstchildproxy.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstchildproxy.Tpo" ".deps/libgstreamer_0.8_la-gstchildproxy.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstchildproxy.Tpo"; exit 1; fi gstpad.c: In function 'gst_pad_set_pad_template': gstpad.c:1971: warning: dereferencing type-punned pointer will break strict-aliasing rules gstpad.c: In function 'gst_pad_event_default_dispatch': gstpad.c:4104: warning: value computed is not used gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstchildproxy.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstchildproxy.Tpo -c gstchildproxy.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstchildproxy.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstchildproxy.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstchildproxy.Tpo -c gstchildproxy.c -o libgstreamer_0.8_la-gstchildproxy.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpipeline.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstpipeline.Tpo" -c -o libgstreamer_0.8_la-gstpipeline.lo `test -f 'gstpipeline.c' || echo './'`gstpipeline.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstpipeline.Tpo" ".deps/libgstreamer_0.8_la-gstpipeline.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstpipeline.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpipeline.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstpipeline.Tpo -c gstpipeline.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstpipeline.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpipeline.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstpipeline.Tpo -c gstpipeline.c -o libgstreamer_0.8_la-gstpipeline.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstplugin.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstplugin.Tpo" -c -o libgstreamer_0.8_la-gstplugin.lo `test -f 'gstplugin.c' || echo './'`gstplugin.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstplugin.Tpo" ".deps/libgstreamer_0.8_la-gstplugin.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstplugin.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstplugin.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstplugin.Tpo -c gstplugin.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstplugin.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstplugin.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstplugin.Tpo -c gstplugin.c -o libgstreamer_0.8_la-gstplugin.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpad.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstpad.Tpo -c gstpad.c -o libgstreamer_0.8_la-gstpad.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpluginfeature.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstpluginfeature.Tpo" -c -o libgstreamer_0.8_la-gstpluginfeature.lo `test -f 'gstpluginfeature.c' || echo './'`gstpluginfeature.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstpluginfeature.Tpo" ".deps/libgstreamer_0.8_la-gstpluginfeature.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstpluginfeature.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpluginfeature.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstpluginfeature.Tpo -c gstpluginfeature.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstpluginfeature.o gstpluginfeature.c: In function 'gst_plugin_feature_ensure_loaded': gstpluginfeature.c:100: warning: type-punning to incomplete type might break strict-aliasing rules gstpluginfeature.c:100: warning: dereferencing type-punned pointer will break strict-aliasing rules gstpluginfeature.c:110: warning: type-punning to incomplete type might break strict-aliasing rules gstpluginfeature.c:110: warning: dereferencing type-punned pointer will break strict-aliasing rules gstpluginfeature.c:114: warning: type-punning to incomplete type might break strict-aliasing rules gstpluginfeature.c:114: warning: dereferencing type-punned pointer will break strict-aliasing rules gstpluginfeature.c:123: warning: type-punning to incomplete type might break strict-aliasing rules gstpluginfeature.c:123: warning: dereferencing type-punned pointer will break strict-aliasing rules gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstpluginfeature.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstpluginfeature.Tpo -c gstpluginfeature.c -o libgstreamer_0.8_la-gstpluginfeature.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstprobe.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstprobe.Tpo" -c -o libgstreamer_0.8_la-gstprobe.lo `test -f 'gstprobe.c' || echo './'`gstprobe.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstprobe.Tpo" ".deps/libgstreamer_0.8_la-gstprobe.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstprobe.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstprobe.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstprobe.Tpo -c gstprobe.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstprobe.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstprobe.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstprobe.Tpo -c gstprobe.c -o libgstreamer_0.8_la-gstprobe.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstqueue.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstqueue.Tpo" -c -o libgstreamer_0.8_la-gstqueue.lo `test -f 'gstqueue.c' || echo './'`gstqueue.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstqueue.Tpo" ".deps/libgstreamer_0.8_la-gstqueue.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstqueue.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstqueue.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstqueue.Tpo -c gstqueue.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstqueue.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstquery.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstquery.Tpo" -c -o libgstreamer_0.8_la-gstquery.lo `test -f 'gstquery.c' || echo './'`gstquery.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstquery.Tpo" ".deps/libgstreamer_0.8_la-gstquery.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstquery.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstquery.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstquery.Tpo -c gstquery.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstquery.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstqueue.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstqueue.Tpo -c gstqueue.c -o libgstreamer_0.8_la-gstqueue.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstquery.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstquery.Tpo -c gstquery.c -o libgstreamer_0.8_la-gstquery.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstscheduler.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstscheduler.Tpo" -c -o libgstreamer_0.8_la-gstscheduler.lo `test -f 'gstscheduler.c' || echo './'`gstscheduler.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstscheduler.Tpo" ".deps/libgstreamer_0.8_la-gstscheduler.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstscheduler.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstscheduler.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstscheduler.Tpo -c gstscheduler.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstscheduler.o gstscheduler.c: In function 'gst_scheduler_dispose': gstscheduler.c:98: warning: dereferencing type-punned pointer will break strict-aliasing rules gstscheduler.c:99: warning: dereferencing type-punned pointer will break strict-aliasing rules gstscheduler.c: In function 'gst_scheduler_use_clock': gstscheduler.c:625: warning: dereferencing type-punned pointer will break strict-aliasing rules gstscheduler.c: In function 'gst_scheduler_set_clock': gstscheduler.c:651: warning: dereferencing type-punned pointer will break strict-aliasing rules gstscheduler.c: In function 'gst_scheduler_auto_clock': gstscheduler.c:689: warning: dereferencing type-punned pointer will break strict-aliasing rules if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gststructure.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gststructure.Tpo" -c -o libgstreamer_0.8_la-gststructure.lo `test -f 'gststructure.c' || echo './'`gststructure.c; \ then mv -f ".deps/libgstreamer_0.8_la-gststructure.Tpo" ".deps/libgstreamer_0.8_la-gststructure.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gststructure.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gststructure.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gststructure.Tpo -c gststructure.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gststructure.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstscheduler.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstscheduler.Tpo -c gstscheduler.c -o libgstreamer_0.8_la-gstscheduler.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstsystemclock.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstsystemclock.Tpo" -c -o libgstreamer_0.8_la-gstsystemclock.lo `test -f 'gstsystemclock.c' || echo './'`gstsystemclock.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstsystemclock.Tpo" ".deps/libgstreamer_0.8_la-gstsystemclock.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstsystemclock.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gststructure.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gststructure.Tpo -c gststructure.c -o libgstreamer_0.8_la-gststructure.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstsystemclock.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstsystemclock.Tpo -c gstsystemclock.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstsystemclock.o gstsystemclock.c: In function 'gst_system_clock_obtain': gstsystemclock.c:134: warning: type-punning to incomplete type might break strict-aliasing rules gstsystemclock.c:134: warning: dereferencing type-punned pointer will break strict-aliasing rules gstsystemclock.c:137: warning: type-punning to incomplete type might break strict-aliasing rules gstsystemclock.c:137: warning: dereferencing type-punned pointer will break strict-aliasing rules gstsystemclock.c:156: warning: type-punning to incomplete type might break strict-aliasing rules gstsystemclock.c:156: warning: dereferencing type-punned pointer will break strict-aliasing rules gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstsystemclock.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstsystemclock.Tpo -c gstsystemclock.c -o libgstreamer_0.8_la-gstsystemclock.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttag.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsttag.Tpo" -c -o libgstreamer_0.8_la-gsttag.lo `test -f 'gsttag.c' || echo './'`gsttag.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsttag.Tpo" ".deps/libgstreamer_0.8_la-gsttag.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsttag.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttaginterface.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsttaginterface.Tpo" -c -o libgstreamer_0.8_la-gsttaginterface.lo `test -f 'gsttaginterface.c' || echo './'`gsttaginterface.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsttaginterface.Tpo" ".deps/libgstreamer_0.8_la-gsttaginterface.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsttaginterface.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttag.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttag.Tpo -c gsttag.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsttag.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttaginterface.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttaginterface.Tpo -c gsttaginterface.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsttaginterface.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttaginterface.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttaginterface.Tpo -c gsttaginterface.c -o libgstreamer_0.8_la-gsttaginterface.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstthread.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstthread.Tpo" -c -o libgstreamer_0.8_la-gstthread.lo `test -f 'gstthread.c' || echo './'`gstthread.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstthread.Tpo" ".deps/libgstreamer_0.8_la-gstthread.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstthread.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstthread.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstthread.Tpo -c gstthread.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstthread.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttag.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttag.Tpo -c gsttag.c -o libgstreamer_0.8_la-gsttag.o >/dev/null 2>&1 gstthread.c: In function 'gst_thread_dispose': gstthread.c:236: warning: dereferencing type-punned pointer will break strict-aliasing rules gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstthread.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstthread.Tpo -c gstthread.c -o libgstreamer_0.8_la-gstthread.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttrace.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsttrace.Tpo" -c -o libgstreamer_0.8_la-gsttrace.lo `test -f 'gsttrace.c' || echo './'`gsttrace.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsttrace.Tpo" ".deps/libgstreamer_0.8_la-gsttrace.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsttrace.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttrace.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttrace.Tpo -c gsttrace.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsttrace.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttrashstack.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsttrashstack.Tpo" -c -o libgstreamer_0.8_la-gsttrashstack.lo `test -f 'gsttrashstack.c' || echo './'`gsttrashstack.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsttrashstack.Tpo" ".deps/libgstreamer_0.8_la-gsttrashstack.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsttrashstack.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttrace.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttrace.Tpo -c gsttrace.c -o libgstreamer_0.8_la-gsttrace.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttrashstack.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttrashstack.Tpo -c gsttrashstack.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsttrashstack.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttypefind.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsttypefind.Tpo" -c -o libgstreamer_0.8_la-gsttypefind.lo `test -f 'gsttypefind.c' || echo './'`gsttypefind.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsttypefind.Tpo" ".deps/libgstreamer_0.8_la-gsttypefind.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsttypefind.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttrashstack.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttrashstack.Tpo -c gsttrashstack.c -o libgstreamer_0.8_la-gsttrashstack.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsturi.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsturi.Tpo" -c -o libgstreamer_0.8_la-gsturi.lo `test -f 'gsturi.c' || echo './'`gsturi.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsturi.Tpo" ".deps/libgstreamer_0.8_la-gsturi.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsturi.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttypefind.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttypefind.Tpo -c gsttypefind.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsttypefind.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsturi.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsturi.Tpo -c gsturi.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsturi.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsttypefind.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsttypefind.Tpo -c gsttypefind.c -o libgstreamer_0.8_la-gsttypefind.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsturitype.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gsturitype.Tpo" -c -o libgstreamer_0.8_la-gsturitype.lo `test -f 'gsturitype.c' || echo './'`gsturitype.c; \ then mv -f ".deps/libgstreamer_0.8_la-gsturitype.Tpo" ".deps/libgstreamer_0.8_la-gsturitype.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gsturitype.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsturi.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsturi.Tpo -c gsturi.c -o libgstreamer_0.8_la-gsturi.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsturitype.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsturitype.Tpo -c gsturitype.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gsturitype.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstutils.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstutils.Tpo" -c -o libgstreamer_0.8_la-gstutils.lo `test -f 'gstutils.c' || echo './'`gstutils.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstutils.Tpo" ".deps/libgstreamer_0.8_la-gstutils.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstutils.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gsturitype.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gsturitype.Tpo -c gsturitype.c -o libgstreamer_0.8_la-gsturitype.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstvalue.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstvalue.Tpo" -c -o libgstreamer_0.8_la-gstvalue.lo `test -f 'gstvalue.c' || echo './'`gstvalue.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstvalue.Tpo" ".deps/libgstreamer_0.8_la-gstvalue.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstvalue.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstutils.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstutils.Tpo -c gstutils.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstutils.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstutils.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstutils.Tpo -c gstutils.c -o libgstreamer_0.8_la-gstutils.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstvalue.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstvalue.Tpo -c gstvalue.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstvalue.o if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstregistry.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstregistry.Tpo" -c -o libgstreamer_0.8_la-gstregistry.lo `test -f 'gstregistry.c' || echo './'`gstregistry.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstregistry.Tpo" ".deps/libgstreamer_0.8_la-gstregistry.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstregistry.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstregistry.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstregistry.Tpo -c gstregistry.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstregistry.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstregistry.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstregistry.Tpo -c gstregistry.c -o libgstreamer_0.8_la-gstregistry.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstregistrypool.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstregistrypool.Tpo" -c -o libgstreamer_0.8_la-gstregistrypool.lo `test -f 'gstregistrypool.c' || echo './'`gstregistrypool.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstregistrypool.Tpo" ".deps/libgstreamer_0.8_la-gstregistrypool.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstregistrypool.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstvalue.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstvalue.Tpo -c gstvalue.c -o libgstreamer_0.8_la-gstvalue.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstregistrypool.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstregistrypool.Tpo -c gstregistrypool.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstregistrypool.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstregistrypool.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstregistrypool.Tpo -c gstregistrypool.c -o libgstreamer_0.8_la-gstregistrypool.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstparse.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstparse.Tpo" -c -o libgstreamer_0.8_la-gstparse.lo `test -f 'gstparse.c' || echo './'`gstparse.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstparse.Tpo" ".deps/libgstreamer_0.8_la-gstparse.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstparse.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstparse.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstparse.Tpo -c gstparse.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstparse.o gstparse.c: In function 'gst_parse_launch': gstparse.c:133: warning: type-punning to incomplete type might break strict-aliasing rules gstparse.c:133: warning: dereferencing type-punned pointer will break strict-aliasing rules gstparse.c:135: warning: type-punning to incomplete type might break strict-aliasing rules gstparse.c:135: warning: dereferencing type-punned pointer will break strict-aliasing rules gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstparse.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstparse.Tpo -c gstparse.c -o libgstreamer_0.8_la-gstparse.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstxml.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstxml.Tpo" -c -o libgstreamer_0.8_la-gstxml.lo `test -f 'gstxml.c' || echo './'`gstxml.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstxml.Tpo" ".deps/libgstreamer_0.8_la-gstxml.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstxml.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstenumtypes.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstenumtypes.Tpo" -c -o libgstreamer_0.8_la-gstenumtypes.lo `test -f 'gstenumtypes.c' || echo './'`gstenumtypes.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstenumtypes.Tpo" ".deps/libgstreamer_0.8_la-gstenumtypes.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstenumtypes.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstxml.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstxml.Tpo -c gstxml.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstxml.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstenumtypes.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstenumtypes.Tpo -c gstenumtypes.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstenumtypes.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstxml.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstxml.Tpo -c gstxml.c -o libgstreamer_0.8_la-gstxml.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstenumtypes.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstenumtypes.Tpo -c gstenumtypes.c -o libgstreamer_0.8_la-gstenumtypes.o >/dev/null 2>&1 if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstmarshal.lo -MD -MP -MF ".deps/libgstreamer_0.8_la-gstmarshal.Tpo" -c -o libgstreamer_0.8_la-gstmarshal.lo `test -f 'gstmarshal.c' || echo './'`gstmarshal.c; \ then mv -f ".deps/libgstreamer_0.8_la-gstmarshal.Tpo" ".deps/libgstreamer_0.8_la-gstmarshal.Plo"; else rm -f ".deps/libgstreamer_0.8_la-gstmarshal.Tpo"; exit 1; fi if /bin/sh ../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\""0.8"\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libcothreads_la-cothreads.lo -MD -MP -MF ".deps/libcothreads_la-cothreads.Tpo" -c -o libcothreads_la-cothreads.lo `test -f 'cothreads.c' || echo './'`cothreads.c; \ then mv -f ".deps/libcothreads_la-cothreads.Tpo" ".deps/libcothreads_la-cothreads.Plo"; else rm -f ".deps/libcothreads_la-cothreads.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstmarshal.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstmarshal.Tpo -c gstmarshal.c -fPIC -DPIC -o .libs/libgstreamer_0.8_la-gstmarshal.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libcothreads_la-cothreads.lo -MD -MP -MF .deps/libcothreads_la-cothreads.Tpo -c cothreads.c -fPIC -DPIC -o .libs/libcothreads_la-cothreads.o gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstreamer_0.8_la-gstmarshal.lo -MD -MP -MF .deps/libgstreamer_0.8_la-gstmarshal.Tpo -c gstmarshal.c -o libgstreamer_0.8_la-gstmarshal.o >/dev/null 2>&1 /bin/sh ../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstreamer-0.8.la -rpath /usr/lib -version-info 5:0:4 -export-symbols-regex [_]*\(gst_\|Gst\|GST_\).* libgstreamer_0.8_la-gst.lo libgstreamer_0.8_la-gstobject.lo libgstreamer_0.8_la-gstatomic.lo libgstreamer_0.8_la-gstbin.lo libgstreamer_0.8_la-gstbuffer.lo libgstreamer_0.8_la-gstcaps.lo libgstreamer_0.8_la-gstclock.lo libgstreamer_0.8_la-gstcpu.lo libgstreamer_0.8_la-gstdata.lo libgstreamer_0.8_la-gstelement.lo libgstreamer_0.8_la-gstelementfactory.lo libgstreamer_0.8_la-gsterror.lo libgstreamer_0.8_la-gstevent.lo libgstreamer_0.8_la-gstfilter.lo libgstreamer_0.8_la-gstformat.lo libgstreamer_0.8_la-gstindex.lo libgstreamer_0.8_la-gstinfo.lo libgstreamer_0.8_la-gstinterface.lo libgstreamer_0.8_la-gstmemchunk.lo libgstreamer_0.8_la-gstpad.lo libgstreamer_0.8_la-gstchildproxy.lo libgstreamer_0.8_la-gstpipeline.lo libgstreamer_0.8_la-gstplugin.lo libgstreamer_0.8_la-gstpluginfeature.lo libgstreamer_0.8_la-gstprobe.lo libgstreamer_0.8_la-gstqueue.lo libgstreamer_0.8_la-gstquery.lo libgstreamer_0.8_la-gstscheduler.lo libgstreamer_0.8_la-gststructure.lo libgstreamer_0.8_la-gstsystemclock.lo libgstreamer_0.8_la-gsttag.lo libgstreamer_0.8_la-gsttaginterface.lo libgstreamer_0.8_la-gstthread.lo libgstreamer_0.8_la-gsttrace.lo libgstreamer_0.8_la-gsttrashstack.lo libgstreamer_0.8_la-gsttypefind.lo libgstreamer_0.8_la-gsturi.lo libgstreamer_0.8_la-gsturitype.lo libgstreamer_0.8_la-gstutils.lo libgstreamer_0.8_la-gstvalue.lo libgstreamer_0.8_la-gstregistry.lo libgstreamer_0.8_la-gstregistrypool.lo libgstreamer_0.8_la-gstparse.lo libgstreamer_0.8_la-gstxml.lo libgstreamer_0.8_la-gstenumtypes.lo libgstreamer_0.8_la-gstmarshal.lo -lxml2 -lz -lm -pthread -Wl,--export-dynamic -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm parse/libgstparse.la registries/libgstxmlregistry.la gcc -DHAVE_CONFIG_H -I. -I. -I.. -D_GNU_SOURCE -DHOSTCPU=\"i686\" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I.. -DGST_MAJORMINOR=\"0.8\" -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libcothreads_la-cothreads.lo -MD -MP -MF .deps/libcothreads_la-cothreads.Tpo -c cothreads.c -o libcothreads_la-cothreads.o >/dev/null 2>&1 /bin/sh ../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libcothreads.la libcothreads_la-cothreads.lo ar cru .libs/libcothreads.a .libs/libcothreads_la-cothreads.o ranlib .libs/libcothreads.a creating libcothreads.la (cd .libs && rm -f libcothreads.la && ln -s ../libcothreads.la libcothreads.la) generating symbol list for `libgstreamer-0.8.la' nm .libs/libgstreamer_0.8_la-gst.o .libs/libgstreamer_0.8_la-gstobject.o .libs/libgstreamer_0.8_la-gstatomic.o .libs/libgstreamer_0.8_la-gstbin.o .libs/libgstreamer_0.8_la-gstbuffer.o .libs/libgstreamer_0.8_la-gstcaps.o .libs/libgstreamer_0.8_la-gstclock.o .libs/libgstreamer_0.8_la-gstcpu.o .libs/libgstreamer_0.8_la-gstdata.o .libs/libgstreamer_0.8_la-gstelement.o .libs/libgstreamer_0.8_la-gstelementfactory.o .libs/libgstreamer_0.8_la-gsterror.o .libs/libgstreamer_0.8_la-gstevent.o .libs/libgstreamer_0.8_la-gstfilter.o .libs/libgstreamer_0.8_la-gstformat.o .libs/libgstreamer_0.8_la-gstindex.o .libs/libgstreamer_0.8_la-gstinfo.o .libs/libgstreamer_0.8_la-gstinterface.o .libs/libgstreamer_0.8_la-gstmemchunk.o .libs/libgstreamer_0.8_la-gstpad.o .libs/libgstreamer_0.8_la-gstchildproxy.o .libs/libgstreamer_0.8_la-gstpipeline.o .libs/libgstreamer_0.8_la-gstplugin.o .libs/libgstreamer_0.8_la-gstpluginfeature.o .libs/libgstreamer_0.8_la-gstprobe.o .libs/libgstreamer_0.8_la-gstqueue.o .libs/libgstreamer_0.8_la-gstquery.o .libs/libgstreamer_0.8_la-gstscheduler.o .libs/libgstreamer_0.8_la-gststructure.o .libs/libgstreamer_0.8_la-gstsystemclock.o .libs/libgstreamer_0.8_la-gsttag.o .libs/libgstreamer_0.8_la-gsttaginterface.o .libs/libgstreamer_0.8_la-gstthread.o .libs/libgstreamer_0.8_la-gsttrace.o .libs/libgstreamer_0.8_la-gsttrashstack.o .libs/libgstreamer_0.8_la-gsttypefind.o .libs/libgstreamer_0.8_la-gsturi.o .libs/libgstreamer_0.8_la-gsturitype.o .libs/libgstreamer_0.8_la-gstutils.o .libs/libgstreamer_0.8_la-gstvalue.o .libs/libgstreamer_0.8_la-gstregistry.o .libs/libgstreamer_0.8_la-gstregistrypool.o .libs/libgstreamer_0.8_la-gstparse.o .libs/libgstreamer_0.8_la-gstxml.o .libs/libgstreamer_0.8_la-gstenumtypes.o .libs/libgstreamer_0.8_la-gstmarshal.o parse/.libs/libgstparse.a registries/.libs/libgstxmlregistry.a | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstreamer-0.8.exp grep -E -e "[_]*(gst_|Gst|GST_).*" ".libs/libgstreamer-0.8.exp" > ".libs/libgstreamer-0.8.expT" mv -f ".libs/libgstreamer-0.8.expT" ".libs/libgstreamer-0.8.exp" echo "{ global:" > .libs/libgstreamer-0.8.ver cat .libs/libgstreamer-0.8.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstreamer-0.8.ver echo "local: *; };" >> .libs/libgstreamer-0.8.ver gcc -shared .libs/libgstreamer_0.8_la-gst.o .libs/libgstreamer_0.8_la-gstobject.o .libs/libgstreamer_0.8_la-gstatomic.o .libs/libgstreamer_0.8_la-gstbin.o .libs/libgstreamer_0.8_la-gstbuffer.o .libs/libgstreamer_0.8_la-gstcaps.o .libs/libgstreamer_0.8_la-gstclock.o .libs/libgstreamer_0.8_la-gstcpu.o .libs/libgstreamer_0.8_la-gstdata.o .libs/libgstreamer_0.8_la-gstelement.o .libs/libgstreamer_0.8_la-gstelementfactory.o .libs/libgstreamer_0.8_la-gsterror.o .libs/libgstreamer_0.8_la-gstevent.o .libs/libgstreamer_0.8_la-gstfilter.o .libs/libgstreamer_0.8_la-gstformat.o .libs/libgstreamer_0.8_la-gstindex.o .libs/libgstreamer_0.8_la-gstinfo.o .libs/libgstreamer_0.8_la-gstinterface.o .libs/libgstreamer_0.8_la-gstmemchunk.o .libs/libgstreamer_0.8_la-gstpad.o .libs/libgstreamer_0.8_la-gstchildproxy.o .libs/libgstreamer_0.8_la-gstpipeline.o .libs/libgstreamer_0.8_la-gstplugin.o .libs/libgstreamer_0.8_la-gstpluginfeature.o .libs/libgstreamer_0.8_la-gstprobe.o .libs/libgstreamer_0.8_la-gstqueue.o .libs/libgstreamer_0.8_la-gstquery.o .libs/libgstreamer_0.8_la-gstscheduler.o .libs/libgstreamer_0.8_la-gststructure.o .libs/libgstreamer_0.8_la-gstsystemclock.o .libs/libgstreamer_0.8_la-gsttag.o .libs/libgstreamer_0.8_la-gsttaginterface.o .libs/libgstreamer_0.8_la-gstthread.o .libs/libgstreamer_0.8_la-gsttrace.o .libs/libgstreamer_0.8_la-gsttrashstack.o .libs/libgstreamer_0.8_la-gsttypefind.o .libs/libgstreamer_0.8_la-gsturi.o .libs/libgstreamer_0.8_la-gsturitype.o .libs/libgstreamer_0.8_la-gstutils.o .libs/libgstreamer_0.8_la-gstvalue.o .libs/libgstreamer_0.8_la-gstregistry.o .libs/libgstreamer_0.8_la-gstregistrypool.o .libs/libgstreamer_0.8_la-gstparse.o .libs/libgstreamer_0.8_la-gstxml.o .libs/libgstreamer_0.8_la-gstenumtypes.o .libs/libgstreamer_0.8_la-gstmarshal.o -Wl,--whole-archive parse/.libs/libgstparse.a registries/.libs/libgstxmlregistry.a -Wl,--no-whole-archive -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm -m32 -march=i386 -mtune=pentium4 -pthread -Wl,--export-dynamic -Wl,-soname -Wl,libgstreamer-0.8.so.1 -Wl,-version-script -Wl,.libs/libgstreamer-0.8.ver -o .libs/libgstreamer-0.8.so.1.4.0 (cd .libs && rm -f libgstreamer-0.8.so.1 && ln -s libgstreamer-0.8.so.1.4.0 libgstreamer-0.8.so.1) (cd .libs && rm -f libgstreamer-0.8.so && ln -s libgstreamer-0.8.so.1.4.0 libgstreamer-0.8.so) rm -fr .libs/libgstreamer-0.8.lax mkdir .libs/libgstreamer-0.8.lax rm -fr .libs/libgstreamer-0.8.lax/libgstparse.a mkdir .libs/libgstreamer-0.8.lax/libgstparse.a (cd .libs/libgstreamer-0.8.lax/libgstparse.a && ar x /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/parse/.libs/libgstparse.a) rm -fr .libs/libgstreamer-0.8.lax/libgstxmlregistry.a mkdir .libs/libgstreamer-0.8.lax/libgstxmlregistry.a (cd .libs/libgstreamer-0.8.lax/libgstxmlregistry.a && ar x /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/registries/.libs/libgstxmlregistry.a) ar cru .libs/libgstreamer-0.8.a libgstreamer_0.8_la-gst.o libgstreamer_0.8_la-gstobject.o libgstreamer_0.8_la-gstatomic.o libgstreamer_0.8_la-gstbin.o libgstreamer_0.8_la-gstbuffer.o libgstreamer_0.8_la-gstcaps.o libgstreamer_0.8_la-gstclock.o libgstreamer_0.8_la-gstcpu.o libgstreamer_0.8_la-gstdata.o libgstreamer_0.8_la-gstelement.o libgstreamer_0.8_la-gstelementfactory.o libgstreamer_0.8_la-gsterror.o libgstreamer_0.8_la-gstevent.o libgstreamer_0.8_la-gstfilter.o libgstreamer_0.8_la-gstformat.o libgstreamer_0.8_la-gstindex.o libgstreamer_0.8_la-gstinfo.o libgstreamer_0.8_la-gstinterface.o libgstreamer_0.8_la-gstmemchunk.o libgstreamer_0.8_la-gstpad.o libgstreamer_0.8_la-gstchildproxy.o libgstreamer_0.8_la-gstpipeline.o libgstreamer_0.8_la-gstplugin.o libgstreamer_0.8_la-gstpluginfeature.o libgstreamer_0.8_la-gstprobe.o libgstreamer_0.8_la-gstqueue.o libgstreamer_0.8_la-gstquery.o libgstreamer_0.8_la-gstscheduler.o libgstreamer_0.8_la-gststructure.o libgstreamer_0.8_la-gstsystemclock.o libgstreamer_0.8_la-gsttag.o libgstreamer_0.8_la-gsttaginterface.o libgstreamer_0.8_la-gstthread.o libgstreamer_0.8_la-gsttrace.o libgstreamer_0.8_la-gsttrashstack.o libgstreamer_0.8_la-gsttypefind.o libgstreamer_0.8_la-gsturi.o libgstreamer_0.8_la-gsturitype.o libgstreamer_0.8_la-gstutils.o libgstreamer_0.8_la-gstvalue.o libgstreamer_0.8_la-gstregistry.o libgstreamer_0.8_la-gstregistrypool.o libgstreamer_0.8_la-gstparse.o libgstreamer_0.8_la-gstxml.o libgstreamer_0.8_la-gstenumtypes.o libgstreamer_0.8_la-gstmarshal.o .libs/libgstreamer-0.8.lax/libgstparse.a/libgstparse_la-lex._gst_parse_yy.o .libs/libgstreamer-0.8.lax/libgstparse.a/libgstparse_la-grammar.tab.o .libs/libgstreamer-0.8.lax/libgstxmlregistry.a/libgstxmlregistry_la-gstlibxmlregistry.o ranlib .libs/libgstreamer-0.8.a rm -fr .libs/libgstreamer-0.8.lax creating libgstreamer-0.8.la (cd .libs && rm -f libgstreamer-0.8.la && ln -s ../libgstreamer-0.8.la libgstreamer-0.8.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' Making all in autoplug make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/autoplug' if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstspider.lo -MD -MP -MF ".deps/libgstspider_la-gstspider.Tpo" -c -o libgstspider_la-gstspider.lo `test -f 'gstspider.c' || echo './'`gstspider.c; \ then mv -f ".deps/libgstspider_la-gstspider.Tpo" ".deps/libgstspider_la-gstspider.Plo"; else rm -f ".deps/libgstspider_la-gstspider.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstspideridentity.lo -MD -MP -MF ".deps/libgstspider_la-gstspideridentity.Tpo" -c -o libgstspider_la-gstspideridentity.lo `test -f 'gstspideridentity.c' || echo './'`gstspideridentity.c; \ then mv -f ".deps/libgstspider_la-gstspideridentity.Tpo" ".deps/libgstspider_la-gstspideridentity.Plo"; else rm -f ".deps/libgstspider_la-gstspideridentity.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstspideridentity.lo -MD -MP -MF .deps/libgstspider_la-gstspideridentity.Tpo -c gstspideridentity.c -fPIC -DPIC -o .libs/libgstspider_la-gstspideridentity.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstspider.lo -MD -MP -MF .deps/libgstspider_la-gstspider.Tpo -c gstspider.c -fPIC -DPIC -o .libs/libgstspider_la-gstspider.o gstspider.c: In function 'gst_spider_request_new_pad': gstspider.c:250: warning: dereferencing type-punned pointer will break strict-aliasing rules gstspider.c: In function 'gst_spider_identity_unplug': gstspider.c:532: warning: ignoring return value of 'g_list_delete_link', declared with attribute warn_unused_result gstspider.c: In function 'gst_spider_create_and_plug': gstspider.c:564: warning: ignoring return value of 'g_list_delete_link', declared with attribute warn_unused_result gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstspideridentity.lo -MD -MP -MF .deps/libgstspider_la-gstspideridentity.Tpo -c gstspideridentity.c -o libgstspider_la-gstspideridentity.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstspider.lo -MD -MP -MF .deps/libgstspider_la-gstspider.Tpo -c gstspider.c -o libgstspider_la-gstspider.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstsearchfuncs.lo -MD -MP -MF ".deps/libgstspider_la-gstsearchfuncs.Tpo" -c -o libgstspider_la-gstsearchfuncs.lo `test -f 'gstsearchfuncs.c' || echo './'`gstsearchfuncs.c; \ then mv -f ".deps/libgstspider_la-gstsearchfuncs.Tpo" ".deps/libgstspider_la-gstsearchfuncs.Plo"; else rm -f ".deps/libgstspider_la-gstsearchfuncs.Tpo"; exit 1; fi if gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT spidertest-spidertest.o -MD -MP -MF ".deps/spidertest-spidertest.Tpo" -c -o spidertest-spidertest.o `test -f 'spidertest.c' || echo './'`spidertest.c; \ then mv -f ".deps/spidertest-spidertest.Tpo" ".deps/spidertest-spidertest.Po"; else rm -f ".deps/spidertest-spidertest.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstsearchfuncs.lo -MD -MP -MF .deps/libgstspider_la-gstsearchfuncs.Tpo -c gstsearchfuncs.c -fPIC -DPIC -o .libs/libgstspider_la-gstsearchfuncs.o /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o spidertest spidertest-spidertest.o ../../gst/libgstreamer-0.8.la gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/spidertest spidertest-spidertest.o ../../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstspider_la-gstsearchfuncs.lo -MD -MP -MF .deps/libgstspider_la-gstsearchfuncs.Tpo -c gstsearchfuncs.c -o libgstspider_la-gstsearchfuncs.o >/dev/null 2>&1 creating spidertest /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstspider.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstspider_la-gstspider.lo libgstspider_la-gstspideridentity.lo libgstspider_la-gstsearchfuncs.lo ../../gst/libgstreamer-0.8.la generating symbol list for `libgstspider.la' nm .libs/libgstspider_la-gstspider.o .libs/libgstspider_la-gstspideridentity.o .libs/libgstspider_la-gstsearchfuncs.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstspider.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstspider.exp" > ".libs/libgstspider.expT" mv -f ".libs/libgstspider.expT" ".libs/libgstspider.exp" echo "{ global:" > .libs/libgstspider.ver cat .libs/libgstspider.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstspider.ver echo "local: *; };" >> .libs/libgstspider.ver gcc -shared .libs/libgstspider_la-gstspider.o .libs/libgstspider_la-gstspideridentity.o .libs/libgstspider_la-gstsearchfuncs.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstspider.so -Wl,-version-script -Wl,.libs/libgstspider.ver -o .libs/libgstspider.so ar cru .libs/libgstspider.a libgstspider_la-gstspider.o libgstspider_la-gstspideridentity.o libgstspider_la-gstsearchfuncs.o ranlib .libs/libgstspider.a creating libgstspider.la (cd .libs && rm -f libgstspider.la && ln -s ../libgstspider.la libgstspider.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/autoplug' Making all in elements make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/elements' if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstaggregator.lo -MD -MP -MF ".deps/libgstelements_la-gstaggregator.Tpo" -c -o libgstelements_la-gstaggregator.lo `test -f 'gstaggregator.c' || echo './'`gstaggregator.c; \ then mv -f ".deps/libgstelements_la-gstaggregator.Tpo" ".deps/libgstelements_la-gstaggregator.Plo"; else rm -f ".deps/libgstelements_la-gstaggregator.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstbufferstore.lo -MD -MP -MF ".deps/libgstelements_la-gstbufferstore.Tpo" -c -o libgstelements_la-gstbufferstore.lo `test -f 'gstbufferstore.c' || echo './'`gstbufferstore.c; \ then mv -f ".deps/libgstelements_la-gstbufferstore.Tpo" ".deps/libgstelements_la-gstbufferstore.Plo"; else rm -f ".deps/libgstelements_la-gstbufferstore.Tpo"; exit 1; fi mkdir .libs mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstaggregator.lo -MD -MP -MF .deps/libgstelements_la-gstaggregator.Tpo -c gstaggregator.c -fPIC -DPIC -o .libs/libgstelements_la-gstaggregator.o mkdir: cannot create directory `.libs': File exists gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstbufferstore.lo -MD -MP -MF .deps/libgstelements_la-gstbufferstore.Tpo -c gstbufferstore.c -fPIC -DPIC -o .libs/libgstelements_la-gstbufferstore.o gstbufferstore.c: In function 'gst_buffer_store_add_buffer_func': gstbufferstore.c:236: warning: ignoring return value of 'g_list_append', declared with attribute warn_unused_result gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstaggregator.lo -MD -MP -MF .deps/libgstelements_la-gstaggregator.Tpo -c gstaggregator.c -o libgstelements_la-gstaggregator.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstbufferstore.lo -MD -MP -MF .deps/libgstelements_la-gstbufferstore.Tpo -c gstbufferstore.c -o libgstelements_la-gstbufferstore.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstelements.lo -MD -MP -MF ".deps/libgstelements_la-gstelements.Tpo" -c -o libgstelements_la-gstelements.lo `test -f 'gstelements.c' || echo './'`gstelements.c; \ then mv -f ".deps/libgstelements_la-gstelements.Tpo" ".deps/libgstelements_la-gstelements.Plo"; else rm -f ".deps/libgstelements_la-gstelements.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfakesink.lo -MD -MP -MF ".deps/libgstelements_la-gstfakesink.Tpo" -c -o libgstelements_la-gstfakesink.lo `test -f 'gstfakesink.c' || echo './'`gstfakesink.c; \ then mv -f ".deps/libgstelements_la-gstfakesink.Tpo" ".deps/libgstelements_la-gstfakesink.Plo"; else rm -f ".deps/libgstelements_la-gstfakesink.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstelements.lo -MD -MP -MF .deps/libgstelements_la-gstelements.Tpo -c gstelements.c -fPIC -DPIC -o .libs/libgstelements_la-gstelements.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfakesink.lo -MD -MP -MF .deps/libgstelements_la-gstfakesink.Tpo -c gstfakesink.c -fPIC -DPIC -o .libs/libgstelements_la-gstfakesink.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstelements.lo -MD -MP -MF .deps/libgstelements_la-gstelements.Tpo -c gstelements.c -o libgstelements_la-gstelements.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfakesrc.lo -MD -MP -MF ".deps/libgstelements_la-gstfakesrc.Tpo" -c -o libgstelements_la-gstfakesrc.lo `test -f 'gstfakesrc.c' || echo './'`gstfakesrc.c; \ then mv -f ".deps/libgstelements_la-gstfakesrc.Tpo" ".deps/libgstelements_la-gstfakesrc.Plo"; else rm -f ".deps/libgstelements_la-gstfakesrc.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfakesink.lo -MD -MP -MF .deps/libgstelements_la-gstfakesink.Tpo -c gstfakesink.c -o libgstelements_la-gstfakesink.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfakesrc.lo -MD -MP -MF .deps/libgstelements_la-gstfakesrc.Tpo -c gstfakesrc.c -fPIC -DPIC -o .libs/libgstelements_la-gstfakesrc.o if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfilesink.lo -MD -MP -MF ".deps/libgstelements_la-gstfilesink.Tpo" -c -o libgstelements_la-gstfilesink.lo `test -f 'gstfilesink.c' || echo './'`gstfilesink.c; \ then mv -f ".deps/libgstelements_la-gstfilesink.Tpo" ".deps/libgstelements_la-gstfilesink.Plo"; else rm -f ".deps/libgstelements_la-gstfilesink.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfilesink.lo -MD -MP -MF .deps/libgstelements_la-gstfilesink.Tpo -c gstfilesink.c -fPIC -DPIC -o .libs/libgstelements_la-gstfilesink.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfakesrc.lo -MD -MP -MF .deps/libgstelements_la-gstfakesrc.Tpo -c gstfakesrc.c -o libgstelements_la-gstfakesrc.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfilesink.lo -MD -MP -MF .deps/libgstelements_la-gstfilesink.Tpo -c gstfilesink.c -o libgstelements_la-gstfilesink.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfilesrc.lo -MD -MP -MF ".deps/libgstelements_la-gstfilesrc.Tpo" -c -o libgstelements_la-gstfilesrc.lo `test -f 'gstfilesrc.c' || echo './'`gstfilesrc.c; \ then mv -f ".deps/libgstelements_la-gstfilesrc.Tpo" ".deps/libgstelements_la-gstfilesrc.Plo"; else rm -f ".deps/libgstelements_la-gstfilesrc.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfdsink.lo -MD -MP -MF ".deps/libgstelements_la-gstfdsink.Tpo" -c -o libgstelements_la-gstfdsink.lo `test -f 'gstfdsink.c' || echo './'`gstfdsink.c; \ then mv -f ".deps/libgstelements_la-gstfdsink.Tpo" ".deps/libgstelements_la-gstfdsink.Plo"; else rm -f ".deps/libgstelements_la-gstfdsink.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfilesrc.lo -MD -MP -MF .deps/libgstelements_la-gstfilesrc.Tpo -c gstfilesrc.c -fPIC -DPIC -o .libs/libgstelements_la-gstfilesrc.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfdsink.lo -MD -MP -MF .deps/libgstelements_la-gstfdsink.Tpo -c gstfdsink.c -fPIC -DPIC -o .libs/libgstelements_la-gstfdsink.o gstfdsink.c: In function 'gst_fdsink_chain': gstfdsink.c:129: warning: ignoring return value of 'write', declared with attribute warn_unused_result gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfdsink.lo -MD -MP -MF .deps/libgstelements_la-gstfdsink.Tpo -c gstfdsink.c -o libgstelements_la-gstfdsink.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfdsrc.lo -MD -MP -MF ".deps/libgstelements_la-gstfdsrc.Tpo" -c -o libgstelements_la-gstfdsrc.lo `test -f 'gstfdsrc.c' || echo './'`gstfdsrc.c; \ then mv -f ".deps/libgstelements_la-gstfdsrc.Tpo" ".deps/libgstelements_la-gstfdsrc.Plo"; else rm -f ".deps/libgstelements_la-gstfdsrc.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfilesrc.lo -MD -MP -MF .deps/libgstelements_la-gstfilesrc.Tpo -c gstfilesrc.c -o libgstelements_la-gstfilesrc.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfdsrc.lo -MD -MP -MF .deps/libgstelements_la-gstfdsrc.Tpo -c gstfdsrc.c -fPIC -DPIC -o .libs/libgstelements_la-gstfdsrc.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstfdsrc.lo -MD -MP -MF .deps/libgstelements_la-gstfdsrc.Tpo -c gstfdsrc.c -o libgstelements_la-gstfdsrc.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstidentity.lo -MD -MP -MF ".deps/libgstelements_la-gstidentity.Tpo" -c -o libgstelements_la-gstidentity.lo `test -f 'gstidentity.c' || echo './'`gstidentity.c; \ then mv -f ".deps/libgstelements_la-gstidentity.Tpo" ".deps/libgstelements_la-gstidentity.Plo"; else rm -f ".deps/libgstelements_la-gstidentity.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstmd5sink.lo -MD -MP -MF ".deps/libgstelements_la-gstmd5sink.Tpo" -c -o libgstelements_la-gstmd5sink.lo `test -f 'gstmd5sink.c' || echo './'`gstmd5sink.c; \ then mv -f ".deps/libgstelements_la-gstmd5sink.Tpo" ".deps/libgstelements_la-gstmd5sink.Plo"; else rm -f ".deps/libgstelements_la-gstmd5sink.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstidentity.lo -MD -MP -MF .deps/libgstelements_la-gstidentity.Tpo -c gstidentity.c -fPIC -DPIC -o .libs/libgstelements_la-gstidentity.o gstidentity.c: In function 'gst_identity_set_clock': gstidentity.c:239: warning: dereferencing type-punned pointer will break strict-aliasing rules gstidentity.c: In function 'gst_identity_chain': gstidentity.c:361: warning: value computed is not used gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstmd5sink.lo -MD -MP -MF .deps/libgstelements_la-gstmd5sink.Tpo -c gstmd5sink.c -fPIC -DPIC -o .libs/libgstelements_la-gstmd5sink.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstidentity.lo -MD -MP -MF .deps/libgstelements_la-gstidentity.Tpo -c gstidentity.c -o libgstelements_la-gstidentity.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstmd5sink.lo -MD -MP -MF .deps/libgstelements_la-gstmd5sink.Tpo -c gstmd5sink.c -o libgstelements_la-gstmd5sink.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstmultifilesrc.lo -MD -MP -MF ".deps/libgstelements_la-gstmultifilesrc.Tpo" -c -o libgstelements_la-gstmultifilesrc.lo `test -f 'gstmultifilesrc.c' || echo './'`gstmultifilesrc.c; \ then mv -f ".deps/libgstelements_la-gstmultifilesrc.Tpo" ".deps/libgstelements_la-gstmultifilesrc.Plo"; else rm -f ".deps/libgstelements_la-gstmultifilesrc.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstpipefilter.lo -MD -MP -MF ".deps/libgstelements_la-gstpipefilter.Tpo" -c -o libgstelements_la-gstpipefilter.lo `test -f 'gstpipefilter.c' || echo './'`gstpipefilter.c; \ then mv -f ".deps/libgstelements_la-gstpipefilter.Tpo" ".deps/libgstelements_la-gstpipefilter.Plo"; else rm -f ".deps/libgstelements_la-gstpipefilter.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstmultifilesrc.lo -MD -MP -MF .deps/libgstelements_la-gstmultifilesrc.Tpo -c gstmultifilesrc.c -fPIC -DPIC -o .libs/libgstelements_la-gstmultifilesrc.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstpipefilter.lo -MD -MP -MF .deps/libgstelements_la-gstpipefilter.Tpo -c gstpipefilter.c -fPIC -DPIC -o .libs/libgstelements_la-gstpipefilter.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstmultifilesrc.lo -MD -MP -MF .deps/libgstelements_la-gstmultifilesrc.Tpo -c gstmultifilesrc.c -o libgstelements_la-gstmultifilesrc.o >/dev/null 2>&1 gstpipefilter.c: In function 'gst_pipefilter_open_file': gstpipefilter.c:289: warning: ignoring return value of 'pipe', declared with attribute warn_unused_result gstpipefilter.c:290: warning: ignoring return value of 'pipe', declared with attribute warn_unused_result gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstpipefilter.lo -MD -MP -MF .deps/libgstelements_la-gstpipefilter.Tpo -c gstpipefilter.c -o libgstelements_la-gstpipefilter.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstshaper.lo -MD -MP -MF ".deps/libgstelements_la-gstshaper.Tpo" -c -o libgstelements_la-gstshaper.lo `test -f 'gstshaper.c' || echo './'`gstshaper.c; \ then mv -f ".deps/libgstelements_la-gstshaper.Tpo" ".deps/libgstelements_la-gstshaper.Plo"; else rm -f ".deps/libgstelements_la-gstshaper.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstshaper.lo -MD -MP -MF .deps/libgstelements_la-gstshaper.Tpo -c gstshaper.c -fPIC -DPIC -o .libs/libgstelements_la-gstshaper.o if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gststatistics.lo -MD -MP -MF ".deps/libgstelements_la-gststatistics.Tpo" -c -o libgstelements_la-gststatistics.lo `test -f 'gststatistics.c' || echo './'`gststatistics.c; \ then mv -f ".deps/libgstelements_la-gststatistics.Tpo" ".deps/libgstelements_la-gststatistics.Plo"; else rm -f ".deps/libgstelements_la-gststatistics.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gststatistics.lo -MD -MP -MF .deps/libgstelements_la-gststatistics.Tpo -c gststatistics.c -fPIC -DPIC -o .libs/libgstelements_la-gststatistics.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gstshaper.lo -MD -MP -MF .deps/libgstelements_la-gstshaper.Tpo -c gstshaper.c -o libgstelements_la-gstshaper.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gststatistics.lo -MD -MP -MF .deps/libgstelements_la-gststatistics.Tpo -c gststatistics.c -o libgstelements_la-gststatistics.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gsttee.lo -MD -MP -MF ".deps/libgstelements_la-gsttee.Tpo" -c -o libgstelements_la-gsttee.lo `test -f 'gsttee.c' || echo './'`gsttee.c; \ then mv -f ".deps/libgstelements_la-gsttee.Tpo" ".deps/libgstelements_la-gsttee.Plo"; else rm -f ".deps/libgstelements_la-gsttee.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gsttee.lo -MD -MP -MF .deps/libgstelements_la-gsttee.Tpo -c gsttee.c -fPIC -DPIC -o .libs/libgstelements_la-gsttee.o if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gsttypefindelement.lo -MD -MP -MF ".deps/libgstelements_la-gsttypefindelement.Tpo" -c -o libgstelements_la-gsttypefindelement.lo `test -f 'gsttypefindelement.c' || echo './'`gsttypefindelement.c; \ then mv -f ".deps/libgstelements_la-gsttypefindelement.Tpo" ".deps/libgstelements_la-gsttypefindelement.Plo"; else rm -f ".deps/libgstelements_la-gsttypefindelement.Tpo"; exit 1; fi gsttee.c: In function 'gst_tee_chain': gsttee.c:336: warning: value computed is not used gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gsttypefindelement.lo -MD -MP -MF .deps/libgstelements_la-gsttypefindelement.Tpo -c gsttypefindelement.c -fPIC -DPIC -o .libs/libgstelements_la-gsttypefindelement.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gsttee.lo -MD -MP -MF .deps/libgstelements_la-gsttee.Tpo -c gsttee.c -o libgstelements_la-gsttee.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstelements_la-gsttypefindelement.lo -MD -MP -MF .deps/libgstelements_la-gsttypefindelement.Tpo -c gsttypefindelement.c -o libgstelements_la-gsttypefindelement.o >/dev/null 2>&1 /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstelements.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstelements_la-gstaggregator.lo libgstelements_la-gstbufferstore.lo libgstelements_la-gstelements.lo libgstelements_la-gstfakesink.lo libgstelements_la-gstfakesrc.lo libgstelements_la-gstfilesink.lo libgstelements_la-gstfilesrc.lo libgstelements_la-gstfdsink.lo libgstelements_la-gstfdsrc.lo libgstelements_la-gstidentity.lo libgstelements_la-gstmd5sink.lo libgstelements_la-gstmultifilesrc.lo libgstelements_la-gstpipefilter.lo libgstelements_la-gstshaper.lo libgstelements_la-gststatistics.lo libgstelements_la-gsttee.lo libgstelements_la-gsttypefindelement.lo ../../gst/libgstreamer-0.8.la generating symbol list for `libgstelements.la' nm .libs/libgstelements_la-gstaggregator.o .libs/libgstelements_la-gstbufferstore.o .libs/libgstelements_la-gstelements.o .libs/libgstelements_la-gstfakesink.o .libs/libgstelements_la-gstfakesrc.o .libs/libgstelements_la-gstfilesink.o .libs/libgstelements_la-gstfilesrc.o .libs/libgstelements_la-gstfdsink.o .libs/libgstelements_la-gstfdsrc.o .libs/libgstelements_la-gstidentity.o .libs/libgstelements_la-gstmd5sink.o .libs/libgstelements_la-gstmultifilesrc.o .libs/libgstelements_la-gstpipefilter.o .libs/libgstelements_la-gstshaper.o .libs/libgstelements_la-gststatistics.o .libs/libgstelements_la-gsttee.o .libs/libgstelements_la-gsttypefindelement.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstelements.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstelements.exp" > ".libs/libgstelements.expT" mv -f ".libs/libgstelements.expT" ".libs/libgstelements.exp" echo "{ global:" > .libs/libgstelements.ver cat .libs/libgstelements.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstelements.ver echo "local: *; };" >> .libs/libgstelements.ver gcc -shared .libs/libgstelements_la-gstaggregator.o .libs/libgstelements_la-gstbufferstore.o .libs/libgstelements_la-gstelements.o .libs/libgstelements_la-gstfakesink.o .libs/libgstelements_la-gstfakesrc.o .libs/libgstelements_la-gstfilesink.o .libs/libgstelements_la-gstfilesrc.o .libs/libgstelements_la-gstfdsink.o .libs/libgstelements_la-gstfdsrc.o .libs/libgstelements_la-gstidentity.o .libs/libgstelements_la-gstmd5sink.o .libs/libgstelements_la-gstmultifilesrc.o .libs/libgstelements_la-gstpipefilter.o .libs/libgstelements_la-gstshaper.o .libs/libgstelements_la-gststatistics.o .libs/libgstelements_la-gsttee.o .libs/libgstelements_la-gsttypefindelement.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstelements.so -Wl,-version-script -Wl,.libs/libgstelements.ver -o .libs/libgstelements.so ar cru .libs/libgstelements.a libgstelements_la-gstaggregator.o libgstelements_la-gstbufferstore.o libgstelements_la-gstelements.o libgstelements_la-gstfakesink.o libgstelements_la-gstfakesrc.o libgstelements_la-gstfilesink.o libgstelements_la-gstfilesrc.o libgstelements_la-gstfdsink.o libgstelements_la-gstfdsrc.o libgstelements_la-gstidentity.o libgstelements_la-gstmd5sink.o libgstelements_la-gstmultifilesrc.o libgstelements_la-gstpipefilter.o libgstelements_la-gstshaper.o libgstelements_la-gststatistics.o libgstelements_la-gsttee.o libgstelements_la-gsttypefindelement.o ranlib .libs/libgstelements.a creating libgstelements.la (cd .libs && rm -f libgstelements.la && ln -s ../libgstelements.la libgstelements.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/elements' Making all in schedulers make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers' if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbasicomegascheduler_la-gstbasicscheduler.lo -MD -MP -MF ".deps/libgstbasicomegascheduler_la-gstbasicscheduler.Tpo" -c -o libgstbasicomegascheduler_la-gstbasicscheduler.lo `test -f 'gstbasicscheduler.c' || echo './'`gstbasicscheduler.c; \ then mv -f ".deps/libgstbasicomegascheduler_la-gstbasicscheduler.Tpo" ".deps/libgstbasicomegascheduler_la-gstbasicscheduler.Plo"; else rm -f ".deps/libgstbasicomegascheduler_la-gstbasicscheduler.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstentryomegascheduler_la-entryscheduler.lo -MD -MP -MF ".deps/libgstentryomegascheduler_la-entryscheduler.Tpo" -c -o libgstentryomegascheduler_la-entryscheduler.lo `test -f 'entryscheduler.c' || echo './'`entryscheduler.c; \ then mv -f ".deps/libgstentryomegascheduler_la-entryscheduler.Tpo" ".deps/libgstentryomegascheduler_la-entryscheduler.Plo"; else rm -f ".deps/libgstentryomegascheduler_la-entryscheduler.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstentryomegascheduler_la-entryscheduler.lo -MD -MP -MF .deps/libgstentryomegascheduler_la-entryscheduler.Tpo -c entryscheduler.c -fPIC -DPIC -o .libs/libgstentryomegascheduler_la-entryscheduler.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbasicomegascheduler_la-gstbasicscheduler.lo -MD -MP -MF .deps/libgstbasicomegascheduler_la-gstbasicscheduler.Tpo -c gstbasicscheduler.c -fPIC -DPIC -o .libs/libgstbasicomegascheduler_la-gstbasicscheduler.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstentryomegascheduler_la-entryscheduler.lo -MD -MP -MF .deps/libgstentryomegascheduler_la-entryscheduler.Tpo -c entryscheduler.c -o libgstentryomegascheduler_la-entryscheduler.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbasicomegascheduler_la-gstbasicscheduler.lo -MD -MP -MF .deps/libgstbasicomegascheduler_la-gstbasicscheduler.Tpo -c gstbasicscheduler.c -o libgstbasicomegascheduler_la-gstbasicscheduler.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -DUSE_COTHREADS -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptomegascheduler_la-gstoptimalscheduler.lo -MD -MP -MF ".deps/libgstoptomegascheduler_la-gstoptimalscheduler.Tpo" -c -o libgstoptomegascheduler_la-gstoptimalscheduler.lo `test -f 'gstoptimalscheduler.c' || echo './'`gstoptimalscheduler.c; \ then mv -f ".deps/libgstoptomegascheduler_la-gstoptimalscheduler.Tpo" ".deps/libgstoptomegascheduler_la-gstoptimalscheduler.Plo"; else rm -f ".deps/libgstoptomegascheduler_la-gstoptimalscheduler.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -DUSE_COTHREADS -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptomegascheduler_la-gstoptimalscheduler.lo -MD -MP -MF .deps/libgstoptomegascheduler_la-gstoptimalscheduler.Tpo -c gstoptimalscheduler.c -fPIC -DPIC -o .libs/libgstoptomegascheduler_la-gstoptimalscheduler.o if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbasicgthreadscheduler_la-gstbasicscheduler.lo -MD -MP -MF ".deps/libgstbasicgthreadscheduler_la-gstbasicscheduler.Tpo" -c -o libgstbasicgthreadscheduler_la-gstbasicscheduler.lo `test -f 'gstbasicscheduler.c' || echo './'`gstbasicscheduler.c; \ then mv -f ".deps/libgstbasicgthreadscheduler_la-gstbasicscheduler.Tpo" ".deps/libgstbasicgthreadscheduler_la-gstbasicscheduler.Plo"; else rm -f ".deps/libgstbasicgthreadscheduler_la-gstbasicscheduler.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbasicgthreadscheduler_la-gstbasicscheduler.lo -MD -MP -MF .deps/libgstbasicgthreadscheduler_la-gstbasicscheduler.Tpo -c gstbasicscheduler.c -fPIC -DPIC -o .libs/libgstbasicgthreadscheduler_la-gstbasicscheduler.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_OMEGA -DUSE_COTHREADS -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptomegascheduler_la-gstoptimalscheduler.lo -MD -MP -MF .deps/libgstoptomegascheduler_la-gstoptimalscheduler.Tpo -c gstoptimalscheduler.c -o libgstoptomegascheduler_la-gstoptimalscheduler.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbasicgthreadscheduler_la-gstbasicscheduler.lo -MD -MP -MF .deps/libgstbasicgthreadscheduler_la-gstbasicscheduler.Tpo -c gstbasicscheduler.c -o libgstbasicgthreadscheduler_la-gstbasicscheduler.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstentrygthreadscheduler_la-entryscheduler.lo -MD -MP -MF ".deps/libgstentrygthreadscheduler_la-entryscheduler.Tpo" -c -o libgstentrygthreadscheduler_la-entryscheduler.lo `test -f 'entryscheduler.c' || echo './'`entryscheduler.c; \ then mv -f ".deps/libgstentrygthreadscheduler_la-entryscheduler.Tpo" ".deps/libgstentrygthreadscheduler_la-entryscheduler.Plo"; else rm -f ".deps/libgstentrygthreadscheduler_la-entryscheduler.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptscheduler_la-gstoptimalscheduler.lo -MD -MP -MF ".deps/libgstoptscheduler_la-gstoptimalscheduler.Tpo" -c -o libgstoptscheduler_la-gstoptimalscheduler.lo `test -f 'gstoptimalscheduler.c' || echo './'`gstoptimalscheduler.c; \ then mv -f ".deps/libgstoptscheduler_la-gstoptimalscheduler.Tpo" ".deps/libgstoptscheduler_la-gstoptimalscheduler.Plo"; else rm -f ".deps/libgstoptscheduler_la-gstoptimalscheduler.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstentrygthreadscheduler_la-entryscheduler.lo -MD -MP -MF .deps/libgstentrygthreadscheduler_la-entryscheduler.Tpo -c entryscheduler.c -fPIC -DPIC -o .libs/libgstentrygthreadscheduler_la-entryscheduler.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptscheduler_la-gstoptimalscheduler.lo -MD -MP -MF .deps/libgstoptscheduler_la-gstoptimalscheduler.Tpo -c gstoptimalscheduler.c -fPIC -DPIC -o .libs/libgstoptscheduler_la-gstoptimalscheduler.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstentrygthreadscheduler_la-entryscheduler.lo -MD -MP -MF .deps/libgstentrygthreadscheduler_la-entryscheduler.Tpo -c entryscheduler.c -o libgstentrygthreadscheduler_la-entryscheduler.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptscheduler_la-gstoptimalscheduler.lo -MD -MP -MF .deps/libgstoptscheduler_la-gstoptimalscheduler.Tpo -c gstoptimalscheduler.c -o libgstoptscheduler_la-gstoptimalscheduler.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -DUSE_COTHREADS -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptgthreadscheduler_la-gstoptimalscheduler.lo -MD -MP -MF ".deps/libgstoptgthreadscheduler_la-gstoptimalscheduler.Tpo" -c -o libgstoptgthreadscheduler_la-gstoptimalscheduler.lo `test -f 'gstoptimalscheduler.c' || echo './'`gstoptimalscheduler.c; \ then mv -f ".deps/libgstoptgthreadscheduler_la-gstoptimalscheduler.Tpo" ".deps/libgstoptgthreadscheduler_la-gstoptimalscheduler.Plo"; else rm -f ".deps/libgstoptgthreadscheduler_la-gstoptimalscheduler.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -DUSE_COTHREADS -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptgthreadscheduler_la-gstoptimalscheduler.lo -MD -MP -MF .deps/libgstoptgthreadscheduler_la-gstoptimalscheduler.Tpo -c gstoptimalscheduler.c -fPIC -DPIC -o .libs/libgstoptgthreadscheduler_la-gstoptimalscheduler.o if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstfairgthreadscheduler_la-fairscheduler.lo -MD -MP -MF ".deps/libgstfairgthreadscheduler_la-fairscheduler.Tpo" -c -o libgstfairgthreadscheduler_la-fairscheduler.lo `test -f 'fairscheduler.c' || echo './'`fairscheduler.c; \ then mv -f ".deps/libgstfairgthreadscheduler_la-fairscheduler.Tpo" ".deps/libgstfairgthreadscheduler_la-fairscheduler.Plo"; else rm -f ".deps/libgstfairgthreadscheduler_la-fairscheduler.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstfairgthreadscheduler_la-fairscheduler.lo -MD -MP -MF .deps/libgstfairgthreadscheduler_la-fairscheduler.Tpo -c fairscheduler.c -fPIC -DPIC -o .libs/libgstfairgthreadscheduler_la-fairscheduler.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -DUSE_COTHREADS -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstoptgthreadscheduler_la-gstoptimalscheduler.lo -MD -MP -MF .deps/libgstoptgthreadscheduler_la-gstoptimalscheduler.Tpo -c gstoptimalscheduler.c -o libgstoptgthreadscheduler_la-gstoptimalscheduler.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstfairgthreadscheduler_la-fairscheduler.lo -MD -MP -MF .deps/libgstfairgthreadscheduler_la-fairscheduler.Tpo -c fairscheduler.c -o libgstfairgthreadscheduler_la-fairscheduler.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstfairgthreadscheduler_la-faircothreads.lo -MD -MP -MF ".deps/libgstfairgthreadscheduler_la-faircothreads.Tpo" -c -o libgstfairgthreadscheduler_la-faircothreads.lo `test -f 'faircothreads.c' || echo './'`faircothreads.c; \ then mv -f ".deps/libgstfairgthreadscheduler_la-faircothreads.Tpo" ".deps/libgstfairgthreadscheduler_la-faircothreads.Plo"; else rm -f ".deps/libgstfairgthreadscheduler_la-faircothreads.Tpo"; exit 1; fi /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstbasicomegascheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstbasicomegascheduler_la-gstbasicscheduler.lo ../../gst/libgstreamer-0.8.la ../libcothreads.la gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstfairgthreadscheduler_la-faircothreads.lo -MD -MP -MF .deps/libgstfairgthreadscheduler_la-faircothreads.Tpo -c faircothreads.c -fPIC -DPIC -o .libs/libgstfairgthreadscheduler_la-faircothreads.o generating symbol list for `libgstbasicomegascheduler.la' nm .libs/libgstbasicomegascheduler_la-gstbasicscheduler.o ../.libs/libcothreads.a | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstbasicomegascheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstbasicomegascheduler.exp" > ".libs/libgstbasicomegascheduler.expT" mv -f ".libs/libgstbasicomegascheduler.expT" ".libs/libgstbasicomegascheduler.exp" echo "{ global:" > .libs/libgstbasicomegascheduler.ver cat .libs/libgstbasicomegascheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstbasicomegascheduler.ver echo "local: *; };" >> .libs/libgstbasicomegascheduler.ver gcc -shared .libs/libgstbasicomegascheduler_la-gstbasicscheduler.o -Wl,--whole-archive ../.libs/libcothreads.a -Wl,--no-whole-archive -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstbasicomegascheduler.so -Wl,-version-script -Wl,.libs/libgstbasicomegascheduler.ver -o .libs/libgstbasicomegascheduler.so rm -fr .libs/libgstbasicomegascheduler.lax mkdir .libs/libgstbasicomegascheduler.lax rm -fr .libs/libgstbasicomegascheduler.lax/libcothreads.a mkdir .libs/libgstbasicomegascheduler.lax/libcothreads.a (cd .libs/libgstbasicomegascheduler.lax/libcothreads.a && ar x /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers/../.libs/libcothreads.a) ar cru .libs/libgstbasicomegascheduler.a libgstbasicomegascheduler_la-gstbasicscheduler.o .libs/libgstbasicomegascheduler.lax/libcothreads.a/libcothreads_la-cothreads.o ranlib .libs/libgstbasicomegascheduler.a rm -fr .libs/libgstbasicomegascheduler.lax creating libgstbasicomegascheduler.la (cd .libs && rm -f libgstbasicomegascheduler.la && ln -s ../libgstbasicomegascheduler.la libgstbasicomegascheduler.la) /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstentryomegascheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstentryomegascheduler_la-entryscheduler.lo ../../gst/libgstreamer-0.8.la ../libcothreads.la gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -D_COTHREADS_GTHREAD -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstfairgthreadscheduler_la-faircothreads.lo -MD -MP -MF .deps/libgstfairgthreadscheduler_la-faircothreads.Tpo -c faircothreads.c -o libgstfairgthreadscheduler_la-faircothreads.o >/dev/null 2>&1 generating symbol list for `libgstentryomegascheduler.la' nm .libs/libgstentryomegascheduler_la-entryscheduler.o ../.libs/libcothreads.a | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstentryomegascheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstentryomegascheduler.exp" > ".libs/libgstentryomegascheduler.expT" mv -f ".libs/libgstentryomegascheduler.expT" ".libs/libgstentryomegascheduler.exp" echo "{ global:" > .libs/libgstentryomegascheduler.ver cat .libs/libgstentryomegascheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstentryomegascheduler.ver echo "local: *; };" >> .libs/libgstentryomegascheduler.ver gcc -shared .libs/libgstentryomegascheduler_la-entryscheduler.o -Wl,--whole-archive ../.libs/libcothreads.a -Wl,--no-whole-archive -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstentryomegascheduler.so -Wl,-version-script -Wl,.libs/libgstentryomegascheduler.ver -o .libs/libgstentryomegascheduler.so rm -fr .libs/libgstentryomegascheduler.lax mkdir .libs/libgstentryomegascheduler.lax rm -fr .libs/libgstentryomegascheduler.lax/libcothreads.a mkdir .libs/libgstentryomegascheduler.lax/libcothreads.a (cd .libs/libgstentryomegascheduler.lax/libcothreads.a && ar x /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers/../.libs/libcothreads.a) ar cru .libs/libgstentryomegascheduler.a libgstentryomegascheduler_la-entryscheduler.o .libs/libgstentryomegascheduler.lax/libcothreads.a/libcothreads_la-cothreads.o ranlib .libs/libgstentryomegascheduler.a rm -fr .libs/libgstentryomegascheduler.lax creating libgstentryomegascheduler.la (cd .libs && rm -f libgstentryomegascheduler.la && ln -s ../libgstentryomegascheduler.la libgstentryomegascheduler.la) /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstoptomegascheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstoptomegascheduler_la-gstoptimalscheduler.lo ../../gst/libgstreamer-0.8.la ../libcothreads.la /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstbasicgthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstbasicgthreadscheduler_la-gstbasicscheduler.lo ../../gst/libgstreamer-0.8.la generating symbol list for `libgstbasicgthreadscheduler.la' nm .libs/libgstbasicgthreadscheduler_la-gstbasicscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstbasicgthreadscheduler.exp generating symbol list for `libgstoptomegascheduler.la' grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstbasicgthreadscheduler.exp" > ".libs/libgstbasicgthreadscheduler.expT" mv -f ".libs/libgstbasicgthreadscheduler.expT" ".libs/libgstbasicgthreadscheduler.exp" nm .libs/libgstoptomegascheduler_la-gstoptimalscheduler.o ../.libs/libcothreads.a | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstoptomegascheduler.exp echo "{ global:" > .libs/libgstbasicgthreadscheduler.ver cat .libs/libgstbasicgthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstbasicgthreadscheduler.ver grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstoptomegascheduler.exp" > ".libs/libgstoptomegascheduler.expT" echo "local: *; };" >> .libs/libgstbasicgthreadscheduler.ver gcc -shared .libs/libgstbasicgthreadscheduler_la-gstbasicscheduler.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstbasicgthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstbasicgthreadscheduler.ver -o .libs/libgstbasicgthreadscheduler.so mv -f ".libs/libgstoptomegascheduler.expT" ".libs/libgstoptomegascheduler.exp" echo "{ global:" > .libs/libgstoptomegascheduler.ver cat .libs/libgstoptomegascheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstoptomegascheduler.ver echo "local: *; };" >> .libs/libgstoptomegascheduler.ver gcc -shared .libs/libgstoptomegascheduler_la-gstoptimalscheduler.o -Wl,--whole-archive ../.libs/libcothreads.a -Wl,--no-whole-archive -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstoptomegascheduler.so -Wl,-version-script -Wl,.libs/libgstoptomegascheduler.ver -o .libs/libgstoptomegascheduler.so ar cru .libs/libgstbasicgthreadscheduler.a libgstbasicgthreadscheduler_la-gstbasicscheduler.o ranlib .libs/libgstbasicgthreadscheduler.a creating libgstbasicgthreadscheduler.la rm -fr .libs/libgstoptomegascheduler.lax mkdir .libs/libgstoptomegascheduler.lax rm -fr .libs/libgstoptomegascheduler.lax/libcothreads.a mkdir .libs/libgstoptomegascheduler.lax/libcothreads.a (cd .libs/libgstoptomegascheduler.lax/libcothreads.a && ar x /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers/../.libs/libcothreads.a) (cd .libs && rm -f libgstbasicgthreadscheduler.la && ln -s ../libgstbasicgthreadscheduler.la libgstbasicgthreadscheduler.la) /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstentrygthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstentrygthreadscheduler_la-entryscheduler.lo ../../gst/libgstreamer-0.8.la ar cru .libs/libgstoptomegascheduler.a libgstoptomegascheduler_la-gstoptimalscheduler.o .libs/libgstoptomegascheduler.lax/libcothreads.a/libcothreads_la-cothreads.o ranlib .libs/libgstoptomegascheduler.a rm -fr .libs/libgstoptomegascheduler.lax creating libgstoptomegascheduler.la (cd .libs && rm -f libgstoptomegascheduler.la && ln -s ../libgstoptomegascheduler.la libgstoptomegascheduler.la) /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstoptscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstoptscheduler_la-gstoptimalscheduler.lo ../../gst/libgstreamer-0.8.la generating symbol list for `libgstentrygthreadscheduler.la' nm .libs/libgstentrygthreadscheduler_la-entryscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstentrygthreadscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstentrygthreadscheduler.exp" > ".libs/libgstentrygthreadscheduler.expT" mv -f ".libs/libgstentrygthreadscheduler.expT" ".libs/libgstentrygthreadscheduler.exp" echo "{ global:" > .libs/libgstentrygthreadscheduler.ver cat .libs/libgstentrygthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstentrygthreadscheduler.ver echo "local: *; };" >> .libs/libgstentrygthreadscheduler.ver gcc -shared .libs/libgstentrygthreadscheduler_la-entryscheduler.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstentrygthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstentrygthreadscheduler.ver -o .libs/libgstentrygthreadscheduler.so ar cru .libs/libgstentrygthreadscheduler.a libgstentrygthreadscheduler_la-entryscheduler.o ranlib .libs/libgstentrygthreadscheduler.a creating libgstentrygthreadscheduler.la (cd .libs && rm -f libgstentrygthreadscheduler.la && ln -s ../libgstentrygthreadscheduler.la libgstentrygthreadscheduler.la) /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstoptgthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstoptgthreadscheduler_la-gstoptimalscheduler.lo ../../gst/libgstreamer-0.8.la generating symbol list for `libgstoptscheduler.la' nm .libs/libgstoptscheduler_la-gstoptimalscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstoptscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstoptscheduler.exp" > ".libs/libgstoptscheduler.expT" mv -f ".libs/libgstoptscheduler.expT" ".libs/libgstoptscheduler.exp" echo "{ global:" > .libs/libgstoptscheduler.ver cat .libs/libgstoptscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstoptscheduler.ver echo "local: *; };" >> .libs/libgstoptscheduler.ver gcc -shared .libs/libgstoptscheduler_la-gstoptimalscheduler.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstoptscheduler.so -Wl,-version-script -Wl,.libs/libgstoptscheduler.ver -o .libs/libgstoptscheduler.so ar cru .libs/libgstoptscheduler.a libgstoptscheduler_la-gstoptimalscheduler.o ranlib .libs/libgstoptscheduler.a creating libgstoptscheduler.la (cd .libs && rm -f libgstoptscheduler.la && ln -s ../libgstoptscheduler.la libgstoptscheduler.la) /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstfairgthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstfairgthreadscheduler_la-fairscheduler.lo libgstfairgthreadscheduler_la-faircothreads.lo ../../gst/libgstreamer-0.8.la generating symbol list for `libgstoptgthreadscheduler.la' nm .libs/libgstoptgthreadscheduler_la-gstoptimalscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstoptgthreadscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstoptgthreadscheduler.exp" > ".libs/libgstoptgthreadscheduler.expT" mv -f ".libs/libgstoptgthreadscheduler.expT" ".libs/libgstoptgthreadscheduler.exp" echo "{ global:" > .libs/libgstoptgthreadscheduler.ver cat .libs/libgstoptgthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstoptgthreadscheduler.ver echo "local: *; };" >> .libs/libgstoptgthreadscheduler.ver gcc -shared .libs/libgstoptgthreadscheduler_la-gstoptimalscheduler.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstoptgthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstoptgthreadscheduler.ver -o .libs/libgstoptgthreadscheduler.so ar cru .libs/libgstoptgthreadscheduler.a libgstoptgthreadscheduler_la-gstoptimalscheduler.o ranlib .libs/libgstoptgthreadscheduler.a creating libgstoptgthreadscheduler.la (cd .libs && rm -f libgstoptgthreadscheduler.la && ln -s ../libgstoptgthreadscheduler.la libgstoptgthreadscheduler.la) generating symbol list for `libgstfairgthreadscheduler.la' nm .libs/libgstfairgthreadscheduler_la-fairscheduler.o .libs/libgstfairgthreadscheduler_la-faircothreads.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstfairgthreadscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstfairgthreadscheduler.exp" > ".libs/libgstfairgthreadscheduler.expT" mv -f ".libs/libgstfairgthreadscheduler.expT" ".libs/libgstfairgthreadscheduler.exp" echo "{ global:" > .libs/libgstfairgthreadscheduler.ver cat .libs/libgstfairgthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstfairgthreadscheduler.ver echo "local: *; };" >> .libs/libgstfairgthreadscheduler.ver gcc -shared .libs/libgstfairgthreadscheduler_la-fairscheduler.o .libs/libgstfairgthreadscheduler_la-faircothreads.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstfairgthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstfairgthreadscheduler.ver -o .libs/libgstfairgthreadscheduler.so ar cru .libs/libgstfairgthreadscheduler.a libgstfairgthreadscheduler_la-fairscheduler.o libgstfairgthreadscheduler_la-faircothreads.o ranlib .libs/libgstfairgthreadscheduler.a creating libgstfairgthreadscheduler.la (cd .libs && rm -f libgstfairgthreadscheduler.la && ln -s ../libgstfairgthreadscheduler.la libgstfairgthreadscheduler.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers' Making all in indexers make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/indexers' if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstindexers.lo -MD -MP -MF ".deps/libgstindexers_la-gstindexers.Tpo" -c -o libgstindexers_la-gstindexers.lo `test -f 'gstindexers.c' || echo './'`gstindexers.c; \ then mv -f ".deps/libgstindexers_la-gstindexers.Tpo" ".deps/libgstindexers_la-gstindexers.Plo"; else rm -f ".deps/libgstindexers_la-gstindexers.Tpo"; exit 1; fi if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstmemindex.lo -MD -MP -MF ".deps/libgstindexers_la-gstmemindex.Tpo" -c -o libgstindexers_la-gstmemindex.lo `test -f 'gstmemindex.c' || echo './'`gstmemindex.c; \ then mv -f ".deps/libgstindexers_la-gstmemindex.Tpo" ".deps/libgstindexers_la-gstmemindex.Plo"; else rm -f ".deps/libgstindexers_la-gstmemindex.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstmemindex.lo -MD -MP -MF .deps/libgstindexers_la-gstmemindex.Tpo -c gstmemindex.c -fPIC -DPIC -o .libs/libgstindexers_la-gstmemindex.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstindexers.lo -MD -MP -MF .deps/libgstindexers_la-gstindexers.Tpo -c gstindexers.c -fPIC -DPIC -o .libs/libgstindexers_la-gstindexers.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstindexers.lo -MD -MP -MF .deps/libgstindexers_la-gstindexers.Tpo -c gstindexers.c -o libgstindexers_la-gstindexers.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstmemindex.lo -MD -MP -MF .deps/libgstindexers_la-gstmemindex.Tpo -c gstmemindex.c -o libgstindexers_la-gstmemindex.o >/dev/null 2>&1 if /bin/sh ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstfileindex.lo -MD -MP -MF ".deps/libgstindexers_la-gstfileindex.Tpo" -c -o libgstindexers_la-gstfileindex.lo `test -f 'gstfileindex.c' || echo './'`gstfileindex.c; \ then mv -f ".deps/libgstindexers_la-gstfileindex.Tpo" ".deps/libgstindexers_la-gstfileindex.Plo"; else rm -f ".deps/libgstindexers_la-gstfileindex.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstfileindex.lo -MD -MP -MF .deps/libgstindexers_la-gstfileindex.Tpo -c gstfileindex.c -fPIC -DPIC -o .libs/libgstindexers_la-gstfileindex.o gcc -DHAVE_CONFIG_H -I. -I. -I../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstindexers_la-gstfileindex.lo -MD -MP -MF .deps/libgstindexers_la-gstfileindex.Tpo -c gstfileindex.c -o libgstindexers_la-gstfileindex.o >/dev/null 2>&1 /bin/sh ../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstindexers.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstindexers_la-gstindexers.lo libgstindexers_la-gstmemindex.lo libgstindexers_la-gstfileindex.lo ../../gst/libgstreamer-0.8.la generating symbol list for `libgstindexers.la' nm .libs/libgstindexers_la-gstindexers.o .libs/libgstindexers_la-gstmemindex.o .libs/libgstindexers_la-gstfileindex.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstindexers.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstindexers.exp" > ".libs/libgstindexers.expT" mv -f ".libs/libgstindexers.expT" ".libs/libgstindexers.exp" echo "{ global:" > .libs/libgstindexers.ver cat .libs/libgstindexers.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstindexers.ver echo "local: *; };" >> .libs/libgstindexers.ver gcc -shared .libs/libgstindexers_la-gstindexers.o .libs/libgstindexers_la-gstmemindex.o .libs/libgstindexers_la-gstfileindex.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstindexers.so -Wl,-version-script -Wl,.libs/libgstindexers.ver -o .libs/libgstindexers.so ar cru .libs/libgstindexers.a libgstindexers_la-gstindexers.o libgstindexers_la-gstmemindex.o libgstindexers_la-gstfileindex.o ranlib .libs/libgstindexers.a creating libgstindexers.la (cd .libs && rm -f libgstindexers.la && ln -s ../libgstindexers.la libgstindexers.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/indexers' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' Making all in libs make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' Making all in gst make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' Making all in bytestream make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/bytestream' if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-bytestream.lo -MD -MP -MF ".deps/libgstbytestream_la-bytestream.Tpo" -c -o libgstbytestream_la-bytestream.lo `test -f 'bytestream.c' || echo './'`bytestream.c; \ then mv -f ".deps/libgstbytestream_la-bytestream.Tpo" ".deps/libgstbytestream_la-bytestream.Plo"; else rm -f ".deps/libgstbytestream_la-bytestream.Tpo"; exit 1; fi if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-adapter.lo -MD -MP -MF ".deps/libgstbytestream_la-adapter.Tpo" -c -o libgstbytestream_la-adapter.lo `test -f 'adapter.c' || echo './'`adapter.c; \ then mv -f ".deps/libgstbytestream_la-adapter.Tpo" ".deps/libgstbytestream_la-adapter.Plo"; else rm -f ".deps/libgstbytestream_la-adapter.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-adapter.lo -MD -MP -MF .deps/libgstbytestream_la-adapter.Tpo -c adapter.c -fPIC -DPIC -o .libs/libgstbytestream_la-adapter.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-bytestream.lo -MD -MP -MF .deps/libgstbytestream_la-bytestream.Tpo -c bytestream.c -fPIC -DPIC -o .libs/libgstbytestream_la-bytestream.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-adapter.lo -MD -MP -MF .deps/libgstbytestream_la-adapter.Tpo -c adapter.c -o libgstbytestream_la-adapter.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-bytestream.lo -MD -MP -MF .deps/libgstbytestream_la-bytestream.Tpo -c bytestream.c -o libgstbytestream_la-bytestream.o >/dev/null 2>&1 if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-filepad.lo -MD -MP -MF ".deps/libgstbytestream_la-filepad.Tpo" -c -o libgstbytestream_la-filepad.lo `test -f 'filepad.c' || echo './'`filepad.c; \ then mv -f ".deps/libgstbytestream_la-filepad.Tpo" ".deps/libgstbytestream_la-filepad.Plo"; else rm -f ".deps/libgstbytestream_la-filepad.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-filepad.lo -MD -MP -MF .deps/libgstbytestream_la-filepad.Tpo -c filepad.c -fPIC -DPIC -o .libs/libgstbytestream_la-filepad.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstbytestream_la-filepad.lo -MD -MP -MF .deps/libgstbytestream_la-filepad.Tpo -c filepad.c -o libgstbytestream_la-filepad.o >/dev/null 2>&1 /bin/sh ../../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstbytestream.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstbytestream_la-bytestream.lo libgstbytestream_la-adapter.lo libgstbytestream_la-filepad.lo generating symbol list for `libgstbytestream.la' nm .libs/libgstbytestream_la-bytestream.o .libs/libgstbytestream_la-adapter.o .libs/libgstbytestream_la-filepad.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstbytestream.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstbytestream.exp" > ".libs/libgstbytestream.expT" mv -f ".libs/libgstbytestream.expT" ".libs/libgstbytestream.exp" echo "{ global:" > .libs/libgstbytestream.ver cat .libs/libgstbytestream.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstbytestream.ver echo "local: *; };" >> .libs/libgstbytestream.ver gcc -shared .libs/libgstbytestream_la-bytestream.o .libs/libgstbytestream_la-adapter.o .libs/libgstbytestream_la-filepad.o -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstbytestream.so -Wl,-version-script -Wl,.libs/libgstbytestream.ver -o .libs/libgstbytestream.so ar cru .libs/libgstbytestream.a libgstbytestream_la-bytestream.o libgstbytestream_la-adapter.o libgstbytestream_la-filepad.o ranlib .libs/libgstbytestream.a creating libgstbytestream.la (cd .libs && rm -f libgstbytestream.la && ln -s ../libgstbytestream.la libgstbytestream.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/bytestream' Making all in control make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/control' if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-control.lo -MD -MP -MF ".deps/libgstcontrol_0.8_la-control.Tpo" -c -o libgstcontrol_0.8_la-control.lo `test -f 'control.c' || echo './'`control.c; \ then mv -f ".deps/libgstcontrol_0.8_la-control.Tpo" ".deps/libgstcontrol_0.8_la-control.Plo"; else rm -f ".deps/libgstcontrol_0.8_la-control.Tpo"; exit 1; fi if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparammanager.lo -MD -MP -MF ".deps/libgstcontrol_0.8_la-dparammanager.Tpo" -c -o libgstcontrol_0.8_la-dparammanager.lo `test -f 'dparammanager.c' || echo './'`dparammanager.c; \ then mv -f ".deps/libgstcontrol_0.8_la-dparammanager.Tpo" ".deps/libgstcontrol_0.8_la-dparammanager.Plo"; else rm -f ".deps/libgstcontrol_0.8_la-dparammanager.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparammanager.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dparammanager.Tpo -c dparammanager.c -fPIC -DPIC -o .libs/libgstcontrol_0.8_la-dparammanager.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-control.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-control.Tpo -c control.c -fPIC -DPIC -o .libs/libgstcontrol_0.8_la-control.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-control.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-control.Tpo -c control.c -o libgstcontrol_0.8_la-control.o >/dev/null 2>&1 if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparam.lo -MD -MP -MF ".deps/libgstcontrol_0.8_la-dparam.Tpo" -c -o libgstcontrol_0.8_la-dparam.lo `test -f 'dparam.c' || echo './'`dparam.c; \ then mv -f ".deps/libgstcontrol_0.8_la-dparam.Tpo" ".deps/libgstcontrol_0.8_la-dparam.Plo"; else rm -f ".deps/libgstcontrol_0.8_la-dparam.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparam.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dparam.Tpo -c dparam.c -fPIC -DPIC -o .libs/libgstcontrol_0.8_la-dparam.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparammanager.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dparammanager.Tpo -c dparammanager.c -o libgstcontrol_0.8_la-dparammanager.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparam.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dparam.Tpo -c dparam.c -o libgstcontrol_0.8_la-dparam.o >/dev/null 2>&1 if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparam_smooth.lo -MD -MP -MF ".deps/libgstcontrol_0.8_la-dparam_smooth.Tpo" -c -o libgstcontrol_0.8_la-dparam_smooth.lo `test -f 'dparam_smooth.c' || echo './'`dparam_smooth.c; \ then mv -f ".deps/libgstcontrol_0.8_la-dparam_smooth.Tpo" ".deps/libgstcontrol_0.8_la-dparam_smooth.Plo"; else rm -f ".deps/libgstcontrol_0.8_la-dparam_smooth.Tpo"; exit 1; fi if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-unitconvert.lo -MD -MP -MF ".deps/libgstcontrol_0.8_la-unitconvert.Tpo" -c -o libgstcontrol_0.8_la-unitconvert.lo `test -f 'unitconvert.c' || echo './'`unitconvert.c; \ then mv -f ".deps/libgstcontrol_0.8_la-unitconvert.Tpo" ".deps/libgstcontrol_0.8_la-unitconvert.Plo"; else rm -f ".deps/libgstcontrol_0.8_la-unitconvert.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparam_smooth.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dparam_smooth.Tpo -c dparam_smooth.c -fPIC -DPIC -o .libs/libgstcontrol_0.8_la-dparam_smooth.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-unitconvert.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-unitconvert.Tpo -c unitconvert.c -fPIC -DPIC -o .libs/libgstcontrol_0.8_la-unitconvert.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dparam_smooth.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dparam_smooth.Tpo -c dparam_smooth.c -o libgstcontrol_0.8_la-dparam_smooth.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-unitconvert.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-unitconvert.Tpo -c unitconvert.c -o libgstcontrol_0.8_la-unitconvert.o >/dev/null 2>&1 if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dplinearinterp.lo -MD -MP -MF ".deps/libgstcontrol_0.8_la-dplinearinterp.Tpo" -c -o libgstcontrol_0.8_la-dplinearinterp.lo `test -f 'dplinearinterp.c' || echo './'`dplinearinterp.c; \ then mv -f ".deps/libgstcontrol_0.8_la-dplinearinterp.Tpo" ".deps/libgstcontrol_0.8_la-dplinearinterp.Plo"; else rm -f ".deps/libgstcontrol_0.8_la-dplinearinterp.Tpo"; exit 1; fi gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dplinearinterp.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dplinearinterp.Tpo -c dplinearinterp.c -fPIC -DPIC -o .libs/libgstcontrol_0.8_la-dplinearinterp.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstcontrol_0.8_la-dplinearinterp.lo -MD -MP -MF .deps/libgstcontrol_0.8_la-dplinearinterp.Tpo -c dplinearinterp.c -o libgstcontrol_0.8_la-dplinearinterp.o >/dev/null 2>&1 /bin/sh ../../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstcontrol-0.8.la -rpath /usr/lib -version-info 5:0:4 -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstcontrol_0.8_la-control.lo libgstcontrol_0.8_la-dparammanager.lo libgstcontrol_0.8_la-dparam.lo libgstcontrol_0.8_la-dparam_smooth.lo libgstcontrol_0.8_la-unitconvert.lo libgstcontrol_0.8_la-dplinearinterp.lo ../../../gst/libgstreamer-0.8.la -lm generating symbol list for `libgstcontrol-0.8.la' nm .libs/libgstcontrol_0.8_la-control.o .libs/libgstcontrol_0.8_la-dparammanager.o .libs/libgstcontrol_0.8_la-dparam.o .libs/libgstcontrol_0.8_la-dparam_smooth.o .libs/libgstcontrol_0.8_la-unitconvert.o .libs/libgstcontrol_0.8_la-dplinearinterp.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstcontrol-0.8.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstcontrol-0.8.exp" > ".libs/libgstcontrol-0.8.expT" mv -f ".libs/libgstcontrol-0.8.expT" ".libs/libgstcontrol-0.8.exp" echo "{ global:" > .libs/libgstcontrol-0.8.ver cat .libs/libgstcontrol-0.8.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstcontrol-0.8.ver echo "local: *; };" >> .libs/libgstcontrol-0.8.ver gcc -shared .libs/libgstcontrol_0.8_la-control.o .libs/libgstcontrol_0.8_la-dparammanager.o .libs/libgstcontrol_0.8_la-dparam.o .libs/libgstcontrol_0.8_la-dparam_smooth.o .libs/libgstcontrol_0.8_la-unitconvert.o .libs/libgstcontrol_0.8_la-dplinearinterp.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../../gst/.libs/libgstreamer-0.8.so -lm -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstcontrol-0.8.so.1 -Wl,-version-script -Wl,.libs/libgstcontrol-0.8.ver -o .libs/libgstcontrol-0.8.so.1.4.0 (cd .libs && rm -f libgstcontrol-0.8.so.1 && ln -s libgstcontrol-0.8.so.1.4.0 libgstcontrol-0.8.so.1) (cd .libs && rm -f libgstcontrol-0.8.so && ln -s libgstcontrol-0.8.so.1.4.0 libgstcontrol-0.8.so) ar cru .libs/libgstcontrol-0.8.a libgstcontrol_0.8_la-control.o libgstcontrol_0.8_la-dparammanager.o libgstcontrol_0.8_la-dparam.o libgstcontrol_0.8_la-dparam_smooth.o libgstcontrol_0.8_la-unitconvert.o libgstcontrol_0.8_la-dplinearinterp.o ranlib .libs/libgstcontrol-0.8.a creating libgstcontrol-0.8.la (cd .libs && rm -f libgstcontrol-0.8.la && ln -s ../libgstcontrol-0.8.la libgstcontrol-0.8.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/control' Making all in dataprotocol make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/dataprotocol' if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -DGST_ENABLE_NEW -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstdataprotocol_la-dataprotocol.lo -MD -MP -MF ".deps/libgstdataprotocol_la-dataprotocol.Tpo" -c -o libgstdataprotocol_la-dataprotocol.lo `test -f 'dataprotocol.c' || echo './'`dataprotocol.c; \ then mv -f ".deps/libgstdataprotocol_la-dataprotocol.Tpo" ".deps/libgstdataprotocol_la-dataprotocol.Plo"; else rm -f ".deps/libgstdataprotocol_la-dataprotocol.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -DGST_ENABLE_NEW -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstdataprotocol_la-dataprotocol.lo -MD -MP -MF .deps/libgstdataprotocol_la-dataprotocol.Tpo -c dataprotocol.c -fPIC -DPIC -o .libs/libgstdataprotocol_la-dataprotocol.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -I../../../libs -DGST_ENABLE_NEW -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstdataprotocol_la-dataprotocol.lo -MD -MP -MF .deps/libgstdataprotocol_la-dataprotocol.Tpo -c dataprotocol.c -o libgstdataprotocol_la-dataprotocol.o >/dev/null 2>&1 /bin/sh ../../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstdataprotocol.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstdataprotocol_la-dataprotocol.lo ../../../gst/libgstreamer-0.8.la generating symbol list for `libgstdataprotocol.la' nm .libs/libgstdataprotocol_la-dataprotocol.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstdataprotocol.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstdataprotocol.exp" > ".libs/libgstdataprotocol.expT" mv -f ".libs/libgstdataprotocol.expT" ".libs/libgstdataprotocol.exp" echo "{ global:" > .libs/libgstdataprotocol.ver cat .libs/libgstdataprotocol.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstdataprotocol.ver echo "local: *; };" >> .libs/libgstdataprotocol.ver gcc -shared .libs/libgstdataprotocol_la-dataprotocol.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstdataprotocol.so -Wl,-version-script -Wl,.libs/libgstdataprotocol.ver -o .libs/libgstdataprotocol.so ar cru .libs/libgstdataprotocol.a libgstdataprotocol_la-dataprotocol.o ranlib .libs/libgstdataprotocol.a creating libgstdataprotocol.la (cd .libs && rm -f libgstdataprotocol.la && ln -s ../libgstdataprotocol.la libgstdataprotocol.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/dataprotocol' Making all in getbits make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/getbits' if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -funroll-all-loops -finline-functions -ffast-math -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstgetbits_la-getbits.lo -MD -MP -MF ".deps/libgstgetbits_la-getbits.Tpo" -c -o libgstgetbits_la-getbits.lo `test -f 'getbits.c' || echo './'`getbits.c; \ then mv -f ".deps/libgstgetbits_la-getbits.Tpo" ".deps/libgstgetbits_la-getbits.Plo"; else rm -f ".deps/libgstgetbits_la-getbits.Tpo"; exit 1; fi if /bin/sh ../../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -funroll-all-loops -finline-functions -ffast-math -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstgetbits_la-gstgetbits_generic.lo -MD -MP -MF ".deps/libgstgetbits_la-gstgetbits_generic.Tpo" -c -o libgstgetbits_la-gstgetbits_generic.lo `test -f 'gstgetbits_generic.c' || echo './'`gstgetbits_generic.c; \ then mv -f ".deps/libgstgetbits_la-gstgetbits_generic.Tpo" ".deps/libgstgetbits_la-gstgetbits_generic.Plo"; else rm -f ".deps/libgstgetbits_la-gstgetbits_generic.Tpo"; exit 1; fi mkdir .libs gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -funroll-all-loops -finline-functions -ffast-math -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstgetbits_la-getbits.lo -MD -MP -MF .deps/libgstgetbits_la-getbits.Tpo -c getbits.c -fPIC -DPIC -o .libs/libgstgetbits_la-getbits.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -funroll-all-loops -finline-functions -ffast-math -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstgetbits_la-gstgetbits_generic.lo -MD -MP -MF .deps/libgstgetbits_la-gstgetbits_generic.Tpo -c gstgetbits_generic.c -fPIC -DPIC -o .libs/libgstgetbits_la-gstgetbits_generic.o gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -funroll-all-loops -finline-functions -ffast-math -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstgetbits_la-getbits.lo -MD -MP -MF .deps/libgstgetbits_la-getbits.Tpo -c getbits.c -o libgstgetbits_la-getbits.o >/dev/null 2>&1 gcc -DHAVE_CONFIG_H -I. -I. -I../../.. -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../../libs -I../../.. -funroll-all-loops -finline-functions -ffast-math -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT libgstgetbits_la-gstgetbits_generic.lo -MD -MP -MF .deps/libgstgetbits_la-gstgetbits_generic.Tpo -c gstgetbits_generic.c -o libgstgetbits_la-gstgetbits_generic.o >/dev/null 2>&1 /bin/sh ../../../libtool --mode=compile gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -c -o gstgetbits_i386.lo gstgetbits_i386.s gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -c gstgetbits_i386.s -fPIC -DPIC -o .libs/gstgetbits_i386.o gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -c gstgetbits_i386.s -o gstgetbits_i386.o >/dev/null 2>&1 /bin/sh ../../../libtool --tag=CC --mode=link gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstgetbits.la -rpath /usr/lib/gstreamer-0.8 ../../../gst/libgstreamer-0.8.la -module -avoid-version -export-symbols-regex _*\(gst_\|Gst\|GST_\).* libgstgetbits_la-getbits.lo libgstgetbits_la-gstgetbits_generic.lo gstgetbits_i386.lo generating symbol list for `libgstgetbits.la' nm .libs/libgstgetbits_la-getbits.o .libs/libgstgetbits_la-gstgetbits_generic.o .libs/gstgetbits_i386.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstgetbits.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstgetbits.exp" > ".libs/libgstgetbits.expT" mv -f ".libs/libgstgetbits.expT" ".libs/libgstgetbits.exp" echo "{ global:" > .libs/libgstgetbits.ver cat .libs/libgstgetbits.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstgetbits.ver echo "local: *; };" >> .libs/libgstgetbits.ver gcc -shared .libs/libgstgetbits_la-getbits.o .libs/libgstgetbits_la-gstgetbits_generic.o .libs/gstgetbits_i386.o -Wl,--rpath -Wl,/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs ../../../gst/.libs/libgstreamer-0.8.so -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstgetbits.so -Wl,-version-script -Wl,.libs/libgstgetbits.ver -o .libs/libgstgetbits.so ar cru .libs/libgstgetbits.a libgstgetbits_la-getbits.o libgstgetbits_la-gstgetbits_generic.o gstgetbits_i386.o ranlib .libs/libgstgetbits.a creating libgstgetbits.la (cd .libs && rm -f libgstgetbits.la && ln -s ../libgstgetbits.la libgstgetbits.la) make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/getbits' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[4]: Nothing to be done for `all-am'. make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' make[3]: Nothing to be done for `all-am'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' Making all in tools make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/tools' if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst-run.o -MD -MP -MF ".deps/gst-run.Tpo" -c -o gst-run.o gst-run.c; \ then mv -f ".deps/gst-run.Tpo" ".deps/gst-run.Po"; else rm -f ".deps/gst-run.Tpo"; exit 1; fi if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_complete_0.8-gst-complete.o -MD -MP -MF ".deps/gst_complete_0.8-gst-complete.Tpo" -c -o gst_complete_0.8-gst-complete.o `test -f 'gst-complete.c' || echo './'`gst-complete.c; \ then mv -f ".deps/gst_complete_0.8-gst-complete.Tpo" ".deps/gst_complete_0.8-gst-complete.Po"; else rm -f ".deps/gst_complete_0.8-gst-complete.Tpo"; exit 1; fi if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_compprep_0.8-gst-compprep.o -MD -MP -MF ".deps/gst_compprep_0.8-gst-compprep.Tpo" -c -o gst_compprep_0.8-gst-compprep.o `test -f 'gst-compprep.c' || echo './'`gst-compprep.c; \ then mv -f ".deps/gst_compprep_0.8-gst-compprep.Tpo" ".deps/gst_compprep_0.8-gst-compprep.Po"; else rm -f ".deps/gst_compprep_0.8-gst-compprep.Tpo"; exit 1; fi if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_xmllaunch_0.8-gst-launch.o -MD -MP -MF ".deps/gst_xmllaunch_0.8-gst-launch.Tpo" -c -o gst_xmllaunch_0.8-gst-launch.o `test -f 'gst-launch.c' || echo './'`gst-launch.c; \ then mv -f ".deps/gst_xmllaunch_0.8-gst-launch.Tpo" ".deps/gst_xmllaunch_0.8-gst-launch.Po"; else rm -f ".deps/gst_xmllaunch_0.8-gst-launch.Tpo"; exit 1; fi /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-feedback gst-run.o -lglib-2.0 -lpopt mkdir .libs gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-feedback gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-inspect gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-launch gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-inspect gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-launch gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-md5sum gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-typefind gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-md5sum gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-xmlinspect gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-typefind gst-run.o -lglib-2.0 -lpopt if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_inspect_0.8-gst-inspect.o -MD -MP -MF ".deps/gst_inspect_0.8-gst-inspect.Tpo" -c -o gst_inspect_0.8-gst-inspect.o `test -f 'gst-inspect.c' || echo './'`gst-inspect.c; \ then mv -f ".deps/gst_inspect_0.8-gst-inspect.Tpo" ".deps/gst_inspect_0.8-gst-inspect.Po"; else rm -f ".deps/gst_inspect_0.8-gst-inspect.Tpo"; exit 1; fi gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-xmlinspect gst-run.o -lglib-2.0 -lpopt if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_launch_0.8-gst-launch.o -MD -MP -MF ".deps/gst_launch_0.8-gst-launch.Tpo" -c -o gst_launch_0.8-gst-launch.o `test -f 'gst-launch.c' || echo './'`gst-launch.c; \ then mv -f ".deps/gst_launch_0.8-gst-launch.Tpo" ".deps/gst_launch_0.8-gst-launch.Po"; else rm -f ".deps/gst_launch_0.8-gst-launch.Tpo"; exit 1; fi if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_md5sum_0.8-gst-md5sum.o -MD -MP -MF ".deps/gst_md5sum_0.8-gst-md5sum.Tpo" -c -o gst_md5sum_0.8-gst-md5sum.o `test -f 'gst-md5sum.c' || echo './'`gst-md5sum.c; \ then mv -f ".deps/gst_md5sum_0.8-gst-md5sum.Tpo" ".deps/gst_md5sum_0.8-gst-md5sum.Po"; else rm -f ".deps/gst_md5sum_0.8-gst-md5sum.Tpo"; exit 1; fi if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_typefind_0.8-gst-typefind.o -MD -MP -MF ".deps/gst_typefind_0.8-gst-typefind.Tpo" -c -o gst_typefind_0.8-gst-typefind.o `test -f 'gst-typefind.c' || echo './'`gst-typefind.c; \ then mv -f ".deps/gst_typefind_0.8-gst-typefind.Tpo" ".deps/gst_typefind_0.8-gst-typefind.Po"; else rm -f ".deps/gst_typefind_0.8-gst-typefind.Tpo"; exit 1; fi if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_xmlinspect_0.8-gst-xmlinspect.o -MD -MP -MF ".deps/gst_xmlinspect_0.8-gst-xmlinspect.Tpo" -c -o gst_xmlinspect_0.8-gst-xmlinspect.o `test -f 'gst-xmlinspect.c' || echo './'`gst-xmlinspect.c; \ then mv -f ".deps/gst_xmlinspect_0.8-gst-xmlinspect.Tpo" ".deps/gst_xmlinspect_0.8-gst-xmlinspect.Po"; else rm -f ".deps/gst_xmlinspect_0.8-gst-xmlinspect.Tpo"; exit 1; fi /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-register-i686 gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-register-i686 gst-run.o -lglib-2.0 -lpopt if gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../libs -I.. -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -MT gst_register_i686_0.8-gst-register.o -MD -MP -MF ".deps/gst_register_i686_0.8-gst-register.Tpo" -c -o gst_register_i686_0.8-gst-register.o `test -f 'gst-register.c' || echo './'`gst-register.c; \ then mv -f ".deps/gst_register_i686_0.8-gst-register.Tpo" ".deps/gst_register_i686_0.8-gst-register.Po"; else rm -f ".deps/gst_register_i686_0.8-gst-register.Tpo"; exit 1; fi cp ./gst-feedback-m.m gst-feedback-0.8 chmod +x gst-feedback-0.8 rm -f gst-register gst-register.tmp sed -e 's,@libexecdir\@,/usr/libexec,g' -e 's,@GST_MAJORMINOR\@,0.8,g' ./gst-register.in >gst-register.tmp mv gst-register.tmp gst-register rm -f gst-register-0.8 gst-register-0.8.tmp sed -e 's,@libexecdir\@,/usr/libexec,g' -e 's,@GST_MAJORMINOR\@,0.8,g' ./gst-register.in >gst-register-0.8.tmp mv gst-register-0.8.tmp gst-register-0.8 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-register.1.in >gst-register-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-complete.1.in >gst-complete-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-compprep.1.in >gst-compprep-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-xmllaunch.1.in >gst-xmllaunch-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-feedback.1.in >gst-feedback-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-inspect.1.in >gst-inspect-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-launch.1.in >gst-launch-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-md5sum.1.in >gst-md5sum-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-typefind.1.in >gst-typefind-0.8.1 sed \ -e s,gst-complete,gst-complete-0.8,g \ -e s,gst-compprep,gst-compprep-0.8,g \ -e s,gst-feedback,gst-feedback-0.8,g \ -e s,gst-inspect,gst-inspect-0.8,g \ -e s,gst-launch,gst-launch-0.8,g \ -e s,gst-md5sum,gst-md5sum-0.8,g \ -e s,gst-register,gst-register-0.8,g \ -e s,gst-typefind,gst-typefind-0.8,g \ -e s,gst-xmlinspect,gst-xmlinspect-0.8,g \ -e s,gst-xmllaunch,gst-xmllaunch-0.8,g \ gst-xmlinspect.1.in >gst-xmlinspect-0.8.1 /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-complete gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-complete gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-compprep gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-xmllaunch gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-compprep gst-run.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-xmllaunch gst-run.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-complete-0.8 ../gst/libgstreamer-0.8.la gst_complete_0.8-gst-complete.o -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-compprep-0.8 ../gst/libgstreamer-0.8.la gst_compprep_0.8-gst-compprep.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-compprep-0.8 gst_compprep_0.8-gst-compprep.o ../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lm -lglib-2.0 -lpopt creating gst-compprep-0.8 gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-complete-0.8 gst_complete_0.8-gst-complete.o ../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lm -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-xmllaunch-0.8 ../gst/libgstreamer-0.8.la gst_xmllaunch_0.8-gst-launch.o -lglib-2.0 -lpopt creating gst-complete-0.8 /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-inspect-0.8 ../gst/libgstreamer-0.8.la gst_inspect_0.8-gst-inspect.o ../libs/gst/control/libgstcontrol-0.8.la gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-xmllaunch-0.8 gst_xmllaunch_0.8-gst-launch.o ../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lm -lglib-2.0 -lpopt creating gst-xmllaunch-0.8 /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-launch-0.8 ../gst/libgstreamer-0.8.la gst_launch_0.8-gst-launch.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-inspect-0.8 gst_inspect_0.8-gst-inspect.o ../gst/.libs/libgstreamer-0.8.so ../libs/gst/control/.libs/libgstcontrol-0.8.so /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm creating gst-inspect-0.8 /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-md5sum-0.8 ../gst/libgstreamer-0.8.la gst_md5sum_0.8-gst-md5sum.o -lglib-2.0 -lpopt gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-launch-0.8 gst_launch_0.8-gst-launch.o ../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lm -lglib-2.0 -lpopt creating gst-launch-0.8 gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-md5sum-0.8 gst_md5sum_0.8-gst-md5sum.o ../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lm -lglib-2.0 -lpopt /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-typefind-0.8 ../gst/libgstreamer-0.8.la gst_typefind_0.8-gst-typefind.o -lglib-2.0 -lpopt creating gst-md5sum-0.8 /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-xmlinspect-0.8 ../gst/libgstreamer-0.8.la gst_xmlinspect_0.8-gst-xmlinspect.o ../libs/gst/control/libgstcontrol-0.8.la gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-typefind-0.8 gst_typefind_0.8-gst-typefind.o ../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lm -lglib-2.0 -lpopt creating gst-typefind-0.8 gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-xmlinspect-0.8 gst_xmlinspect_0.8-gst-xmlinspect.o ../gst/.libs/libgstreamer-0.8.so ../libs/gst/control/.libs/libgstcontrol-0.8.so /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm /bin/sh ../libtool --tag=CC --mode=link gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o gst-register-i686-0.8 ../gst/libgstreamer-0.8.la gst_register_i686_0.8-gst-register.o -lglib-2.0 -lpopt creating gst-xmlinspect-0.8 gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o .libs/gst-register-i686-0.8 gst_register_i686_0.8-gst-register.o ../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lm -lglib-2.0 -lpopt creating gst-register-i686-0.8 make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/tools' Making all in pkgconfig make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/pkgconfig' cp gstreamer.pc gstreamer-0.8.pc cp gstreamer-control.pc gstreamer-control-0.8.pc cp gstreamer-uninstalled.pc gstreamer-0.8-uninstalled.pc cp gstreamer-control-uninstalled.pc gstreamer-control-0.8-uninstalled.pc make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/pkgconfig' Making all in po make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/po' make[2]: Nothing to be done for `all'. make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/po' Making all in common make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' Making all in m4 make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common/m4' make[3]: Nothing to be done for `all'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common/m4' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' make[3]: Nothing to be done for `all-am'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' Making all in docs make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' Making all in faq make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' make[4]: warning: jobserver unavailable: using -j1. Add `+' to parent make rule. cd build && xmllint -noout -valid faq.xml make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq/build/faq.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" GStreamer FAQ (0.8.11) This is the FAQ for GStreamer, a multimedia framework. Questions and answers range from general information to deep-down-and-dirty compilation issues. 0.1.12003-04-24Added Q&A about developing with uninstalled copy.0.1.02002-10-01Initial conversion from FAQ database.Getting Started So you're eager to get started learning about GStreamer. There's a few ways you can get started. If you want to learn by reading about it, start with If you'd rather learn by trying it out, start with If you want to live on the bleeding edge and develop and use CVS, see GeneralIs GStreamer a media player ? No, GStreamer is a development framework for creating applications like media players, video editors, streaming media broadcasters and so on. That said, very good media players can easily be built on top of GStreamer and we even include a simple yet functional media player with GStreamer, called gst-player. Why is GStreamer written in C ? Why not C++/Objective-C/... ? We like C. Aside from "personal preference", there are a number of technical reasons why C is nice in this project: C is extremely portable.C is fast.It is easy to make language bindings for libraries written in C. The GObject object system provided by GLib implements objects in C, in a portable, powerful way. This library provides for introspection and runtime dynamic typing. It is a full OO system, but without the syntactic sugar. If you want sugar, take a look at GOB.Use of C integrates nicely with Gtk+ and GNOME. Some people like this a lot, but neither Gtk+ nor GNOME are required by GStreamer. So, in closing, we like C. If you don't, that's fine; if you still want to help out on GStreamer, we always need more language binding people. And if not, don't bother us; we're working :-) What applications are available for GStreamer ? GStreamer is still very early in its development, but already we see some really nice applications being developed in parallel with GStreamer. Both gst-player and gst-editor are very closely linked to GStreamer itself for obvious reasons. Does GStreamer support the format of my media files? GStreamer aims to support every format imaginable, but that doesn't mean the developers have managed to achieve that aim yet. If a GStreamer enabled application doesn't play back your files, you can help us solve that problem by filing an enhancement request bug for that format. If you have it, please provide: links to other players, preferrably Open Source and working on Unixlinks to explanations of the format.ways to obtain mediafiles in that format to test. What are the exact licensing terms for GStreamer and its plugins ? All of GStreamer, including our own plugin code, is licensed under the GNU LGPL license. Some of the libraries we use for some of the plugins are however under the GPL, which means that those plugins can not be used by a non-GPL-compatible application. As part of the GStreamer source download you find a file called LICENSE_readme in gst-plugins package. That file contains information in the exact licensing terms of the libraries we use. As a general rule, GStreamer aims at using only LGPL or BSD licensed libraries if available and only use GPL or proprietary libraries where no good LGPL or BSD alternatives are available. From GStreamer 0.4.2 on, we implemented a license field for all of the plugins, and in the future we might have the application enforce a stricter policy (much like tainting in the kernel). Is GStreamer a sound server ? No, GStreamer is not a soundserver. GStreamer does however have plugins supporting most of the major soundservers available today, including ESD, aRTSd, and to some extent Jack. Support for MAS is also planned. Will GStreamer be available for platforms other than Unix ? Depends. Our main target is the Unix platform. That said, interest has been expressed in porting GStreamer to other platforms and the GStreamer core team will gladly accept patches to accomplish this. What is GStreamer's relationship with the GNOME community ? While GStreamer is operated as an independent project, we do have a close relationship with the GNOME community. Many of our hackers consider themselves also to be members of the GNOME community. There are plans to make (some part of) GStreamer an official part of the development framework of GNOME. This does not exclude use of GStreamer by other communities at all, of course. What is GStreamer's relationship with the KDE community ? The GStreamer community wants to have as good a relationship as possible with KDE, and we hope that someday KDE decides to adopt GStreamer as their multimedia API, just like the GNOME community plans on doing. There have been contacts from time to time between the GStreamer community and KDE and we do already have support for the aRTSd sound server used by KDE. Also, some of the KDE hackers have created Qt bindings of GStreamer and made a simple video player. I'm considering adding GStreamer output to my application... That doesn't really make sense. GStreamer is not a sound server, so you don't output directly to GStreamer, and it's not an intermediate API between audio data and different kinds of audio sinks. It is a fundamental design decision to use GStreamer in your app; there are no easy ways of somehow 'transfering' data from your app to GStreamer. Instead, your app would have to use or implement a number of GStreamer elements, string them together, and tell them to run. In that manner the data would all be internal to the GStreamer pipeline. That said, it is possible to write a plugin specific to your app that can get at the audio data. DependenciesWhy are there so many dependencies ? Making a full-featured media framework is a huge undertaking in itself. By using the work done by others, we both reduce the amount of redundant work being done and leave ourselves free to work on the architecture itself instead of working on the low-level stuff. We would be stupid not to reuse the code others have written. However, do realize that in no way you are forced to have all dependencies installed. None of the core developers has all of them installed. GStreamer has only a few obligate dependencies : GLib 2.0, popt >= 1.6.0, and very common stuff like glibc, a C compiler, and so on. All of the other dependencies are optional. So, in closing, let's rephrase the question to Why are you giving me so many choices and such a rich environment ? Does GStreamer use GTK+ 1.2/GLib 1.2 or GLib 2.0 ? Since the 0.3.3 release of GStreamer, we use GLib 2.0 as the core library for GStreamer, which features a move of GObject from GTK+ 2.0 to GLib 2.0. If you want to compile using GTK+ 1.2/GLib 1.2, you need to get the 0.3.1 or earlier release. It is of course not supported. Does GStreamer offer support for DVD decoder cards like dxr2/3 ? We do have support for the dxr3, although dxr2 support is unknown. GStreamer can easily accomodate hardware acceleration by writing new device-specific elements. Is GStreamer X independent ? Yes, we have no X dependency in any of our core modules. There are GStreamer applications that run fine without any need for X. However, until our Linux Framebuffer or libsvga plugin is ready, you will not be able to play videos without X. In the future, there will probably be lots of different output plugins for video available. What is GStreamer's position on efforts such as LADSPA ? GStreamer actively supports such efforts, and in the case of LADPSA, we already have a wrapper plugin. This wrapper plug-in detects the LADSPA plugins present on your system at register time. Does GStreamer support MIDI ? Not yet. The GStreamer architecture should be able to support the needs of MIDI applications very well however. If you are a developer interested in adding MIDI support to GStreamer we are very interested in getting in touch with you. Does GStreamer depend on GNOME ? No. But many of the applications developed for GStreamer do, including our sample applications. There is nothing hindering people from developing applications using other toolkits however and we would happily help promote such efforts. A good example of an application using GStreamer, but which is not using GNOME is the Mozstreamer which uses Mozilla XUL. Getting GStreamerHow do I get GStreamer ? Generally speaking, you have three options, ranging from easy to hard : distribution-specific packages source tarballs CVS How can I install GStreamer from source ? We provide tarballs of our releases on our own site, at http://gstreamer.freedesktop.org/src/ When compiling from source, make sure you specify PKG_CONFIG_PATH correctly when building against GStreamer. For example, if you configured GStreamer with the default prefix (which is /usr/local), then you need to export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig before building gst-plugins. Are there premade binaries available ? Yes, we currently provide precompiled packages for Red Hat, Debian and Linux Mandrake. We provide RPMS for Red Hat and Fedora Core through our Apt for rpm page. We usually support the last 2-3 releases of Red Hat. (RH9 and FC1) GStreamer is already in Debian experimental, so if you are a debian user you should be able to get the Debian packages from there.GStreamer is also in Mandrake Cooker so if you are using a recent release of Linux Mandrake you should be able to get GStreamer from there. To learn howto get packages from Mandrake cooker the Mandrake cooker page has more info For other RPM based distributions we recommend getting the source tarball and doing 'rpm -ta gstreamer-0.X.X' to create rpms. We keep our SPEC file constantly up to date so you should always be able to build GStreamer rpms from a tarball. The SPEC file is aimed at Red Hat however, so there might be some need for you to edit the Requirements list if your distribution name these packages differently.Why don't you provide premade binaries for distribution XY ? GStreamer is run on a volunteer basis. The package that are provided are made by non-paid people who do this on their own time. The distributions we support with binaries are the distributions that we have people who have volunteered to make binaries for. If you are interested in maintaining GStreamer binaries for other distributions or Unices we would be happy to hear from you. Contact us through the GStreamer-devel mailing list. I am having trouble compiling GStreamer on my LFS installation, why ? If you are running LFS our basic opinion is that you should be knowledgeable enough to solve any build issues you get on your own. Being volunteered based we can't promise support to anyone of course, but are you using LFS consider yourself extra unsupported. We neither can or want to know enough, about how your unique system is configured, to be able to help you. That said, if you come to the #gstreamer channel on irc.openprojects.net we might of course be able to give you some general hints and pointers. How do I get GStreamer through CVS ? see this page : http://gstreamer.freedesktop.org/dev/ for CVS access. (anonymous and developer) Using GStreamerOk, I've installed GStreamer. What can I do next ? First of all, verify that you have a working registry and that you can inspect them by typing $ gst-inspect fakesrc This should print out a bunch of information about this particular element. If this tells you that there is "no such element or plugin", you haven't installed GStreamer correctly. Please check how to get GStreamer If this fails with any other message, we would appreciate a bug report. It's time to try out a few things. Start with gst-launch and two plug-ins that you really should have : fakesrc and fakesink. They do nothing except pass empty buffers. Type this at the command-line : $ gst-launch -v fakesrc num-buffers=3 ! fakesink This will print out output that looks similar to this : RUNNING pipeline ... fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 0) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 0) 0x8057510" fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 1) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 1) 0x8057510" fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 2) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 2) 0x8057510" execution ended after 5 iterations (sum 301479000 ns, average 60295800 ns, min 3000 ns, max 105482000 ns) (Some parts of output have been removed for clarity) If it looks similar, then GStreamer itself is running correctly. Can my system play sound through GStreamer ? You can test this by trying to play a sine tone. For this, you need to link the sinesrc plug-in to an output plug-in that matches your hardware. A (non-complete) list of output plug-ins for audio is osssink for OSS outputesdsink for ESound outputartsdsink for aRTs outputalsasink for ALSA outputjacksink for JACK output First of all, run gst-inspect on the output plug-in you want to use to make sure you have it installed. For example, if you use OSS, run $ gst-inspect osssink and see if that prints out a bunch of properties for the plug-in. Then try to play the sine tone by running $ gst-launch sinesrc ! osssink and see if you hear something. Make sure your volume is turned up, but also make sure it is not too loud and you are not wearing your headphones. In GNOME, you can configure audio output for most applications by running $ gstreamer-properties which can also be found in the start menu (Applications -> Preferences -> Multimedia Systems Selector). In KDE, there is not yet a shared way of setting audio output for all applications; however, applications such as Amarok allow you to specify an audio output in their preferences dialog. How can I see what GStreamer plugins I have on my system ? To do this you use the gst-inspect command-line tool, which comes standard with GStreamer. Invoked without any arguments, $ gst-inspect will print out a listing of installed plugins. To learn more about a particular plugin, pass its name on the command line. For example, $ gst-inspect volume will give you information about the volume plugin. Also, if you install the gst-editor package, you will have a graphical plugin browser available, gst-inspect-gui. Where should I report bugs ? Bug management is now hosted on GNOME's Bugzilla at http://bugzilla.gnome.org, under the product GStreamer. Using bugzilla you can view past bug history, report new bugs, etc. Bugzilla requires you to make an account here, which might seem cumbersome, but allows us to at least have a chance at contacting you for further information, as we will most likely have to. How should I report bugs ? When doing a bug report, you should at least describe your distribution how you installed GStreamer (from cvs, source, packages, which ?)if you installed GStreamer before It also is useful for us if you attach output of the gst-feedback command to your bug report. If you're having problem with a specific application (either one of ours, somebody else's, or your own), please also provide a log of gst-mask by running myapp --gst-mask=-1 > mask.log 2>&1 gzip mask.log (interrupting the program if it doesn't stop by itself) and attach mask.log.gz to your bug report. If the application you are having problems with is segfaulting, then provide us with the necessary gdb output. See How do I use the GStreamer command line interface ? You access the GStreamer command line interface using the command gst-launch. To decode an mp3 and play it through OSS, you could use gst-launch filesrc location=thesong.mp3 ! mad ! osssink . More examples can be found in the gst-launch man page. To automatically detect the right codec in a pipeline, try gst-launch filesrc location=my-random-media-file.mpeg ! spider ! osssink . Try replacing osssink with sdlvideosink and see what happens. We also have a simple tool called gst-launch-ext used for debugging, which has predefined pipelines for you. This means you can just write gst-launch-ext (filename) and it will play the file if the extension is supported. Note that no effort has been made for uninterrupted synchronized playback using this tool. Troubleshooting GStreamer My GStreamer-based application crashes on startup with errors about unfound schedulers on the command-line. I get undefined behaviour as soon as any GStreamer element is being initialized. Your registry is probably missing, or it is outdated (i.e. not updated after a recent upgrade). Fix this by running gst-register yourself: gst-register In the worst case, you might have to run it both as user and as root. Note that package managers are suggested to run this automatically during the post-installation. Our RPMs and Debian packages do just that. Some application is telling me that I am missing a plug-in. What do I do ? Well, start by checking if you really are missing the plug-in. gst-inspect (plug-in) and replace (plug-in) with the plug-in you think is missing. If this doesn't return any result, then you either don't have it or your registry cannot find it. If you're not sure either way, then chances are good that you don't have it. You should get the plug-in and run gst-register to register it. How to get the plug-in depends on your distribution. if you run GStreamer using packages for your distribution, you should check what packages are available for your distribution and see if any of the available packages contains the plug-in. if you run GStreamer from a source install, there's a good chance the plug-in didn't get built because you are missing an external library. When you ran configure, you should have gotten output of what plug-ins are going to be built. You can re-run configure to see if it's there. If it isn't, there is a good reason why it is not getting built. The most likely is that you're missing the library you need for it. Check the README file in gst-plugins to see what library you need. Make sure to remember to re-run configure after installing the supporting library ! if you run GStreamer from CVS, the same logic applies as for a source install. Go over the reasons why the plug-in didn't get configured for build. Check output of config.log for a clue as to why it doesn't get built if you're sure you have the library needed installed in a sane place. I get an error that says something like (process:26626): GLib-GObject-WARNING **: specified instance size for type `DVDReadSrc' is smaller than the parent type's `GstElement' instance size What's wrong ? If you run GStreamer CVS uninstalled, it means that something changed in the core that requires a recompilation in the plugins. Recompile the plugins by doing "make clean && make". If you run GStreamer installed, it probably means that you run the plugins against a different (incompatible) version than they were compiled against, which ususally means that you run multiple installations of GStreamer. Remove the old ones and - if needed - recompile again to ensure that it is using the right version. Note that we strongly recommend using Debian or RPM packages, since you will not get such issues if you use provided packages. The GStreamer application I used stops with a segmentation fault. What can I do ? There are two things you can do. If you compiled GStreamer with specific optimization compilation flags, you should try recompiling GStreamer, the application and the plug-ins without any optimization flags. This allows you to verify if the problem is due to optimization or due to bad code. Second, it will also allow you to provide a reasonable backtrace in case the segmentation fault still occurs. The second thing you can do is look at the backtrace to get an idea of where things are going wrong, or give us an idea of what is going wrong. To provide a backtrace, you should run the application in gdb by starting it with gdb (gst-application) (If the application is in a source tree instead of installed on the system, you might want to put "libtool" before "gdb") Pass on the command line arguments to the application by typing set args (the arguments to the application) at the (gdb) prompt Type "run" at the (gdb) prompt and wait for the application to segfault. The application will run a lot slower, however. After the segfault, type "bt" to get a backtrace. This is a stack of function calls detailing the path from main () to where the code is currently at. If the application you're trying to debug contains threads, it is also useful to do info threads and get backtraces of all of the threads involved, by switching to a different thread using "thread (number)" and then again requesting a backtrace using "bt". If you can't or don't want to work out the problem yourself, a copy and paste of all this information should be included in your bug report. Building GStreamer from CVS How do I check out GStreamer from CVS ? GStreamer is hosted on Freedesktop.org. GStreamer consists of various parts. In the beginning, you will be interested in the "gstreamer" module, containing the core, and "gst-plugins", containing the basic set of plugins. To check out the HEAD version of the core, use cvs -d:pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer co gstreamer This will create a directory "gstreamer" in your current directory. If you want to get another module, replace the last "gstreamer" with the name of the module. How do I get developer access to GStreamer CVS ? If you want to gain developer access to GStreamer CVS, you should ask for it on the development lists, or ask one of the maintainers directly. If you are not already a registered developer with a user account on Freedesktop.org, You will then have to provide them with: your desired unix usernameyour full nameyour e-mail addressa copy of your public sshv2 identity. If you do not have this yet, you can generate it by running "ssh-keygen -t dsa". The resulting public key will be in .ssh/id_dsa.pub(optionally) your GPG fingerprint. This would allow you to add and remove ssh keys to your account. I ran autogen.sh, but it fails with something like this: + running aclocal -I m4 -I common/m4 ... aclocal: configure.ac: 8: macro `AM_DISABLE_STATIC' not found in library aclocal: configure.ac: 17: macro `AM_PROG_LIBTOOL' not found in library aclocal failed What's wrong ? aclocal is unable to find two macros installed by libtool in a file called libtool.m4. Normally this would indicate that you don't have libtool, but that would mean autogen.sh would have failed on not finding libtool. It is more likely that you installed automake (which provides aclocal) in a different prefix than libtool. You can check this by examining in what prefix both aclocal and libtool are installed. You can do three things to fix this : install automake in the same prefix as libtoolforce use of the automake installed in the same prefix as libtool by using the --with-automake optionfigure out what prefix libtool has been installed to and point aclocal to the right location by running export ACLOCAL_FLAGS="-I $(prefix)/share/aclocal" where you replace prefix with the prefix where libtool was installed. Developing applications with GStreamerHow do I compile programs that use GStreamer ? GStreamer uses pkg-config to assist applications with compilationa and linking flags. pkg-config is already used by GTK+, GNOME, SDL, and others; so if you are familiar with using it for any of those, you're set. If you're not familiar with pkg-config to compile and link a small one-file program, pass the --cflags and --libs arguments to pkg-config. For example: $ libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.8` -o myprog myprog.c would be sufficient for a gstreamer-only program. If (for example) your app also used GTK+ 2.0, you could use $ libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.8 gtk+-2.0` -o myprog myprog.c Those are back-ticks (on the same key with the tilde on US keyboards), not single quotes. For bigger projects, you should integrate pkg-config use in your Makefile, or integrate with autoconf using the pkg.m4 macro. How do I develop against an uninstalled GStreamer copy ? It is possible to develop and compile against an uninstalled copy of gstreamer and gst-plugins (for example, against CVS copies). The easiest way to do this is to use a script like this (for bash): #!/bin/bash -i # # this script is in CVS as gstreamer/docs/faq/gst-uninstalled # # set up environment to use and develop gstreamer and friends uninstalled # # set up PATH, LD_LIBRARY_PATH, PKG_CONFIG_PATH, GST_PLUGIN_PATH, MANPATH, # PYTHONPATH # # prefer uninstalled versions, but also put installed ones on the path # # this script assumes that the relevant modules are checked out one by one # under a given tree specified below in MYGST # # symlink this script in a directory in your path (for example $HOME/bin) # to a name that reflects the version of your checkout # # e.g.: # - mkdir $HOME/gst/head # - ln -sf gst-uninstalled $HOME/bin/gst-head # - checkout copies of gstreamer modules in $HOME/gst/head # - gst-head # this script is run -i so that PS1 doesn't get cleared # change this variable to a different location depending on where you # store your cvs checkouts MYGST=$HOME/gst # extract version from $0 # if this script is called "gst-head" then version will be "head" VERSION=`echo $0 | sed s/.*gst-//g` # base path under which dirs are installed GST=$MYGST/$VERSION if test ! -e $GST; then echo "$GST does not exist !" exit fi # set up a bunch of paths PATH=$GST/gstreamer/tools:$GST/gst-plugins/tools:$GST/gst-player/src:$GST/gst-editor/src:$GST/prefix/bin:$PATH # /some/path: makes the dynamic linker look in . too, so avoid this export LD_LIBRARY_PATH=$GST/prefix/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} export PKG_CONFIG_PATH=$GST/prefix/lib/pkgconfig:$GST/gstreamer/pkgconfig:$GST/gst-plugins/pkgconfig:$GST/gst-python/pkgconfig:$PKG_CONFIG_PATH export GST_PLUGIN_PATH=$GST/gstreamer:$GST/gst-plugins:$GST/gst-ffmpeg:$GST/gst-monkeysaudio:$GST_PLUGIN_PATH export MANPATH=$GST/gstreamer/tools:$GST/prefix/share/man:$MANPATH pythonver=`python -c "import sys; print sys.version[:3]"` export PYTHONPATH=$GST/gst-python:$GST/prefix/lib/python$pythonver/site-packages:$PYTHONPATH # if we got a command, run it, else start a shell if test ! -z "$1"; then $@ exit $? fi # set up prompt to help us remember we're in a subshell, cd to # the gstreamer base dir and start $SHELL cd $GST PS1="[gst-$VERSION] $PS1" $SHELL If you put this script in your path, and symlink it to gst-cvs (if you want to develop against cvs HEAD) or to gst-0.6 (if you want to develop against the 0.6 branch), it will automatically use the uninstalled version from that directory. This requires you to have put your checkouts of gstreamer and gst-plugins under ~/gst/cvs (for the HEAD version). The program is easily modifiable if this isn't the case. After running this script, you'll be in an environment where you can use the uninstalled tools, and where gst-register registers the uninstalled plugins by default. Also, pkg-config wil detect the uninstalled copies before any installed copies. How can I use GConf to get the system-wide defaults ? It's a good idea to use GConf to use default ways of outputting audio and video. Since GStreamer's GConf keys can be more than just one element, but a whole pipeline, it would be a good idea to use the gstgconf library. It provides functions to parse the GConf key to a usable pipeline. To link against gstgconf, use pkg-config to query the gstreamer-libs-0.8.pc file for link flags, and add -lgstgconf to the link flags. This fragment of configure.ac shows how to use pkg-config to get the LIBS: dnl check for GStreamer helper libs PKG_CHECK_MODULES(GST_HELPLIBS, gstreamer-libs-0.8 >= $GSTREAMER_REQ,,exit) AC_SUBST(GST_HELPLIBS_LIBS) AC_SUBST(GST_HELPLIBS_CFLAGS) This fragment of a Makefile.am file shows how to make your application link to it: bin_PROGRAMS = application application_LDADD = $(GST_LIBS) $(GST_HELPLIBS_LIBS) -lgstgconf application_CFLAGS = $(GST_CFLAGS) $(GST_HELPLIBS_CFLAGS) How do I debug these funny shell scripts that libtool makes ? When you link a program against uninstalled GStreamer using libtool, funny shell scripts are made to modify your shared object search path and then run your program. For instance, to debug gst-launch, try libtool gdb /path/to/gstreamer-launch . If this does not work, you're probably using a broken version of libtool. Why is mail traffic so low on gstreamer-devel ? Our main arena for coordination and discussion is IRC, not email. Join us in #gstreamer on irc.freenode.net For larger picture questions or getting more input from more persons, a mail to gstreamer-devel is never a bad idea. However, we do archive our IRC discussions, which you may find in the gstreamer-daily mailing list archives. What kind of versioning scheme does GStreamer use ? For public releases, GStreamer uses a standard MAJOR.MINOR.MICRO version scheme. If the release consists of mostly bug fixes or incremental changes, the MICRO version is incremented. If the release contains big changes, the MINOR version is incremented. If we're particularly giddy, we might even increase the MAJOR number. Don't hold your breath for that though. During the development cycle, GStreamer also uses a fourth or NANO number. If this number is 1, then it's a CVS version. Any tarball or package that has a nano number of 1 is made from CVS and thus not supported. Additionally, if you didn't get this package or tarball from the GStreamer team, don't have high hopes on it doing whatever you want it to do. If the number is 2 or higher, it's an official pre-release in preparation of an actual complete release. Your help in testing these tarballs and packages is very much appreciated. What is the coding style for GStreamer core ? The core is basically coded in K&R with 2-space indenting. Just follow what's already there and you'll be fine. The core could use a code cleanup though at this point. Individual plugins in gst-plugins or plugins that you want considered for addition to the gst-plugins module should be coded in the same style. It's easier if everything is consistent. Consistency is, of course, the goal. If you use emacs, try these lines: (defun gstreamer-c-mode () "C mode with adjusted defaults for use with GStreamer." (interactive) (c-mode) (c-set-style "K&R") (setq c-basic-offset 2)) (setq auto-mode-alist (cons '("gst.*/.*\\.[ch]$" . gstreamer-c-mode) auto-mode-alist)) Or, run your code through indent -br -bad -cbi0 -cli2 -bls -l100 -ut -ce before submitting a patch (FIXME: check if these are indeed the proper options). As for the code itself, the GNOME coding guidelines is a good read. Where possible, we try to adhere to the spirit of GObject and use similar coding idioms. GStreamer Legal Issues This part of the FAQ is based on a series of questions we asked the FSF to understand how the GPL works and how patents affects the GPL. These questions were answered by the FSF lawyers, so we view them as the final interpretation on how the GPL and LGPL interact with patents in our opinion. This consultancy was paid for by Fluendo in order to obtain clear and quotable answers. These answers were certified by the FSF lawyer team and verified by FSF lawyer and law professor Eben Moglen. Can someone distribute the combination of GStreamer, the LGPL libraryTotem, a GPL playback applicationThe binary-only Sorenson decoder together in one distribution/operating system ? If not, what needs to be changed to make this possible ? This would be a problem, because the GStreamer and Totem licenses would forbid it. In order to link GStreamer to Totem, you need to use section 3 of the LGPL to convert GStreamer to GPL. The GPL version of GStreamer forbids linking to the Sorenson decoder. Anyway, the Totem GPL license forbids this. If the authors of Totem want to permit this, we have an exception for them: the controlled interface exception from the FAQ. The idea of this is that you can't get around the GPL just by including a LGPL bit in the middle. Suppose Apple wants to write a binary-only proprietary plugin for GStreamer to decode Sorenson video, which will be shipped stand-alone, not part of a package like in the question above. Can Apple distribute this binary-only plugin ? Yes, modulo certain reverse engineering requirements in section 6 of the LGPL. If a program released under the GPL uses a library that is LGPL, and this library can dlopen plug-ins at runtime, what are the requirements for the license of the plug-in ? You may not distribute the plug-in with the GPL application. Distributing the plug-in alone, with the knowledge that it will be used primarily by GPL software is a bit of an edge case. We will not advise you that it would be safe to do so, but we also will not advise you that it would be absolutely forbidden. Can someone in a country that does not have software patents distribute code covered by US patents under the GPL to people in, for example, Norway ? If he/she visits the US, can he/she be arrested ? Yes, he can. No, there are no criminal penalties for patent infringement in the US. Can someone from the US distribute software covered by US patents under the GPL to people in Norway ? To people in the US ? This might infringe some patents, but the GPL would not forbid it absent some actual restriction, such as a court judgement or agreement. The US government is empowered to refuse importation of patent infringing devices, including software. There are a lot of GPL- or LGPL-licensed libraries that handle media codecs which have patents. Take mad, an mp3 decoding library, as an example. It is licensed under the GPL. In countries where patents are valid, does this invalidate the GPL license for this project ? The mere existence of a patent which might read on the program does not change anything. However, if a court judgement or other agreement prevents you from distributing libmad under GPL terms, you can not distribute it at all. The GPL and LGPL say (sections 7 and 11): If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. So let's say there is a court judgement. Does this mean that the GPL license is invalid for the project everywhere, or only in the countries where it conflicts with the applicable patents ? The GPL operates on a per-action, not per-program basis. That is, if you are in a country which has software patents, and a court tells you that you cannot distribute (say) libmad in source code form, then you cannot distribute libmad at all. This doesn't affect anyone else. Patented decoding can be implemented in GStreamer either by having a binary-only plugin do the decoding, or by writing a plugin (with any applicable license) that links to a binary-only library. Does this affect the licensing issues involved in regards to GPL/LGPL? No. Is it correct that you cannot distribute the GPL mad library to decode mp3's, *even* in the case where you have obtained a valid license for decoding mp3 ? The only GPL-compatible patent licenses are those which are open to all parties posessing copies of GPL software which practices the teachings of the patent. If you take a license which doesn't allow others to distribute original or modified versions of libmad practicing the same patent claims as the version you distribute, then you may not distribute at all. Done. Copying .css files: base.css make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' Making all in manual make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' Generating build/images/bin-element-ghost.png from bin-element-ghost.fig Generating build/images/bin-element-noghost.png from bin-element-noghost.fig Generating build/images/bin-element.png from bin-element.fig Generating build/images/filter-element-multi.png from filter-element-multi.fig Generating build/images/filter-element.png from filter-element.fig Generating build/images/hello-world.png from hello-world.fig Generating build/images/linked-elements.png from linked-elements.fig Generating build/images/mime-world.png from mime-world.fig Generating build/images/queue.png from queue.fig Generating build/images/sink-element.png from sink-element.fig Generating build/images/src-element.png from src-element.fig Generating build/images/state-diagram.png from state-diagram.fig Generating build/images/thread.png from thread.fig make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' make[4]: warning: jobserver unavailable: using -j1. Add `+' to parent make rule. cd build && xmllint -noout -valid manual.xml make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual/build/manual.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" WimTaymans wim.taymans@chello.be SteveBaker stevebaker_org@yahoo.co.uk AndyWingo wingo@pobox.com RonaldS.Bultje rbultje@ronald.bitfreak.net This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/opl.shtml). GStreamer Application Development Manual (0.8.11)Overview GStreamer is an exremely powerful and versatile framework for creating streaming media applications. Many of the virtues of the GStreamer framework come from its modularity: GStreamer can seamlessly incorporate new plugin modules. But because modularity and power often come at a cost of greater complexity (consider, for example, CORBA), writing new applications is not always easy. This guide is intended to help you understand the GStreamer framework (version 0.8.11) so you can develop applications based on it. The first chapters will focus on development of a simple audio player, with much effort going into helping you understand GStreamer concepts. Later chapters will go into more advanced topics related to media playback, but also at other forms of media processing (capture, editing, etc.). Introduction This chapter gives you an overview of the technologies described in this book. What is GStreamer? GStreamer is a framework for creating streaming media applications. The fundamental design comes from the video pipeline at Oregon Graduate Institute, as well as some ideas from DirectShow. GStreamer's development framework makes it possible to write any type of streaming multimedia application. The GStreamer framework is designed to make it easy to write applications that handle audio or video or both. It isn't restricted to audio and video, and can process any kind of data flow. The pipeline design is made to have little overhead above what the applied filters induce. This makes GStreamer a good framework for designing even high-end audio applications which put high demands on latency. One of the the most obvious uses of GStreamer is using it to build a media player. GStreamer already includes components for building a media player that can support a very wide variety of formats, including MP3, Ogg/Vorbis, MPEG-1/2, AVI, Quicktime, mod, and more. GStreamer, however, is much more than just another media player. Its main advantages are that the pluggable components can be mixed and matched into arbitrary pipelines so that it's possible to write a full-fledged video or audio editing application. The framework is based on plugins that will provide the various codec and other functionality. The plugins can be linked and arranged in a pipeline. This pipeline defines the flow of the data. Pipelines can also be edited with a GUI editor and saved as XML so that pipeline libraries can be made with a minimum of effort. The GStreamer core function is to provide a framework for plugins, data flow and media type handling/negotiation. It also provides an API to write applications using the various plugins. Structure of this Manual This book is about GStreamer from a developer's point of view; it describes how to write a GStreamer application using the GStreamer libraries and tools. For an explanation about writing plugins, we suggest the Plugin Writers Guide. gives you an overview of GStreamer's motivation design goals. rapidly covers the basics of GStreamer application programming. At the end of that chapter, you should be able to build your own audio player using GStreamer In , we will move on to complicated subjects which make GStreamer stand out of its competitors. We will discuss application-pipeline interaction using dynamic parameters and interfaces, we will discuss threading and threaded pipelines, scheduling and clocks (and synchronization). Most of those topics are not just there to introduce you to their API, but primarily to give a deeper insight in solving application programming problems with GStreamer and understanding their concepts. Next, in , we will go into higher-level programming APIs for GStreamer. You don't exactly need to know all the details from the previous parts to understand this, but you will need to understand basic GStreamer concepts nevertheless. We will, amongst others, discuss XML, playbin and autopluggers. In , you will find some random information on integrating with GNOME, KDE, OS X or Windows, some debugging help and general tips to improve and simplify GStreamer programming. In order to understand this manual, you will need to have a basic understanding of the C language. Since GStreamer uses GLib 2.0, the reader is assumed to understand the basics of the GObject object model. It is recommended to have skimmed through the introduction of the GObject tutorial before reading this. You may also want to have a look at Eric Harlow's book Developing Linux Applications with GTK+ and GDK. Motivation & Goals Linux has historically lagged behind other operating systems in the multimedia arena. Microsoft's Windows and Apple's MacOS both have strong support for multimedia devices, multimedia content creation, playback, and realtime processing. Linux, on the other hand, has a poorly integrated collection of multimedia utilities and applications available, which can hardly compete with the professional level of software available for MS Windows and MacOS. GStreamer was designed to provide a solution to the current Linux media problems. Current problems We describe the typical problems in today's media handling on Linux. Multitude of duplicate code The Linux user who wishes to hear a sound file must hunt through their collection of sound file players in order to play the tens of sound file formats in wide use today. Most of these players basically reimplement the same code over and over again. The Linux developer who wishes to embed a video clip in their application must use crude hacks to run an external video player. There is no library available that a developer can use to create a custom media player. 'One goal' media players/libraries Your typical MPEG player was designed to play MPEG video and audio. Most of these players have implemented a complete infrastructure focused on achieving their only goal: playback. No provisions were made to add filters or special effects to the video or audio data. If you want to convert an MPEG-2 video stream into an AVI file, your best option would be to take all of the MPEG-2 decoding algorithms out of the player and duplicate them into your own AVI encoder. These algorithms cannot easily be shared across applications. Attempts have been made to create libraries for handling various media types. Because they focus on a very specific media type (avifile, libmpeg2, ...), significant work is needed to integrate them due to a lack of a common API. GStreamer allows you to wrap these libraries with a common API, which significantly simplifies integration and reuse. Non unified plugin mechanisms Your typical media player might have a plugin for different media types. Two media players will typically implement their own plugin mechanism so that the codecs cannot be easily exchanged. The plugin system of the typical media player is also very tailored to the specific needs of the application. The lack of a unified plugin mechanism also seriously hinders the creation of binary only codecs. No company is willing to port their code to all the different plugin mechanisms. While GStreamer also uses it own plugin system it offers a very rich framework for the plugin developer and ensures the plugin can be used in a wide range of applications, transparently interacting with other plugins. The framework that GStreamer provides for the plugins is flexible enough to host even the most demanding plugins. Poor user experience Because of the problems mentioned above, application authors have so far often been urged to spend a considerable amount of time in writing their own backends, plugin mechanisms and so on. The result has often been, unfortunately, that both the backend as well as the user interface were only half-finished. Demotivated, the application authors would start rewriting the whole thing and complete the circle. This leads to a poor end user experience. Provision for network transparency No infrastructure is present to allow network transparent media handling. A distributed MPEG encoder will typically duplicate the same encoder algorithms found in a non-distributed encoder. No provisions have been made for technologies such as the GNOME object embedding using Bonobo. The GStreamer core does not use network transparent technologies at the lowest level as it only adds overhead for the local case. That said, it shouldn't be hard to create a wrapper around the core components. There are tcp plugins now that implement a GStreamer Data Protocol that allows pipelines to be slit over TCP. These are located in the gst-plugins module directory gst/tcp. Catch up with the Windows world We need solid media handling if we want to see Linux succeed on the desktop. We must clear the road for commercially backed codecs and multimedia applications so that Linux can become an option for doing multimedia. The design goals We describe what we try to achieve with GStreamer. Clean and powerful GStreamer wants to provide a clean interface to: The application programmer who wants to build a media pipeline. The programmer can use an extensive set of powerful tools to create media pipelines without writing a single line of code. Performing complex media manipulations becomes very easy. The plugin programmer. Plugin programmers are provided a clean and simple API to create self-contained plugins. An extensive debugging and tracing mechanism has been integrated. GStreamer also comes with an extensive set of real-life plugins that serve as examples too. Object oriented GStreamer adheres to the GLib 2.0 object model. A programmer familiar with GLib 2.0 or older versions of GTK+ will be comfortable with GStreamer. GStreamer uses the mechanism of signals and object properties. All objects can be queried at runtime for their various properties and capabilities. GStreamer intends to be similar in programming methodology to GTK+. This applies to the object model, ownership of objects, reference counting, ... Extensible All GStreamer Objects can be extended using the GObject inheritance methods. All plugins are loaded dynamically and can be extended and upgraded independently. Allow binary only plugins Plugins are shared libraries that are loaded at runtime. Since all the properties of the plugin can be set using the GObject properties, there is no need (and in fact no way) to have any header files installed for the plugins. Special care has been taken to make plugins completely self-contained. All relevant aspects of plugins can be queried at run-time. High performance High performance is obtained by: using GLib's g_mem_chunk and fast non-blocking allocation algorithms where possible to minimize dynamic memory allocation. extremely light-weight links between plugins. Data can travel the pipeline with minimal overhead. Data passing between plugins only involves a pointer dereference in a typical pipeline. providing a mechanism to directly work on the target memory. A plugin can for example directly write to the X server's shared memory space. Buffers can also point to arbitrary memory, such as a sound card's internal hardware buffer. refcounting and copy on write minimize usage of memcpy. Sub-buffers efficiently split buffers into manageable pieces. the use of cothreads to minimize the threading overhead. Cothreads are a simple and fast user-space method for switching between subtasks. Cothreads were measured to consume as little as 600 cpu cycles. allowing hardware acceleration by using specialized plugins. using a plugin registry with the specifications of the plugins so that the plugin loading can be delayed until the plugin is actually used. all critical data passing is free of locks and mutexes. Clean core/plugins separation The core of GStreamer is essentially media-agnostic. It only knows about bytes and blocks, and only contains basic elements. The core of GStreamer is functional enough to even implement low-level system tools, like cp. All of the media handling functionality is provided by plugins external to the core. These tell the core how to handle specific types of media. Provide a framework for codec experimentation GStreamer also wants to be an easy framework where codec developers can experiment with different algorithms, speeding up the development of open and free multimedia codecs like Theora and Vorbis. Foundations This chapter of the guide introduces the basic concepts of GStreamer. Understanding these concepts will be important in reading any of the rest of this guide, all of them assume understanding of these basic concepts. Elements An element is the most important class of objects in GStreamer. You will usually create a chain of elements linked together and let data flow through this chain of elements. An element has one specific function, which can be the reading of data from a file, decoding of this data or outputting this data to your sound card (or anything else). By chaining together several such elements, you create a pipeline that can do a specific task, for example media playback or capture. GStreamer ships with a large collection of elements by default, making the development of a large variety of media applications possible. If needed, you can also write new elements. That topic is explained in great deal in the Plugin Writer's Guide. Bins and pipelines A bin is a container for a collection of elements. A pipeline is a special subtype of a bin that allows execution of all of its contained child elements. Since bins are subclasses of elements themselves, you can mostly control a bin as if it where an element, thereby abstracting away a lot of complexity for your application. You can, for example change state on all elements in a bin by changing the state of that bin itself. Bins also forward some signals from their contained childs (such as errors and tags). A pipeline is a bin that allows to run (technically referred to as iterating) its contained childs. By iterating a pipeline, data flow will start and media processing will take place. A pipeline requires iterating for anything to happen. you can also use threads, which automatically iterate the contained childs in a newly created threads. We will go into this in detail later on. Pads Pads are used to negotiate links and data flow between elements in GStreamer. A pad can be viewed as a plug or port on an element where links may be made with other elements, and through which data can flow to or from those elements. Pads have specific data handling capabilities: A pad can restrict the type of data that flows through it. Links are only allowed between two pads when the allowed data types of the two pads are compatible. Data types are negotiated between pads using a process called caps negotiation. Data types are described as a GstCaps. An analogy may be helpful here. A pad is similar to a plug or jack on a physical device. Consider, for example, a home theater system consisting of an amplifier, a DVD player, and a (silent) video projector. Linking the DVD player to the amplifier is allowed because both devices have audio jacks, and linking the projector to the DVD player is allowed because both devices have compatible video jacks. Links between the projector and the amplifier may not be made because the projector and amplifier have different types of jacks. Pads in GStreamer serve the same purpose as the jacks in the home theater system. For the most part, all data in GStreamer flows one way through a link between elements. Data flows out of one element through one or more source pads, and elements accept incoming data through one or more sink pads. Source and sink elements have only source and sink pads, respectively. Data is embodied in a GstData structure. Basic Concepts In these chapters, we will discuss the basic concepts of GStreamer and the most-used objects, such as elements, pads and buffers. We will use a visual representation of these objects so that we can visualize the more complex pipelines you will learn to build later on. You will get a first glance at the GStreamer API, which should be enough for building elementary applications. Later on in this part, you will also learn to build a basic command-line application. Note that this part will give a look into the low-level API and concepts of GStreamer. Once you're going to build applications, you might want to use higher-level APIs. Those will be discussed later on in this manual. Initializing GStreamer When writing a GStreamer application, you can simply include gst/gst.h to get access to the library functions. Besides that, you will also need to intialize the GStreamer library. Simple initialization Before the GStreamer libraries can be used, gst_init has to be called from the main application. This call will perform the necessary initialization of the library as well as parse the GStreamer-specific command line options. A typical program The code for this example is automatically extracted from the documentation and built under examples/manual in the GStreamer tarball. would have code to initialize GStreamer that looks like this: #include <gst/gst.h> int main (int argc, char *argv[]) { guint major, minor, micro; gst_init (&argc, &argv); gst_version (&major, &minor, &micro); printf ("This program is linked against GStreamer %d.%d.%d\n", major, minor, micro); return 0; } Use the GST_VERSION_MAJOR, GST_VERSION_MINOR and GST_VERSION_MICRO macros to get the GStreamer version you are building against, or use the function gst_version to get the version your application is linked against. GStreamer currently uses a scheme where versions with the same major and minor versions are API-/ and ABI-compatible. It is also possible to call the gst_init function with two NULL arguments, in which case no command line options will be parsed by GStreamer. The popt interface You can also use a popt table to initialize your own parameters as shown in the next example: #include <gst/gst.h> int main (int argc, char *argv[]) { gboolean silent = FALSE; gchar *savefile = NULL; struct poptOption options[] = { {"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0, "do not output status information", NULL}, {"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0, "save xml representation of pipeline to FILE and exit", "FILE"}, POPT_TABLEEND }; gst_init_with_popt_table (&argc, &argv, options); printf ("Run me with --help to see the Application options appended.\n"); return 0; } As shown in this fragment, you can use a popt table to define your application-specific command line options, and pass this table to the function gst_init_with_popt_table. Your application options will be parsed in addition to the standard GStreamer options. Elements The most important object in GStreamer for the application programmer is the GstElement object. An element is the basic building block for a media pipeline. All the different high-level components you will use are derived from GstElement. Every decoder, encoder, demuxer, video or audio output is in fact a GstElement What are elements? For the application programmer, elements are best visualized as black boxes. On the one end, you might put something in, the element does something with it and something else comes out at the other side. For a decoder element, ifor example, you'd put in encoded data, and the element would output decoded data. In the next chapter (see ), you will learn more about data input and output in elements, and how you can set that up in your application. Source elements Source elements generate data for use by a pipeline, for example reading from disk or from a sound card. shows how we will visualise a source element. We always draw a source pad to the right of the element. Visualisation of a source element Source elements do not accept data, they only generate data. You can see this in the figure because it only has a source pad (on the right). A source pad can only generate data. Filters, convertors, demuxers, muxers and codecs Filters and filter-like elements have both input and outputs pads. They operate on data that they receive on their input (sink) pads, and will provide data on their output (source) pads. Examples of such elements are a volume element (filter), a video scaler (convertor), an Ogg demuxer or a Vorbis decoder. Filter-like elements can have any number of source or sink pads. A video demuxer, for example, would have one sink pad and several (1-N) source pads, one for each elementary stream contained in the container format. Decoders, on the other hand, will only have one source and sink pads. Visualisation of a filter element shows how we will visualise a filter-like element. This specific element has one source and one sink element. Sink pads, receiving input data, are depicted at the left of the element; source pads are still on the right. Visualisation of a filter element with more than one output pad shows another filter-like element, this one having more than one output (source) pad. An example of one such element could, for example, be an Ogg demuxer for an Ogg stream containing both audio and video. One source pad will contain the elementary video stream, another will contain the elementary audio stream. Demuxers will generally fire signals when a new pad is created. The application programmer can then handle the new elementary stream in the signal handler. Sink elements Sink elements are end points in a media pipeline. They accept data but do not produce anything. Disk writing, soundcard playback, and video output would all be implemented by sink elements. shows a sink element. Visualisation of a sink elementCreating a GstElement The simplest way to create an element is to use gst_element_factory_make (). This function takes a factory name and an element name for the newly created element. The name of the element is something you can use later on to look up the element in a bin, for example. The name will also be used in debug output. You can pass NULL as the name argument to get a unique, default name. When you don't need the element anymore, you need to unref it using gst_object_unref (). This decreases the reference count for the element by 1. An element has a refcount of 1 when it gets created. An element gets destroyed completely when the refcount is decreased to 0. The following example The code for this example is automatically extracted from the documentation and built under examples/manual in the GStreamer tarball. shows how to create an element named source from the element factory named fakesrc. It checks if the creation succeeded. After checking, it unrefs the element. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *element; /* init GStreamer */ gst_init (&argc, &argv); /* create element */ element = gst_element_factory_make ("fakesrc", "source"); if (!element) { g_print ("Failed to create element of type 'fakesrc'\n"); return -1; } gst_object_unref (GST_OBJECT (element)); return 0; } gst_element_factory_make is actually a shorthand for a combination of two functions. A GstElement object is created from a factory. To create the element, you have to get access to a GstElementFactory object using a unique factory name. This is done with gst_element_factory_find (). The following code fragment is used to get a factory that can be used to create the fakesrc element, a fake data source. The function gst_element_factory_create () will use the element factory to create an element with the given name. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElementFactory *factory; GstElement * element; /* init GStreamer */ gst_init (&argc, &argv); /* create element, method #2 */ factory = gst_element_factory_find ("fakesrc"); if (!factory) { g_print ("Failed to find factory of type 'fakesrc'\n"); return -1; } element = gst_element_factory_create (factory, "source"); if (!element) { g_print ("Failed to create element, even though its factory exists!\n"); return -1; } gst_object_unref (GST_OBJECT (element)); return 0; } Using an element as a GObject A GstElement can have several properties which are implemented using standard GObject properties. The usual GObject methods to query, set and get property values and GParamSpecs are therefore supported. Every GstElement inherits at least one property from its parent GstObject: the "name" property. This is the name you provide to the functions gst_element_factory_make () or gst_element_factory_create (). You can get and set this property using the functions gst_object_set_name and gst_object_get_name or use the GObject property mechanism as shown below. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *element; const gchar *name; /* init GStreamer */ gst_init (&argc, &argv); /* create element */ element = gst_element_factory_make ("fakesrc", "source"); /* get name */ g_object_get (G_OBJECT (element), "name", &name, NULL); g_print ("The name of the element is '%s'.\n", name); gst_object_unref (GST_OBJECT (element)); return 0; } Most plugins provide additional properties to provide more information about their configuration or to configure the element. gst-inspect is a useful tool to query the properties of a particular element, it will also use property introspection to give a short explanation about the function of the property and about the parameter types and ranges it supports. See the appendix for details about gst-inspect. For more information about GObject properties we recommend you read the GObject manual and an introduction to The Glib Object system. A GstElement also provides various GObject signals that can be used as a flexible callback mechanism. Here, too, you can use gst-inspect to see which signals a specific elements supports. Together, signals and properties are the most basic way in which elements and applications interact. More about element factories In the previous section, we briefly introduced the GstElementFactory object already as a way to create instances of an element. Element factories, however, are much more than just that. Element factories are the basic types retrieved from the GStreamer registry, they describe all plugins and elements that GStreamer can create. This means that element factories are useful for automated element instancing, such as what autopluggers do, and for creating lists of available elements, such as what pipeline editing applications (e.g. GStreamer Editor) do. Getting information about an element using a factory Tools like gst-inspect will provide some generic information about an element, such as the person that wrote the plugin, a descriptive name (and a shortname), a rank and a category. The category can be used to get the type of the element that can be created using this element factory. Examples of categories include Codec/Decoder/Video (video decoder), Codec/Encoder/Video (video encoder), Source/Video (a video generator), Sink/Video (a video output), and all these exist for audio as well, of course. Then, there's also Codec/Demuxer and Codec/Muxer and a whole lot more. gst-inspect will give a list of all factories, and gst-inspect <factory-name> will list all of the above information, and a lot more. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElementFactory *factory; /* init GStreamer */ gst_init (&argc, &argv); /* get factory */ factory = gst_element_factory_find ("sinesrc"); if (!factory) { g_print ("You don't have the 'sinesrc' element installed, go get it!\n"); return -1; } /* display information */ g_print ("The '%s' element is a member of the category %s.\n" "Description: %s\n", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), gst_element_factory_get_klass (factory), gst_element_factory_get_description (factory)); return 0; } You can use gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY) to get a list of all the element factories that GStreamer knows about. Finding out what pads an element can contain Perhaps the most powerful feature of element factories is that they contain a full description of the pads that the element can generate, and the capabilities of those pads (in layman words: what types of media can stream over those pads), without actually having to load those plugins into memory. This can be used to provide a codec selection list for encoders, or it can be used for autoplugging purposes for media players. All current GStreamer-based media players and autopluggers work this way. We'll look closer at these features as we learn about GstPad and GstCaps in the next chapter: Linking elements By linking a source element with zero or more filter-like elements and finally a sink element, you set up a media pipeline. Data will flow through the elements. This is the basic concept of media handling in GStreamer. Visualisation of three linked elements By linking these three elements, we have created a very simple chain of elements. The effect of this will be that the output of the source element (element1) will be used as input for the filter-like element (element2). The filter-like element will do something with the data and send the result to the final sink element (element3). Imagine the above graph as a simple Ogg/Vorbis audio decoder. The source is a disk source which reads the file from disc. The second element is a Ogg/Vorbis audio decoder. The sink element is your soundcard, playing back the decoded audio data. We will use this simple graph to construct an Ogg/Vorbis player later in this manual. In code, the above graph is written like this: #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *source, *filter, *sink; /* init */ gst_init (&argc, &argv); /* create elements */ source = gst_element_factory_make ("fakesrc", "source"); filter = gst_element_factory_make ("identity", "filter"); sink = gst_element_factory_make ("fakesink", "sink"); /* link */ gst_element_link_many (source, filter, sink, NULL); [..] } For more specific behaviour, there are also the functions gst_element_link () and gst_element_link_pads (). You can also obtain references to individual pads and link those using various gst_pad_link_* () functions. See the API references for more details. Element States After being created, an element will not actually perform any actions yet. You need to change elements state to make it do something. GStreamer knows four element states, each with a very specific meaning. Those four states are: GST_STATE_NULL: this is the default state. This state will deallocate all resources held by the element. GST_STATE_READY: in the ready state, an element has allocated all of its global resources, that is, resources that can be kept within streams. You can think about opening devices, allocating buffers and so on. However, the stream is not opened in this state, so the stream positions is automatically zero. If a stream was previously opened, it should be closed in this state, and position, properties and such should be reset. GST_STATE_PAUSED: in this state, an element has opened the stream, but is not actively processing it. An element should not modify the stream's position, data or anything else in this state. When set back to PLAYING, it should continue processing at the point where it left off as soon as possible. GST_STATE_PLAYING: in the PLAYING state, an element does exactly the same as in the PAUSED state, except that it actually processes data. You can change the state of an element using the function gst_element_set_state (). If you set an element to another state, GStreamer will internally traverse all intermediate states. So if you set an element from NULL to PLAYING, GStreamer will internally set the element to READY and PAUSED in between. Even though an element in GST_STATE_PLAYING is ready for data processing, it will not necessarily do that. If the element is placed in a thread (see ), it will process data automatically. In other cases, however, you will need to iterate the element's container. Bins A bin is a container element. You can add elements to a bin. Since a bin is an element itself, a bin can be handled in the same way as any other element. Therefore, the whole previous chapter () applies to bins as well. What are bins Bins allow you to combine a group of linked elements into one logical element. You do not deal with the individual elements anymore but with just one element, the bin. We will see that this is extremely powerful when you are going to construct complex pipelines since it allows you to break up the pipeline in smaller chunks. The bin will also manage the elements contained in it. It will figure out how the data will flow in the bin and generate an optimal plan for that data flow. Plan generation is one of the most complicated procedures in GStreamer. You will learn more about this process, called scheduling, in . Visualisation of a bin with some elements in it There are two specialized types of bins available to the GStreamer programmer: A pipeline: a generic container that allows scheduling of the containing elements. The toplevel bin has to be a pipeline. Every application thus needs at least one of these. Applications can iterate pipelines using gst_bin_iterate () to make it process data while in the playing state. A thread: a bin that will be run in a separate execution thread. You will have to use this bin if you have to carefully synchronize audio and video, or for buffering. You will learn more about threads in . Creating a bin Bins are created in the same way that other elements are created, i.e. using an element factory. There are also convenience functions available (gst_bin_new (), gst_thread_new () and gst_pipeline_new ()). To add elements to a bin or remove elements from a bin, you can use gst_bin_add () and gst_bin_remove (). Note that the bin that you add an element to will take ownership of that element. If you destroy the bin, the element will be dereferenced with it. If you remove an element from a bin, it will be dereferenced automatically. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *bin, *pipeline, *source, *sink; /* init */ gst_init (&argc, &argv); /* create */ pipeline = gst_pipeline_new ("my_pipeline"); bin = gst_pipeline_new ("my_bin"); source = gst_element_factory_make ("fakesrc", "source"); sink = gst_element_factory_make ("fakesink", "sink"); /* set up pipeline */ gst_bin_add_many (GST_BIN (bin), source, sink, NULL); gst_bin_add (GST_BIN (pipeline), bin); gst_element_link (source, sink); [..] } There are various functions to lookup elements in a bin. You can also get a list of all elements that a bin contains using the function gst_bin_get_list (). See the API references of GstBin for details. Custom bins The application programmer can create custom bins packed with elements to perform a specific task. This allows you, for example, to write an Ogg/Vorbis decoder with just the following lines of code: int main (int argc char *argv[]) { GstElement *player; /* init */ gst_init (&argc, &argv); /* create player */ player = gst_element_factory_make ("oggvorbisplayer", "player"); /* set the source audio file */ g_object_set (G_OBJECT (player), "location", "helloworld.ogg", NULL); /* start playback */ gst_element_set_state (GST_ELEMENT (player), GST_STATE_PLAYING); [..] } Custom bins can be created with a plugin or an XML description. You will find more information about creating custom bin in the Plugin Writers Guide. Pads and capabilities As we have seen in , the pads are the element's interface to the outside world. Data streams from one element's source pad to another element's sink pad. The specific type of media that the element can handle will be exposed by the pad's capabilities. We will talk more on capabilities later in this chapter (see ). Pads A pad type is defined by two properties: its direction and its availability. As we've mentioned before, GStreamer defines two pad directions: source pads and sink pads. This terminology is defined from the view of within the element: elements receive data on their sink pads and generate data on their source pads. Schematically, sink pads are drawn on the left side of an element, whereas source pads are drawn on the right side of an element. In such graphs, data flows from left to right. In reality, there is no objection to data flowing from a source pad to the sink pad of an element upstream (to the left of this element in drawings). Data will, however, always flow from a source pad of one element to the sink pad of another. Pad directions are very simple compared to pad availability. A pad can have any of three availabilities: always, sometimes and on request. The meaning of those three types is exactly as it says: always pads always exist, sometimes pad exist only in certain cases (and can disappear randomly), and on-request pads appear only if explicitely requested by applications. Dynamic (or sometimes) pads Some elements might not have all of their pads when the element is created. This can happen, for example, with an Ogg demuxer element. The element will read the Ogg stream and create dynamic pads for each contained elementary stream (vorbis, theora) when it detects such a stream in the Ogg stream. Likewise, it will delete the pad when the stream ends. This principle is very useful for demuxer elements, for example. Running gst-inspect oggdemux will show that the element has only one pad: a sink pad called 'sink'. The other pads are dormant. You can see this in the pad template because there is an Exists: Sometimes property. Depending on the type of Ogg file you play, the pads will be created. We will see that this is very important when you are going to create dynamic pipelines. You can attach a signal handler to an element to inform you when the element has created a new pad from one of its sometimes pad templates. The following piece of code is an example of how to do this: #include <gst/gst.h> static void cb_new_pad (GstElement *element, GstPad *pad, gpointer data) { g_print ("A new pad %s was created\n", gst_pad_get_name (pad)); /* here, you would setup a new pad link for the newly created pad */ [..] } int main(int argc, char *argv[]) { GstElement *pipeline, *source, *demux; /* init */ gst_init (&argc, &argv); /* create elements */ pipeline = gst_pipeline_new ("my_pipeline"); source = gst_element_factory_make ("filesrc", "source"); g_object_set (source, "location", argv[1], NULL); demux = gst_element_factory_make ("oggdemux", "demuxer"); /* you would normally check that the elements were created properly */ /* put together a pipeline */ gst_bin_add_many (GST_BIN (pipeline), source, demux, NULL); gst_element_link (source, demux); /* listen for newly created pads */ g_signal_connect (demux, "new-pad", G_CALLBACK (cb_new_pad), NULL); /* start the pipeline */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); [..] } Request pads An element can also have request pads. These pads are not created automatically but are only created on demand. This is very useful for multiplexers, aggregators and tee elements. Aggregators are elements that merge the content of several input streams together into one output stream. Tee elements are the reverse: they are elements that have one input stream and copy this stream to each of their output pads, which are created on request. Whenever an application needs another copy of the stream, it can simply request a new output pad from the tee element. The following piece of code shows how you can request a new output pad from a tee element: static void some_function (GstElement *tee) { GstPad * pad; pad = gst_element_get_request_pad (tee, "src%d"); g_print ("A new pad %s was created\n", gst_pad_get_name (pad)); /* here, you would link the pad */ [..] } The gst_element_get_request_pad () method can be used to get a pad from the element based on the name of the pad template. It is also possible to request a pad that is compatible with another pad template. This is very useful if you want to link an element to a multiplexer element and you need to request a pad that is compatible. The method gst_element_get_compatible_pad () can be used to request a compatible pad, as shown in the next example. It will request a compatible pad from an Ogg multiplexer from any input. static void link_to_multiplexer (GstPad *tolink_pad, GstElement *mux) { GstPad *pad; pad = gst_element_get_compatible_pad (mux, tolink_pad); gst_pad_link (tolinkpad, pad); g_print ("A new pad %s was created and linked to %s\n", gst_pad_get_name (pad), gst_pad_get_name (tolink_pad)); } Capabilities of a pad Since the pads play a very important role in how the element is viewed by the outside world, a mechanism is implemented to describe the data that can flow or currently flows through the pad by using capabilities. Here,w e will briefly describe what capabilities are and how to use them, enough to get an understanding of the concept. For an in-depth look into capabilities and a list of all capabilities defined in GStreamer, see the Plugin Writers Guide. Capabilities are attached to pad templates and to pads. For pad templates, it will describe the types of media that may stream over a pad created from this template. For pads, it can either be a list of possible caps (usually a copy of the pad template's capabilities), in which case the pad is not yet negotiated, or it is the type of media that currently streams over this pad, in which case the pad has been negotiated already. Dissecting capabilities A pads capabilities are described in a GstCaps object. Internally, a GstCaps will contain one or more GstStructure that will describe one media type. A negotiated pad will have capabilities set that contain exactly one structure. Also, this structure will contain only fixed values. These constraints are not true for unnegotiated pads or pad templates. As an example, below is a dump of the capabilities of the vorbisdec element, which you will get by running gst-inspect vorbisdec. You will see two pads: a source and a sink pad. Both of these pads are always available, and both have capabilities attached to them. The sink pad will accept vorbis-encoded audio data, with the mime-type audio/x-vorbis. The source pad will be used to send raw (decoded) audio samples to the next element, with a raw audio mime-type (either audio/x-raw-int or audio/x-raw-float). The source pad will also contain properties for the audio samplerate and the amount of channels, plus some more that you don't need to worry about for now. Pad Templates: SRC template: 'src' Availability: Always Capabilities: audio/x-raw-float rate: [ 8000, 50000 ] channels: [ 1, 2 ] endianness: 1234 width: 32 buffer-frames: 0 SINK template: 'sink' Availability: Always Capabilities: audio/x-vorbis Properties and values Properties are used to describe extra information for capabilities. A property consists of a key (a string) and a value. There are different possible value types that can be used: Basic types, this can be pretty much any GType registered with Glib. Those properties indicate a specific, non-dynamic value for this property. Examples include: An integer value (G_TYPE_INT): the property has this exact value. A boolean value (G_TYPE_BOOLEAN): the property is either TRUE or FALSE. A float value (G_TYPE_FLOAT): the property has this exact floating point value. A string value (G_TYPE_STRING): the property contains a UTF-8 string. Range types are GTypes registered by GStreamer to indicate a range of possible values. They are used for indicating allowed audio samplerate values or supported video sizes. The two types defined in GStreamer are: An integer range value (GST_TYPE_INT_RANGE): the property denotes a range of possible integers, with a lower and an upper boundary. The vorbisdec element, for example, has a rate property that can be between 8000 and 50000. A float range value (GST_TYPE_FLOAT_RANGE): the property denotes a range of possible floating point values, with a lower and an upper boundary. A list value (GST_TYPE_LIST): the property can take any value from a list of basic values given in this list. What capabilities are used for Capabilities describe the type of data that is streamed between two pads, or that one pad (template) supports. This makes them very useful for various purposes: Autoplugging: automatically finding elements to link to a pad based on its capabilities. All autopluggers use this method. Compatibility detection: when two pads are linked, GStreamer can verify if the two pads are talking about the same media type. The process of linking two pads and checking if they are compatible is called caps negotiation. Metadata: by reading the capabilities from a pad, applications can provide information about the type of media that is being streamed over the pad, which is information about the stream thatis currently being played back. Filtering: an application can use capabilities to limit the possible media types that can stream between two pads to a specific subset of their supported stream types. An application can, for example, use filtered caps to set a specific (non-fixed) video size that will stream between two pads. Using capabilities for metadata A pad can have a set (i.e. one or more) of capabilities attached to it. You can get values of properties in a set of capabilities by querying individual properties of one structure. You can get a structure from a caps using gst_caps_get_structure (): static void read_video_props (GstCaps *caps) { gint width, height; const GstStructure *str; str = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (str, "width", &width) || !gst_structure_get_int (str, "height", &height)) { g_print ("No width/height available\n"); return; } g_print ("The video size of this set of capabilities is %dx%d\n", width, height); } Creating capabilities for filtering While capabilities are mainly used inside a plugin to describe the media type of the pads, the application programmer also has to have basic understanding of capabilities in order to interface with the plugins, especially when using filtered caps. When you're using filtered caps or fixation, you're limiting the allowed types of media that can stream between two pads to a subset of their supported media types. You do this by filtering using your own set of capabilities. In order to do this, you need to create your own GstCaps. The simplest way to do this is by using the convenience function gst_caps_new_simple (): static void link_pads_with_filter (GstPad *one, GstPad *other) { GstCaps *caps; caps = gst_caps_new_simple ("video/x-raw-yuv", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL); gst_pad_link_filtered (one, other, caps); } In some cases, you will want to create a more elaborate set of capabilities to filter a link between two pads. Then, this function is too simplistic and you'll want to use the method gst_caps_new_full (): static void link_pads_with_filter (GstPad *one, GstPad *other) { GstCaps *caps; caps = gst_caps_new_full ( gst_structure_new ("video/x-raw-yuv", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL), gst_structure_new ("video/x-raw-rgb", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL), NULL); gst_pad_link_filtered (one, other, caps); } See the API references for the full API of GstStructure and GstCaps. Ghost pads You can see from how a bin has no pads of its own. This is where "ghost pads" come into play. Visualisation of a GstBin element without ghost pads A ghost pad is a pad from some element in the bin that can be accessed directly from the bin as well. Compare it to a symbolic link in UNIX filesystems. Using ghost pads on bins, the bin also has a pad and can transparently be used as an element in other parts of your code. Visualisation of a GstBin element with a ghost pad is a representation of a ghost pad. The sink pad of element one is now also a pad of the bin. Obviously, ghost pads can be added to any type of elements, not just to a GstBin. A ghostpad is created using the function gst_element_add_ghost_pad (): #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *bin, *sink; /* init */ gst_init (&argc, &argv); /* create element, add to bin, add ghostpad */ sink = gst_element_factory_make ("fakesink", "sink"); bin = gst_bin_new ("mybin"); gst_bin_add (GST_BIN (bin), sink); gst_element_add_ghost_pad (bin, gst_element_get_pad (sink, "sink"), "sink"); [..] } In the above example, the bin now also has a pad: the pad called sink of the given element. The bin can, from here on, be used as a substitute for the sink element. You could, for example, link another element to the bin. Buffers and Events The data flowing through a pipeline consists of a combination of buffers and events. Buffers contain the actual pipeline data. Events contain control information, such as seeking information and end-of-stream notifiers. All this will flow through the pipeline automatically when it's running. This chapter is mostly meant to explain the concept to you; you don't need to do anything for this. Buffers Buffers contain the data that will flow through the pipeline you have created. A source element will typically create a new buffer and pass it through a pad to the next element in the chain. When using the GStreamer infrastructure to create a media pipeline you will not have to deal with buffers yourself; the elements will do that for you. A buffer consists, amongst others, of: A pointer to a piece of memory. The size of the memory. A timestamp for the buffer. A refcount that indicates how many elements are using this buffer. This refcount will be used to destroy the buffer when no element has a reference to it. The simple case is that a buffer is created, memory allocated, data put in it, and passed to the next element. That element reads the data, does something (like creating a new buffer and decoding into it), and unreferences the buffer. This causes the data to be free'ed and the buffer to be destroyed. A typical video or audio decoder works like this. There are more complex scenarios, though. Elements can modify buffers in-place, i.e. without allocating a new one. Elements can also write to hardware memory (such as from video-capture sources) or memory allocated from the X-server using XShm). Buffers can be read-only, and so on. Events Events are control particles that are sent both up- and downstream in a pipeline along with buffers. Downstream events notify fellow elements of stream states. Possible events include discontinuities, flushes, end-of-stream notifications and so on. Upstream events are used both in application-element interaction as well as event-event interaction to request changes in stream state, such as seeks. For applications, only upstream events are important. Downstream events are just explained to get a more complete picture of the data concept. Since most applications seek in time units, our example below does so too: static void seek_to_time (GstElement *element, guint64 time_ns) { GstEvent *event; event = gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME, time_ns); gst_element_send_event (element, event); } The function gst_element_seek () is a shortcut for this. This is mostly just to show how it all works. Your first application This chapter will summarize everything you've learned in the previous chapters. It describes all aspects of a simple GStreamer application, including initializing libraries, creating elements, packing elements together in a pipeline and playing this pipeline. By doing all this, you will be able to build a simple Ogg/Vorbis audio player. Hello world We're going to create a simple first application, a simple Ogg/Vorbis command-line audio player. For this, we will use only standard GStreamer components. The player will read a file specified on the command-line. Let's get started! We've learned, in , that the first thing to do in your application is to initialize GStreamer by calling gst_init (). Also, make sure that the application includes gst/gst.h so all function names and objects are properly defined. Use #include <gst/gst.h> to do that. Next, you'll want to create the different elements using gst_element_factory_make (). For an Ogg/Vorbis audio player, we'll need a source element that reads files from a disk. GStreamer includes this element under the name filesrc. Next, we'll need something to parse the file and decoder it into raw audio. GStreamer has two elements for this: the first parses Ogg streams into elementary streams (video, audio) and is called oggdemux. The second is a Vorbis audio decoder, it's conveniently called vorbisdec. Since oggdemux creates dynamic pads for each elementary stream, you'll need to set a new-pad event handler on the oggdemux element, like you've learned in , to link the Ogg parser and the Vorbis decoder elements together. At last, we'll also need an audio output element, we will use alsasink, which outputs sound to an ALSA audio device. The last thing left to do is to add all elements into a container element, a GstPipeline, and iterate this pipeline until we've played the whole song. We've previously learned how to add elements to a container bin in , and we've learned about element states in . We will use the function gst_bin_sync_children_state () to synchronize the state of a bin on all of its contained children. Let's now add all the code together to get our very first audio player: #include <gst/gst.h> /* * Global objects are usually a bad thing. For the purpose of this * example, we will use them, however. */ GstElement *pipeline, *source, *parser, *decoder, *conv, *scale, *sink; static void new_pad (GstElement *element, GstPad *pad, gpointer data) { /* We can now link this pad with the audio decoder and * add both decoder and audio output to the pipeline. */ gst_pad_link (pad, gst_element_get_pad (decoder, "sink")); gst_bin_add_many (GST_BIN (pipeline), decoder, conv, scale, sink, NULL); /* This function synchronizes a bins state on all of its * contained children. */ gst_bin_sync_children_state (GST_BIN (pipeline)); } int main (int argc, char *argv[]) { /* initialize GStreamer */ gst_init (&argc, &argv); /* check input arguments */ if (argc != 2) { g_print ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]); return -1; } /* create elements */ pipeline = gst_pipeline_new ("audio-player"); source = gst_element_factory_make ("filesrc", "file-source"); parser = gst_element_factory_make ("oggdemux", "ogg-parser"); decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder"); conv = gst_element_factory_make ("audioconvert", "conv"); scale = gst_element_factory_make ("audioscale", "scale"); sink = gst_element_factory_make ("alsasink", "alsa-output"); /* set filename property on the file source */ g_object_set (G_OBJECT (source), "location", argv[1], NULL); /* link together - note that we cannot link the parser and * decoder yet, becuse the parser uses dynamic pads. For that, * we set a new-pad signal handler. */ gst_element_link (source, parser); gst_element_link_many (decoder, conv, scale, sink, NULL); g_signal_connect (parser, "new-pad", G_CALLBACK (new_pad), NULL); /* put all elements in a bin - or at least the ones we will use * instantly. */ gst_bin_add_many (GST_BIN (pipeline), source, parser, NULL); /* Now set to playing and iterate. We will set the decoder and * audio output to ready so they initialize their memory already. * This will decrease the amount of time spent on linking these * elements when the Ogg parser emits the new-pad signal. */ gst_element_set_state (decoder, GST_STATE_READY); gst_element_set_state (conv, GST_STATE_READY); gst_element_set_state (scale, GST_STATE_READY); gst_element_set_state (sink, GST_STATE_READY); gst_element_set_state (pipeline, GST_STATE_PLAYING); /* and now iterate - the rest will be automatic from here on. * When the file is finished, gst_bin_iterate () will return * FALSE, thereby terminating this loop. */ while (gst_bin_iterate (GST_BIN (pipeline))) ; /* clean up nicely */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } We now have created a complete pipeline. We can visualise the pipeline as follows: The "hello world" pipelineCompiling and Running helloworld.c To compile the helloworld example, use: gcc -Wall $(pkg-config --cflags --libs gstreamer-0.8) helloworld.c -o helloworld. GStreamer makes use of pkg-config to get compiler and linker flags needed to compile this application. If you're running a non-standard installation, make sure the PKG_CONFIG_PATH environment variable is set to the correct location ($libdir/pkgconfig). application against the uninstalled location. You can run this example application with ./helloworld file.ogg. Substitute file.ogg with your favourite Ogg/Vorbis file. Conclusion This concludes our first example. As you see, setting up a pipeline is very low-level but powerful. You will see later in this manual how you can create a more powerful media player with even less effort using higher-level interfaces. We will discuss all that in . We will first, however, go more in-depth into more advanced GStreamer internals. It should be clear from the example that we can very easily replace the filesrc element with some other element that reads data from a network, or some other data source element that is better integrated with your desktop environment. Also, you can use other decoders and parsers to support other media types. You can use another audio sink if you're not running Linux, but Mac OS X, Windows or FreeBSD, or you can instead use a filesink to write audio files to disk instead of playing them back. By using an audio card source, you can even do audio capture instead of playback. All this shows the reusability of GStreamer elements, which is its greatest advantage. Advanced GStreamer concepts In this part we will cover the more advanced features of GStreamer. With the basics you learned in the previous part you should be able to create a simple application. However, GStreamer provides much more candy than just the basics of playing back audio files. In this chapter, you will learn more of the low-level features and internals of GStreamer, such as threads, scheduling, synchronization, metadata, interfaces and dynamic parameters. Position tracking and seeking So far, we've looked at how to create a pipeline to do media processing and how to make it run ("iterate"). Most application developers will be interested in providing feedback to the user on media progress. Media players, for example, will want to show a slider showing the progress in the song, and usually also a label indicating stream length. Transcoding applications will want to show a progress bar on how much % of the task is done. GStreamer has built-in support for doing all this using a concept known as querying. Since seeking is very similar, it will be discussed here as well. Seeking is done using the concept of events. Querying: getting the position or length of a stream Querying is defined as requesting a specific stream-property related to progress tracking. This includes getting the length of a stream (if available) or getting the current position. Those stream properties can be retrieved in various formats such as time, audio samples, video frames or bytes. The functions used are gst_element_query () and gst_pad_query (). Obviously, using either of the above-mentioned functions requires the application to know which element or pad to run the query on. This is tricky, but there are some good sides to the story. The good thing is that elements (or, rather, pads - since gst_element_query () internally calls gst_pad_query ()) forward (dispatch) events and queries to peer pads (or elements) if they don't handle it themselves. The bad side is that some elements (or pads) will handle events, but not the specific formats that you want, and therefore it still won't work. Most queries will, fortunately, work fine. Queries are always dispatched backwards. This means, effectively, that it's easiest to run the query on your video or audio output element, and it will take care of dispatching the query to the element that knows the answer (such as the current position or the media length; usually the demuxer or decoder). #include <gst/gst.h> gint main (gint argc, gchar *argv[]) { GstElement *sink, *pipeline; [..] /* run pipeline */ do { gint64 len, pos; GstFormat fmt = GST_FORMAT_TIME; if (gst_element_query (sink, GST_QUERY_POSITION, &fmt, &pos) && gst_element_query (sink, GST_QUERY_TOTAL, &fmt, &len)) { g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", GST_TIME_ARGS (pos), GST_TIME_ARGS (len)); } } while (gst_bin_iterate (GST_BIN (pipeline))); [..] } If you are having problems with the dispatching behaviour, your best bet is to manually decide which element to start running the query on. You can get a list of supported formats and query-types with gst_element_get_query_types () and gst_element_get_formats (). Events: seeking (and more) Events work in a very similar way as queries. Dispatching, for example, works exactly the same for events (and also has the same limitations). Although there are more ways in which applications and elements can interact using events, we will only focus on seeking here. This is done using the seek-event. A seek-event contains a seeking offset, a seek method (which indicates relative to what the offset was given), a seek format (which is the unit of the offset, e.g. time, audio samples, video frames or bytes) and optionally a set of seeking-related flags (e.g. whether internal buffers should be flushed). The behaviour of a seek is also wrapped in the function gst_element_seek (). static void seek_to_time (GstElement *audiosink, gint64 time_nanonseconds) { gst_element_seek (audiosink, GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_FLUSH, time_nanoseconds); } Metadata GStreamer makes a clear distinction between two types of metadata, and has support for both types. The first is stream tags, which describe the content of a stream in a non-technical way. Examples include the author of a song, the title of that very same song or the album it is a part of. The other type of metadata is stream-info, which is a somewhat technical description of the properties of a stream. This can include video size, audio samplerate, codecs used and so on. Tags are handled using the GStreamer tagging system. Stream-info can be retrieved from a GstPad. Stream information Stream information can most easily be read by reading them from a GstPad. This has already been discussed before in . Therefore, we will skip it here. Tag reading Tag reading is remarkably simple in GStreamer Every element supports the found-tag signal, which will be fired each the time the element reads tags from the stream. A GstBin will conveniently forward tags found by its childs. Therefore, in most applications, you will only need to connect to the found-tag signal on the top-most bin in your pipeline, and you will automatically retrieve all tags from the stream. Note, however, that the found-tag might be fired multiple times and by multiple elements in the pipeline. It is the application's responsibility to put all those tags together and display them to the user in a nice, coherent way. Tag writing WRITEME Interfaces In , you have learned how to use GObject properties as a simple way to do interaction between applications and elements. This method suffices for the simple'n'straight settings, but fails for anything more complicated than a getter and setter. For the more complicated use cases, GStreamer uses interfaces based on the Glib GInterface type. Most of the interfaces handled here will not contain any example code. See the API references for details. Here, we will just describe the scope and purpose of each interface. The Mixer interface The mixer interface provides a uniform way to control the volume on a hardware (or software) mixer. The interface is primarily intended to be implemented by elements for audio inputs and outputs that talk directly to the hardware (e.g. OSS or ALSA plugins). Using this interface, it is possible to control a list of tracks (such as Line-in, Microphone, etc.) from a mixer element. They can be muted, their volume can be changed and, for input tracks, their record flag can be set as well. Example plugins implementing this interface include the OSS elements (osssrc, osssink, ossmixer) and the ALSA plugins (alsasrc, alsasink and alsamixer). The Tuner interface The tuner interface is a uniform way to control inputs and outputs on a multi-input selection device. This is primarily used for input selection on elements for TV- and capture-cards. Using this interface, it is possible to select one track from a list of tracks supported by that tuner-element. The tuner will than select that track for media-processing internally. This can, for example, be used to switch inputs on a TV-card (e.g. from Composite to S-video). This interface is currently only implemented by the Video4linux and Video4linux2 elements. The Color Balance interface The colorbalance interface is a way to control video-related properties on an element, such as brightness, contrast and so on. It's sole reason for existance is that, as far as its authors know, there's no way to dynamically register properties using GObject. The colorbalance interface is implemented by several plugins, including xvimagesink and the Video4linux and Video4linux2 elements. The Property Probe interface The property probe is a way to autodetect allowed values for a GObject property. It's primary use (and the only thing that we currently use it for) is to autodetect devices in several elements. For example, the OSS elements use this interface to detect all OSS devices on a system. Applications can then probe this property and get a list of detected devices. Given the overlap between HAL and the practical implementations of this interface, this might in time be deprecated in favour of HAL. This interface is currently implemented by many elements, including the ALSA, OSS, Video4linux and Video4linux2 elements. The X Overlay interface The X Overlay interface was created to solve the problem of embedding video streams in an application window. The application provides an X-window to the element implementing this interface to draw on, and the element will then use this X-window to draw on rather than creating a new toplevel window. This is useful to embed video in video players. This interface is implemented by, amongst others, the Video4linux and Video4linux2 elements and by ximagesink, xvimagesink and sdlvideosink. Clocks in GStreamer WRITEME Dynamic ParametersGetting Started The Dynamic Parameters subsystem is contained within the gstcontrol library. You need to include the header in your application's source file: ... #include <gst/gst.h> #include <gst/control/control.h> ... Your application should link to the shared library gstcontrol. The gstcontrol library needs to be initialized when your application is run. This can be done after the the GStreamer library has been initialized. ... gst_init(&argc,&argv); gst_control_init(&argc,&argv); ... Creating and Attaching Dynamic Parameters Once you have created your elements you can create and attach dparams to them. First you need to get the element's dparams manager. If you know exactly what kind of element you have, you may be able to get the dparams manager directly. However if this is not possible, you can get the dparams manager by calling gst_dpman_get_manager. Once you have the dparams manager, you must set the mode that the manager will run in. There is currently only one mode implemented called "synchronous" - this is used for real-time applications where the dparam value cannot be known ahead of time (such as a slider in a GUI). The mode is called "synchronous" because the dparams are polled by the element for changes before each buffer is processed. Another yet-to-be-implemented mode is "asynchronous". This is used when parameter changes are known ahead of time - such as with a timelined editor. The mode is called "asynchronous" because parameter changes may happen in the middle of a buffer being processed. GstElement *sinesrc; GstDParamManager *dpman; ... sinesrc = gst_element_factory_make("sinesrc","sine-source"); ... dpman = gst_dpman_get_manager (sinesrc); gst_dpman_set_mode(dpman, "synchronous"); If you don't know the names of the required dparams for your element you can call gst_dpman_list_dparam_specs(dpman) to get a NULL terminated array of param specs. This array should be freed after use. You can find the name of the required dparam by calling g_param_spec_get_name on each param spec in the array. In our example, "volume" will be the name of our required dparam. Each type of dparam currently has its own new function. This may eventually be replaced by a factory method for creating new instances. A default dparam instance can be created with the gst_dparam_new function. Once it is created it can be attached to a required dparam in the element. GstDParam *volume; ... volume = gst_dparam_new(G_TYPE_DOUBLE); if (gst_dpman_attach_dparam (dpman, "volume", volume)){ /* the dparam was successfully attached */ ... } Changing Dynamic Parameter Values All interaction with dparams to actually set the dparam value is done through simple GObject properties. There is a property value for each type that dparams supports - these currently being "value_double", "value_float", "value_int" and "value_int64". To set the value of a dparam, simply set the property which matches the type of your dparam instance. #define ZERO(mem) memset(&mem, 0, sizeof(mem)) ... gdouble set_to_value; GstDParam *volume; GValue set_val; ZERO(set_val); g_value_init(&set_val, G_TYPE_DOUBLE); ... g_value_set_double(&set_val, set_to_value); g_object_set_property(G_OBJECT(volume), "value_double", &set_val); Or if you create an actual GValue instance: gdouble set_to_value; GstDParam *volume; GValue *set_val; set_val = g_new0(GValue,1); g_value_init(set_val, G_TYPE_DOUBLE); ... g_value_set_double(set_val, set_to_value); g_object_set_property(G_OBJECT(volume), "value_double", set_val); Different Types of Dynamic Parameter There are currently only two implementations of dparams so far. They are both for real-time use so should be run in the "synchronous" mode. GstDParam - the base dparam type All dparam implementations will subclass from this type. It provides a basic implementation which simply propagates any value changes as soon as it can. A new instance can be created with the function GstDParam* gst_dparam_new (GType type). It has the following object properties: "value_double" - the property to set and get if it is a double dparam "value_float" - the property to set and get if it is a float dparam "value_int" - the property to set and get if it is an integer dparam "value_int64" - the property to set and get if it is a 64 bit integer dparam "is_log" - readonly boolean which is TRUE if the param should be displayed on a log scale "is_rate" - readonly boolean which is TRUE if the value is a proportion of the sample rate. For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz. GstDParamSmooth - smoothing real-time dparam Some parameter changes can create audible artifacts if they change too rapidly. The GstDParamSmooth implementation can greatly reduce these artifacts by limiting the rate at which the value can change. This is currently only supported for double and float dparams - the other types fall back to the default implementation. A new instance can be created with the function GstDParam* gst_dpsmooth_new (GType type). It has the following object properties: "update_period" - an int64 value specifying the number nanoseconds between updates. This will be ignored in "synchronous" mode since the buffer size dictates the update period. "slope_time" - an int64 value specifying the time period to use in the maximum slope calculation "slope_delta_double" - a double specifying the amount a double value can change in the given slope_time. "slope_delta_float" - a float specifying the amount a float value can change in the given slope_time. Audible artifacts may not be completely eliminated by using this dparam. The only way to eliminate artifacts such as "zipper noise" would be for the element to implement its required dparams using the array method. This would allow dparams to change parameters at the sample rate which should eliminate any artifacts. Timelined dparams A yet-to-be-implemented subclass of GstDParam will add an API which allows the creation and manipulation of points on a timeline. This subclass will also provide a dparam implementation which uses linear interpolation between these points to find the dparam value at any given time. Further subclasses can extend this functionality to implement more exotic interpolation algorithms such as splines. Threads GStreamer has support for multithreading through the use of the GstThread object. This object is in fact a special GstBin that will start a new thread (using Glib's GThread system) when started. To create a new thread, you can simply use gst_thread_new (). From then on, you can use it similar to how you would use a GstBin. You can add elements to it, change state and so on. The largest difference between a thread and other bins is that the thread does not require iteration. Once set to the GST_STATE_PLAYING state, it will iterate its contained children elements automatically. shows how a thread can be visualised. A threadWhen would you want to use a thread? There are several reasons to use threads. However, there's also some reasons to limit the use of threads as much as possible. We will go into the drawbacks of threading in GStreamer in the next section. Let's first list some situations where threads can be useful: Data buffering, for example when dealing with network streams or when recording data from a live stream such as a video or audio card. Short hickups elsewhere in the pipeline will not cause data loss. See for a visualization of this idea. Synchronizing output devices, e.g. when playing a stream containing both video and audio data. By using threads for both outputs, they will run independently and their synchronization will be better. Data pre-rolls. You can use threads and queues (thread boundaries) to cache a few seconds of data before playing. By using this approach, the whole pipeline will already be setup and data will already be decoded. When activating the rest of the pipeline, the switch from PAUSED to PLAYING will be instant. a two-threaded decoder with a queue Above, we've mentioned the queue element several times now. A queue is a thread boundary element. It does so by using a classic provider/receiver model as learned in threading classes at universities all around the world. By doing this, it acts both as a means to make data throughput between threads threadsafe, and it can also act as a buffer. Queues have several GObject properties to be configured for specific uses. For example, you can set lower and upper tresholds for the element. If there's less data than the lower treshold (default: disabled), it will block output. If there's more data than the upper treshold, it will block input or (if configured to do so) drop data. Constraints placed on the pipeline by the GstThread Within the pipeline, everything is the same as in any other bin. The difference lies at the thread boundary, at the link between the thread and the outside world (containing bin). Since GStreamer is fundamentally buffer-oriented rather than byte-oriented, the natural solution to this problem is an element that can "buffer" the buffers between the threads, in a thread-safe fashion. This element is the queue element. A queue should be placed in between any two elements whose pads are linked together while the elements live in different threads. It doesn't matter if the queue is placed in the containing bin or in the thread itself, but it needs to be present on one side or the other to enable inter-thread communication. If you are writing a GUI application, making the top-level bin a thread will make your GUI more responsive. If it were a pipeline instead, it would have to be iterated by your application's event loop, which increases the latency between events (say, keyboard presses) and responses from the GUI. In addition, any slight hang in the GUI would delay iteration of the pipeline, which (for example) could cause pops in the output of the sound card, if it is an audio pipeline. A problem with using threads is, however, thread contexts. If you connect to a signal that is emitted inside a thread, then the signal handler for this thread will be executed in that same thread! This is very important to remember, because many graphical toolkits can not run multi-threaded. Gtk+, for example, only allows threaded access to UI objects if you explicitely use mutexes. Not doing so will result in random crashes and X errors. A solution many people use is to place an idle handler in the signal handler, and have the actual signal emission code be executed in the idle handler, which will be executed from the mainloop. Generally, if you use threads, you will encounter some problems. Don't hesistate to ask us for help in case of problems. A threaded example application As an example we show the helloworld program that we coded in using a thread. Note that the whole application lives in a thread (as opposed to half of the application living in a thread and the other half being another thread or a pipeline). Therefore, it does not need a queue element in this specific case. #include <gst/gst.h> GstElement *thread, *source, *decodebin, *audiosink; static gboolean idle_eos (gpointer data) { g_print ("Have idle-func in thread %p\n", g_thread_self ()); gst_main_quit (); /* do this function only once */ return FALSE; } /* * EOS will be called when the src element has an end of stream. * Note that this function will be called in the thread context. * We will place an idle handler to the function that really * quits the application. */ static void cb_eos (GstElement *thread, gpointer data) { g_print ("Have eos in thread %p\n", g_thread_self ()); g_idle_add ((GSourceFunc) idle_eos, NULL); } /* * On error, too, you'll want to forward signals to the main * thread, especially when using GUI applications. */ static void cb_error (GstElement *thread, GstElement *source, GError *error, gchar *debug, gpointer data) { g_print ("Error in thread %p: %s\n", g_thread_self (), error->message); g_idle_add ((GSourceFunc) idle_eos, NULL); } /* * Link new pad from decodebin to audiosink. * Contains no further error checking. */ static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) { gst_pad_link (pad, gst_element_get_pad (audiosink, "sink")); gst_bin_add (GST_BIN (thread), audiosink); gst_bin_sync_children_state (GST_BIN (thread)); } gint main (gint argc, gchar *argv[]) { /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have a filename argument */ if (argc != 2) { g_print ("usage: %s <Ogg/Vorbis filename>\n", argv[0]); return -1; } /* create a new thread to hold the elements */ thread = gst_thread_new ("thread"); g_signal_connect (thread, "eos", G_CALLBACK (cb_eos), NULL); g_signal_connect (thread, "error", G_CALLBACK (cb_error), NULL); /* create elements */ source = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (source), "location", argv[1], NULL); decodebin = gst_element_factory_make ("decodebin", "decoder"); g_signal_connect (decodebin, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); audiosink = gst_element_factory_make ("alsasink", "audiosink"); /* setup */ gst_bin_add_many (GST_BIN (thread), source, decodebin, NULL); gst_element_link (source, decodebin); gst_element_set_state (audiosink, GST_STATE_PAUSED); gst_element_set_state (thread, GST_STATE_PLAYING); /* no need to iterate. We can now use a mainloop */ gst_main (); /* unset */ gst_element_set_state (thread, GST_STATE_NULL); gst_object_unref (GST_OBJECT (thread)); return 0; } Scheduling By now, you've seen several example applications. All of them would set up a pipeline and call gst_bin_iterate () to start media processing. You might have started wondering what happens during pipeline iteration. This whole process of media processing is called scheduling. Scheduling is considered one of the most complex parts of GStreamer. Here, we will do no more than give a global overview of scheduling, most of which will be purely informative. It might help in understanding the underlying parts of GStreamer. The scheduler is responsible for managing the plugins at runtime. Its main responsibilities are: Managing data throughput between pads and elements in a pipeline. This might sometimes imply temporary data storage between elements. Calling functions in elements that do the actual data processing. Monitoring state changes and enabling/disabling elements in the chain. Selecting and distributing the global clock. The scheduler is a pluggable component; this means that alternative schedulers can be written and plugged into GStreamer. There is usually no need for interaction in the process of choosing the scheduler, though. The default scheduler in GStreamer is called opt. Some of the concepts discussed here are specific to opt. Managing elements and data throughput To understand some specifics of scheduling, it is important to know how elements work internally. Largely, there are four types of elements: _chain ()-based elements, _loop ()-based elements, _get ()-based elements and decoupled elements. Each of those have a set of features and limitations that are important for how they are scheduled. _chain ()-based elements are elements that have a _chain ()-function defined for each of their sinkpads. Those functions will receive data whenever input data is available. In those functions, the element can push data over its source pad(s) to peer elements. _chain ()-based elements cannot pull additional data from their sinkpad(s). Most elements in GStreamer are _chain ()-based. _loop ()-based elements are elements that have a _loop ()-function defined for the whole element. Inside this function, the element can pull buffers from its sink pad(s) and push data over its source pad(s) as it sees fit. Such elements usually require specific control over their input. Muxers and demuxers are usually _loop ()-based. _get ()-based elements are elements with only source pads. For each source pad, a _get ()-function is defined, which is called whenever the peer element needs additional input data. Most source elements are, in fact, _get ()-based. Such an element cannot actively push data. Decoupled elements are elements whose source pads are _get ()-based and whose sink pads are _chain ()-based. The _chain ()-function cannot push data over its source pad(s), however. One such element is the queue element, which is a thread boundary element. Since only one side of such elements are interesting for one particular scheduler, we can safely handle those elements as if they were either _get ()- or _chain ()-based. Therefore, we will further omit this type of elements in the discussion. Obviously, the type of elements that are linked together have implications for how the elements will be scheduled. If a get-based element is linked to a loop-based element and the loop-based element requests data from its sinkpad, we can just call the get-function and be done with it. However, if two loop-based elements are linked to each other, it's a lot more complicated. Similarly, a loop-based element linked to a chain-based element is a lot easier than two loop-based elements linked to each other. The default GStreamer scheduler, opt, uses a concept of chains and groups. A group is a series of elements that do not require any context switches or intermediate data stores to be executed. In practice, this implies zero or one loop-based elements, one get-based element (at the beginning) and an infinite amount of chain-based elements. If there is a loop-based element, then the scheduler will simply call this elements loop-function to iterate. If there is no loop-based element, then data will be pulled from the get-based element and will be pushed over the chain-based elements. A chain is a series of groups that depend on each other for data. For example, two linked loop-based elements would end up in different groups, but in the same chain. Whenever the first loop-based element pushes data over its source pad, the data will be temporarily stored inside the scheduler until the loop-function returns. When it's done, the loop-function of the second element will be called to process this data. If it pulls data from its sinkpad while no data is available, the scheduler will emulate a get-function and, in this function, iterate the first group until data is available. The above is roughly how scheduling works in GStreamer. This has some implications for ideal pipeline design. An pipeline would ideally contain at most one loop-based element, so that all data processing is immediate and no data is stored inside the scheduler during group switches. You would think that this decreases overhead significantly. In practice, this is not so bad, however. It's something to keep in the back of your mind, nothing more. Autoplugging In , you've learned to build a simple media player for Ogg/Vorbis files. By using alternative elements, you are able to build media players for other media types, such as Ogg/Speex, MP3 or even video formats. However, you would rather want to build an application that can automatically detect the media type of a stream and automatically generate the best possible pipeline by looking at all available elements in a system. This process is called autoplugging, and GStreamer contains high-quality autopluggers. If you're looking for an autoplugger, don't read any further and go to . This chapter will explain the concept of autoplugging and typefinding. It will explain what systems GStreamer includes to dynamically detect the type of a media stream, and how to generate a pipeline of decoder elements to playback this media. The same principles can also be used for transcoding. Because of the full dynamicity of this concept, GStreamer can be automatically extended to support new media types without needing any adaptations to its autopluggers. We will first introduce the concept of MIME types as a dynamic and extendible way of identifying media streams. After that, we will introduce the concept of typefinding to find the type of a media stream. Lastly, we will explain how autoplugging and the GStreamer registry can be used to setup a pipeline that will convert media from one mimetype to another, for example for media decoding. MIME-types as a way to identity streams We have previously introduced the concept of capabilities as a way for elements (or, rather, pads) to agree on a media type when streaming data from one element to the next (see ). We have explained that a capability is a combination of a mimetype and a set of properties. For most container formats (those are the files that you will find on your hard disk; Ogg, for example, is a container format), no properties are needed to describe the stream. Only a MIME-type is needed. A full list of MIME-types and accompanying properties can be found in the Plugin Writer's Guide. An element must associate a MIME-type to its source and sink pads when it is loaded into the system. GStreamer knows about the different elements and what type of data they expect and emit through the GStreamer registry. This allows for very dynamic and extensible element creation as we will see. In , we've learned to build a music player for Ogg/Vorbis files. Let's look at the MIME-types associated with each pad in this pipeline. shows what MIME-type belongs to each pad in this pipeline. The Hello world pipeline with MIME types Now that we have an idea how GStreamer identifies known media streams, we can look at methods GStreamer uses to setup pipelines for media handling and for media type detection. Media stream type detection Usually, when loading a media stream, the type of the stream is not known. This means that before we can choose a pipeline to decode the stream, we first need to detect the stream type. GStreamer uses the concept of typefinding for this. Typefinding is a normal part of a pipeline, it will read data for as long as the type of a stream is unknown. During this period, it will provide data to all plugins that implement a typefinder. when one of the typefinders recognizes the stream, the typefind element will emit a signal and act as a passthrough module from that point on. If no type was found, it will emit an error and further media processing will stop. Once the typefind element has found a type, the application can use this to plug together a pipeline to decode the media stream. This will be discussed in the next section. Plugins in GStreamer can, as mentioned before, implement typefinder functionality. A plugin implementing this functionality will submit a mimetype, optionally a set of file extensions commonly used for this media type, and a typefind function. Once this typefind function inside the plugin is called, the plugin will see if the data in this media stream matches a specific pattern that marks the media type identified by that mimetype. If it does, it will notify the typefind element of this fact, telling which mediatype was recognized and how certain we are that this stream is indeed that mediatype. Once this run has been completed for all plugins implementing a typefind functionality, the typefind element will tell the application what kind of media stream it thinks to have recognized. The following code should explain how to use the typefind element. It will print the detected media type, or tell that the media type was not found. The next section will introduce more useful behaviours, such as plugging together a decoding pipeline. #include <gst/gst.h> static void cb_typefound (GstElement *typefind, guint probability, GstCaps *caps, gpointer data) { gchar *type; type = gst_caps_to_string (caps); g_print ("Media type %s found, probability %d%%\n", type, probability); g_free (type); /* done */ (* (gboolean *) data) = TRUE; } static void cb_error (GstElement *pipeline, GstElement *source, GError *error, gchar *debug, gpointer data) { g_print ("Error: %s\n", error->message); /* done */ (* (gboolean *) data) = TRUE; } gint main (gint argc, gchar *argv[]) { GstElement *pipeline, *filesrc, *typefind; gboolean done = FALSE; /* init GStreamer */ gst_init (&argc, &argv); /* check args */ if (argc != 2) { g_print ("Usage: %s <filename>\n", argv[0]); return -1; } /* create a new pipeline to hold the elements */ pipeline = gst_pipeline_new ("pipe"); g_signal_connect (pipeline, "error", G_CALLBACK (cb_error), &done); /* create file source and typefind element */ filesrc = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); typefind = gst_element_factory_make ("typefind", "typefinder"); g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), &done); /* setup */ gst_bin_add_many (GST_BIN (pipeline), filesrc, typefind, NULL); gst_element_link (filesrc, typefind); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); /* now iterate until the type is found */ do { if (!gst_bin_iterate (GST_BIN (pipeline))) break; } while (!done); /* unset */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Once a media type has been detected, you can plug an element (e.g. a demuxer or decoder) to the source pad of the typefind element, and decoding of the media stream will start right after. Plugging together dynamic pipelines In this chapter we will see how you can create a dynamic pipeline. A dynamic pipeline is a pipeline that is updated or created while data is flowing through it. We will create a partial pipeline first and add more elements while the pipeline is playing. The basis of this player will be the application that we wrote in the previous section () to identify unknown media streams. Once the type of the media has been found, we will find elements in the registry that can decode this streamtype. For this, we will get all element factories (which we've seen before in ) and find the ones with the given MIME-type and capabilities on their sinkpad. Note that we will only use parsers, demuxers and decoders. We will not use factories for any other element types, or we might get into a loop of encoders and decoders. For this, we will want to build a list of allowed factories right after initializing GStreamer. static GList *factories; /* * This function is called by the registry loader. Its return value * (TRUE or FALSE) decides whether the given feature will be included * in the list that we're generating further down. */ static gboolean cb_feature_filter (GstPluginFeature *feature, gpointer data) { const gchar *klass; guint rank; /* we only care about element factories */ if (!GST_IS_ELEMENT_FACTORY (feature)) return FALSE; /* only parsers, demuxers and decoders */ klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); if (g_strrstr (klass, "Demux") == NULL && g_strrstr (klass, "Decoder") == NULL && g_strrstr (klass, "Parse") == NULL) return FALSE; /* only select elements with autoplugging rank */ rank = gst_plugin_feature_get_rank (feature); if (rank < GST_RANK_MARGINAL) return FALSE; return TRUE; } /* * This function is called to sort features by rank. */ static gint cb_compare_ranks (GstPluginFeature *f1, GstPluginFeature *f2) { return gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); } static void init_factories (void) { /* first filter out the interesting element factories */ factories = gst_registry_pool_feature_filter ( (GstPluginFeatureFilter) cb_feature_filter, FALSE, NULL); /* sort them according to their ranks */ factories = g_list_sort (factories, (GCompareFunc) cb_compare_ranks); } From this list of element factories, we will select the one that most likely will help us decoding a media stream to a given output type. For each newly created element, we will again try to autoplug new elements to its source pad(s). Also, if the element has dynamic pads (which we've seen before in ), we will listen for newly created source pads and handle those, too. The following code replaces the cb_type_found from the previous section with a function to initiate autoplugging, which will continue with the above approach. static void try_to_plug (GstPad *pad, const GstCaps *caps); static GstElement *audiosink; static void cb_newpad (GstElement *element, GstPad *pad, gpointer data) { GstCaps *caps; caps = gst_pad_get_caps (pad); try_to_plug (pad, caps); gst_caps_free (caps); } static void close_link (GstPad *srcpad, GstElement *sinkelement, const gchar *padname, const GList *templlist) { gboolean has_dynamic_pads = FALSE; g_print ("Plugging pad %s:%s to newly created %s:%s\n", gst_object_get_name (GST_OBJECT (gst_pad_get_parent (srcpad))), gst_pad_get_name (srcpad), gst_object_get_name (GST_OBJECT (sinkelement)), padname); /* add the element to the pipeline and set correct state */ gst_element_set_state (sinkelement, GST_STATE_PAUSED); gst_bin_add (GST_BIN (pipeline), sinkelement); gst_pad_link (srcpad, gst_element_get_pad (sinkelement, padname)); gst_bin_sync_children_state (GST_BIN (pipeline)); /* if we have static source pads, link those. If we have dynamic * source pads, listen for new-pad signals on the element */ for ( ; templlist != NULL; templlist = templlist->next) { GstPadTemplate *templ = GST_PAD_TEMPLATE (templlist->data); /* only sourcepads, no request pads */ if (templ->direction != GST_PAD_SRC || templ->presence == GST_PAD_REQUEST) { continue; } switch (templ->presence) { case GST_PAD_ALWAYS: { GstPad *pad = gst_element_get_pad (sinkelement, templ->name_template); GstCaps *caps = gst_pad_get_caps (pad); /* link */ try_to_plug (pad, caps); gst_caps_free (caps); break; } case GST_PAD_SOMETIMES: has_dynamic_pads = TRUE; break; default: break; } } /* listen for newly created pads if this element supports that */ if (has_dynamic_pads) { g_signal_connect (sinkelement, "new-pad", G_CALLBACK (cb_newpad), NULL); } } static void try_to_plug (GstPad *pad, const GstCaps *caps) { GstObject *parent = GST_OBJECT (gst_pad_get_parent (pad)); const gchar *mime; const GList *item; GstCaps *res, *audiocaps; /* don't plug if we're already plugged */ if (GST_PAD_IS_LINKED (gst_element_get_pad (audiosink, "sink"))) { g_print ("Omitting link for pad %s:%s because we're already linked\n", gst_object_get_name (parent), gst_pad_get_name (pad)); return; } /* as said above, we only try to plug audio... Omit video */ mime = gst_structure_get_name (gst_caps_get_structure (caps, 0)); if (g_strrstr (mime, "video")) { g_print ("Omitting link for pad %s:%s because mimetype %s is non-audio\n", gst_object_get_name (parent), gst_pad_get_name (pad), mime); return; } /* can it link to the audiopad? */ audiocaps = gst_pad_get_caps (gst_element_get_pad (audiosink, "sink")); res = gst_caps_intersect (caps, audiocaps); if (res && !gst_caps_is_empty (res)) { g_print ("Found pad to link to audiosink - plugging is now done\n"); close_link (pad, audiosink, "sink", NULL); gst_caps_free (audiocaps); gst_caps_free (res); return; } gst_caps_free (audiocaps); gst_caps_free (res); /* try to plug from our list */ for (item = factories; item != NULL; item = item->next) { GstElementFactory *factory = GST_ELEMENT_FACTORY (item->data); const GList *pads; for (pads = gst_element_factory_get_pad_templates (factory); pads != NULL; pads = pads->next) { GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data); /* find the sink template - need an always pad*/ if (templ->direction != GST_PAD_SINK || templ->presence != GST_PAD_ALWAYS) { continue; } /* can it link? */ res = gst_caps_intersect (caps, templ->caps); if (res && !gst_caps_is_empty (res)) { GstElement *element; gchar *name_template = g_strdup (templ->name_template); /* close link and return */ gst_caps_free (res); element = gst_element_factory_create (factory, NULL); close_link (pad, element, name_template, gst_element_factory_get_pad_templates (factory)); g_free (name_template); return; } gst_caps_free (res); /* we only check one sink template per factory, so move on to the * next factory now */ break; } } /* if we get here, no item was found */ g_print ("No compatible pad found to decode %s on %s:%s\n", mime, gst_object_get_name (parent), gst_pad_get_name (pad)); } static void cb_typefound (GstElement *typefind, guint probability, GstCaps *caps, gpointer data) { gchar *s; s = gst_caps_to_string (caps); g_print ("Detected media type %s\n", s); g_free (s); /* actually plug now */ try_to_plug (gst_element_get_pad (typefind, "src"), caps); } By doing all this, we will be able to make a simple autoplugger that can automatically setup a pipeline for any media type. In the example below, we will do this for audio only. However, we can also do this for video to create a player that plays both audio and video. The example above is a good first try for an autoplugger. Next steps would be to listen for pad-removed signals, so we can dynamically change the plugged pipeline if the stream changes (this happens for DVB or Ogg radio). Also, you might want special-case code for input with known content (such as a DVD or an audio-CD), and much, much more. Moreover, you'll want many checks to prevent infinite loops during autoplugging, maybe you'll want to implement shortest-path-finding to make sure the most optimal pipeline is chosen, and so on. Basically, the features that you implement in an autoplugger depend on what you want to use it for. For full-blown implementations, see the playbin, decodebin and spider elements. Pipeline manipulation This chapter will discuss how you can manipulate your pipeline in several ways from your application on. Parts of this chapter are downright hackish, so be assured that you'll need some programming knowledge before you start reading this. Topics that will be discussed here include how you can insert data into a pipeline from your application, how to read data from a pipeline, how to manipulate the pipeline's speed, length, starting point and how to listen to a pipeline's data processing. Data probes Probes are best envisioned as pad listeners. They are attached to a pad in a pipeline, and you can add callback functions to this probe. Those callback functions will be called whenever data is being sent over this pad. The callback can then decide whether the data should be discarded or it can replace the piece of data with another piece of data. In this callback, it can also trigger actions in the application itself. For pipeline manipulation, probes are rather limited, but for pipeline tracking, they can be very useful. Manually adding or removing data from/to a pipeline Many people have expressed the wish to use their own sources to inject data into a pipeline. Some people have also expressed the wish to grab the output in a pipeline and take care of the actual output inside their application. While either of these methods are stongly discouraged, GStreamer offers hacks to do this. However, there is no support for those methods. If it doesn't work, you're on your own. Also, synchronization, thread-safety and other things that you've been able to take for granted so far are no longer guanranteed if you use any of those methods. It's always better to simply write a plugin and have the pipeline schedule and manage it. See the Plugin Writer's Guide for more information on this topic. Also see the next section, which will explain how to embed plugins statically in your application. After all those disclaimers, let's start. There's three possible elements that you can use for the above-mentioned purposes. Those are called fakesrc (an imaginary source), fakesink (an imaginary sink) and identity (an imaginary filter). The same method applies to each of those elements. Here, we will discuss how to use those elements to insert (using fakesrc) or grab (using fakesink or identity) data from a pipeline, and how to set negotiation. Inserting or grabbing data The three before-mentioned elements (fakesrc, fakesink and identity) each have a handoff signal that will be called in the _get ()- (fakesrc) or _chain ()-function (identity, fakesink). In the signal handler, you can set (fakesrc) or get (identity, fakesink) data to/from the provided buffer. Note that in the case of fakesrc, you have to set the size of the provided buffer using the sizemax property. For both fakesrc and fakesink, you also have to set the signal-handoffs property for this method to work. Note that your handoff function should not block, since this will block pipeline iteration. Also, do not try to use all sort of weird hacks in such functions to accomplish something that looks like synchronization or so; it's not the right way and will lead to issues elsewhere. If you're doing any of this, you're basically misunderstanding the GStreamer design. Forcing a format Sometimes, when using fakesrc as a source in your pipeline, you'll want to set a specific format, for example a video size and format or an audio bitsize and number of channels. You can do this by forcing a specific GstCaps on the pipeline, which is possible by using filtered caps. You can set a filtered caps on a link by using gst_pad_link_filtered (), where the third argument is the format to force on the link. Example application This example application will generate black/white (it switches every second) video to an X-window output by using fakesrc as a source and using filtered caps to force a format. Since the depth of the image depends on your X-server settings, we use a colorspace conversion element to make sure that the output to your X server will have the correct bitdepth. You can also set timestamps on the provided buffers to override the fixed framerate. #include <string.h> /* for memset () */ #include <gst/gst.h> static void cb_handoff (GstElement *fakesrc, GstBuffer *buffer, GstPad *pad, gpointer user_data) { static gboolean white = FALSE; /* this makes the image black/white */ memset (GST_BUFFER_DATA (buffer), white ? 0xff : 0x0, GST_BUFFER_SIZE (buffer)); white = !white; } gint main (gint argc, gchar *argv[]) { GstElement *pipeline, *fakesrc, *conv, *videosink; GstCaps *filter; /* init GStreamer */ gst_init (&argc, &argv); /* setup pipeline */ pipeline = gst_pipeline_new ("pipeline"); fakesrc = gst_element_factory_make ("fakesrc", "source"); conv = gst_element_factory_make ("ffmpegcolorspace", "conv"); videosink = gst_element_factory_make ("ximagesink", "videosink"); /* setup */ filter = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, (gdouble) 1.0, "bpp", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL); gst_element_link_filtered (fakesrc, conv, filter); gst_element_link (conv, videosink); gst_bin_add_many (GST_BIN (pipeline), fakesrc, conv, videosink, NULL); /* setup fake source */ g_object_set (G_OBJECT (fakesrc), "signal-handoffs", TRUE, "sizemax", 384 * 288 * 2, "sizetype", 2, NULL); g_signal_connect (fakesrc, "handoff", G_CALLBACK (cb_handoff), NULL); /* play */ gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))) ; /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Embedding static elements in your application The Plugin Writer's Guide describes in great detail how to write elements for the GStreamer framework. In this section, we will solely discuss how to embed such elements statically in your application. This can be useful for application-specific elements that have no use elsewhere in GStreamer. Dynamically loaded plugins contain a structure that's defined using GST_PLUGIN_DEFINE (). This structure is loaded when the plugin is loaded by the GStreamer core. The structure contains an initialization function (usually called plugin_init) that will be called right after that. It's purpose is to register the elements provided by the plugin with the GStreamer framework. If you want to embed elements directly in your application, the only thing you need to do is to manually run this structure using _gst_plugin_register_static (). The initialization will then be called, and the elements will from then on be available like any other element, without them having to be dynamically loadable libraries. In the example below, you would be able to call gst_element_factory_make ("my-element-name", "some-name") to create an instance of the element. /* * Here, you would write the actual plugin code. */ [..] static gboolean register_elements (GstPlugin *plugin) { return gst_element_register (plugin, "my-element-name", GST_RANK_NONE, MY_PLUGIN_TYPE); } static GstPluginDesc plugin_desc = { GST_VERSION_MAJOR, GST_VERSION_MINOR, "my-private-plugins", "Private elements of my application", register_elements, NULL, "0.0.1", "LGPL", "my-application", "http://www.my-application.net/", GST_PADDING_INIT }; /* * Call this function right after calling gst_init (). */ void my_elements_init (void) { _gst_plugin_register_static (&plugin_desc); } Higher-level interfaces for GStreamer applications In the previous two parts, you have learned many of the internals and their corresponding low-level interfaces into GStreamer application programming. Many people will, however, not need so much control (and as much code), but will prefer to use a standard playback interface that does most of the difficult internals for them. In this chapter, we will introduce you into the concept of autopluggers, playback managing elements, XML-based pipelines and other such things. Those higher-level interfaces are intended to simplify GStreamer-based application programming. They do, however, also reduce the flexibility. It is up to the application developer to choose which interface he will want to use. Components GStreamer includes several higher-level components to simplify your applications life. All of the components discussed here (for now) are targetted at media playback. The idea of each of these components is to integrate as closely as possible with a GStreamer pipeline, but to hide the complexity of media type detection and several other rather complex topics that have been discussed in . We currently recommend people to use either playbin (see ) or decodebin (see ), depending on their needs. The other components discussed here are either outdated or deprecated. The documentation is provided for legacy purposes. Use of those other components is not recommended. Playbin Playbin is an element that can be created using the standard GStreamer API (e.g. gst_element_factory_make ()). The factory is conveniently called playbin. By being a GstElement, playbin automatically supports all of the features of this class, including error handling, tag support, state handling, getting stream positions, seeking, and so on. Setting up a playbin pipeline is as simple as creating an instance of the playbin element, setting a file location (this has to be a valid URI, so <protocol>://<location>, e.g. file:///tmp/my.ogg or http://www.example.org/stream.ogg) using the uri property on playbin, and then setting the element to the GST_STATE_PLAYING state. Internally, playbin uses threads, so there's no need to iterate the element or anything. However, one thing to keep in mind is that signals fired by playbin might come from another than the main thread, so be sure to keep this in mind in your signal handles. Most application programmers will want to use a function such as g_idle_add () to make sure that the signal is handled in the main thread. #include <gst/gst.h> static void cb_eos (GstElement *play, gpointer data) { gst_main_quit (); } static void cb_error (GstElement *play, GstElement *src, GError *err, gchar *debug, gpointer data) { g_print ("Error: %s\n", err->message); } gint main (gint argc, gchar *argv[]) { GstElement *play; /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have a URI */ if (argc != 2) { g_print ("Usage: %s <URI>\n", argv[0]); return -1; } /* set up */ play = gst_element_factory_make ("playbin", "play"); g_object_set (G_OBJECT (play), "uri", argv[1], NULL); g_signal_connect (play, "eos", G_CALLBACK (cb_eos), NULL); g_signal_connect (play, "error", G_CALLBACK (cb_error), NULL); if (gst_element_set_state (play, GST_STATE_PLAYING) != GST_STATE_SUCCESS) { g_print ("Failed to play\n"); return -1; } /* now run */ gst_main (); /* also clean up */ gst_element_set_state (play, GST_STATE_NULL); gst_object_unref (GST_OBJECT (play)); return 0; } Playbin has several features that have been discussed previously: Settable video and audio output (using the video-sink and audio-sink properties). Mostly controllable and trackable as a GstElement, including error handling, eos handling, tag handling, state handling, media position handling and seeking. Buffers network-sources. Supports visualizations for audio-only media. Supports subtitles, both in the media as well as from separate files. Supports stream selection and disabling. If your media has multiple audio or subtitle tracks, you can dynamically choose which one to play back, or decide to turn it off alltogther (which is especially useful to turn off subtitles). Decodebin Decodebin is the actual autoplugger backend of playbin, which was discussed in the previous section. Decodebin will, in short, accept input from a source that is linked to its sinkpad and will try to detect the media type contained in the stream, and set up decoder routines for each of those. It will automatically select decoders. For each decoded stream, it will emit the new-decoded-pad signal, to let the client know about the newly found decoded stream. For unknown streams (which might be the whole stream), it will emit the unknown-type signal. The application is then responsible for reporting the error to the user. The example code below will play back an audio stream of an input file. For readability, it does not include any error handling of any sort. #include <gst/gst.h> GstElement *pipeline, *audio; GstPad *audiopad; static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) { GstCaps *caps; GstStructure *str; /* only link audio; only link once */ if (GST_PAD_IS_LINKED (audiopad)) return; caps = gst_pad_get_caps (pad); str = gst_caps_get_structure (caps, 0); if (!g_strrstr (gst_structure_get_name (str), "audio")) return; /* link'n'play */ gst_pad_link (pad, audiopad); gst_bin_add (GST_BIN (pipeline), audio); gst_bin_sync_children_state (GST_BIN (pipeline)); } gint main (gint argc, gchar *argv[]) { GstElement *src, *dec, *conv, *scale, *sink; /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have input */ if (argc != 2) { g_print ("Usage: %s <filename>\n", argv[0]); return -1; } /* setup */ pipeline = gst_pipeline_new ("pipeline"); src = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (src), "location", argv[1], NULL); dec = gst_element_factory_make ("decodebin", "decoder"); g_signal_connect (dec, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); audio = gst_bin_new ("audiobin"); conv = gst_element_factory_make ("audioconvert", "aconv"); audiopad = gst_element_get_pad (conv, "sink"); scale = gst_element_factory_make ("audioscale", "scale"); sink = gst_element_factory_make ("alsasink", "sink"); gst_bin_add_many (GST_BIN (audio), conv, scale, sink, NULL); gst_element_link_many (conv, scale, sink, NULL); gst_bin_add_many (GST_BIN (pipeline), src, dec, NULL); gst_element_link (src, dec); /* run */ gst_element_set_state (audio, GST_STATE_PAUSED); gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))) ; /* cleanup */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Decodebin, similar to playbin, supports the following features: Can decode an unlimited number of contained streams to decoded output pads. Is handled as a GstElement in all ways, including tag or error forwarding and state handling. Although decodebin is a good autoplugger, there's a whole lot of things that it does not do and is not intended to do: Taking care of input streams with a known media type (e.g. a DVD, an audio-CD or such). Selection of streams (e.g. which audio track to play in case of multi-language media streams). Overlaying subtitles over a decoded video stream. Decodebin can be easily tested on the commandline, e.g. by using the command gst-launch-0.8 filesrc location=file.ogg ! decodebin ! audioconvert ! audioscale ! alsasink. Spider Spider is an autoplugger that looks and feels very much like decodebin. On the commandline, you can literally switch between spider and decodebin and it'll mostly just work. Try, for example, gst-launch-0.8 filesrc location=file.ogg ! spider ! audioconvert ! audioscale ! alsasink. Although the two may seem very much alike from the outside, they are very different from the inside. Those internal differences are the main reason why spider is currently considered deprecated (along with the fact that it was hard to maintain). As opposed to decodebin, spider does not decode pads and emit signals for each detected stream. Instead, you have to add output sinks to spider by create source request pads and connecting those to sink elements. This means that streams decoded by spider cannot be dynamic. Also, spider uses many loop-based elements internally, which is rather heavy scheduler-wise. Code for using spider would look almost identical to the code of decodebin, and is therefore omitted. Also, featureset and limitations are very much alike, except for the above-mentioned extra limitations for spider with respect to decodebin. GstPlay GstPlay is a GtkWidget with a simple API to play, pause and stop a media file. GstEditor GstEditor is a set of widgets to display a graphical representation of a pipeline. XML in GStreamer GStreamer uses XML to store and load its pipeline definitions. XML is also used internally to manage the plugin registry. The plugin registry is a file that contains the definition of all the plugins GStreamer knows about to have quick access to the specifics of the plugins. We will show you how you can save a pipeline to XML and how you can reload that XML file again for later use. Turning GstElements into XML We create a simple pipeline and write it to stdout with gst_xml_write_file (). The following code constructs an MP3 player pipeline with two threads and then writes out the XML both to stdout and to a file. Use this program with one argument: the MP3 file on disk. #include <stdlib.h> #include <gst/gst.h> gboolean playing; int main (int argc, char *argv[]) { GstElement *filesrc, *osssink, *queue, *queue2, *decode; GstElement *bin; GstElement *thread, *thread2; gst_init (&argc,&argv); if (argc != 2) { g_print ("usage: %s <mp3 filename>\n", argv[0]); exit (-1); } /* create a new thread to hold the elements */ thread = gst_element_factory_make ("thread", "thread"); g_assert (thread != NULL); thread2 = gst_element_factory_make ("thread", "thread2"); g_assert (thread2 != NULL); /* create a new bin to hold the elements */ bin = gst_bin_new ("bin"); g_assert (bin != NULL); /* create a disk reader */ filesrc = gst_element_factory_make ("filesrc", "disk_source"); g_assert (filesrc != NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); queue = gst_element_factory_make ("queue", "queue"); queue2 = gst_element_factory_make ("queue", "queue2"); /* and an audio sink */ osssink = gst_element_factory_make ("osssink", "play_audio"); g_assert (osssink != NULL); decode = gst_element_factory_make ("mad", "decode"); g_assert (decode != NULL); /* add objects to the main bin */ gst_bin_add_many (GST_BIN (bin), filesrc, queue, NULL); gst_bin_add_many (GST_BIN (thread), decode, queue2, NULL); gst_bin_add (GST_BIN (thread2), osssink); gst_element_link_many (filesrc, queue, decode, queue2, osssink, NULL); gst_bin_add_many (GST_BIN (bin), thread, thread2, NULL); /* write the bin to stdout */ gst_xml_write_file (GST_ELEMENT (bin), stdout); /* write the bin to a file */ gst_xml_write_file (GST_ELEMENT (bin), fopen ("xmlTest.gst", "w")); exit (0); } The most important line is: gst_xml_write_file (GST_ELEMENT (bin), stdout); gst_xml_write_file () will turn the given element into an xmlDocPtr that is then formatted and saved to a file. To save to disk, pass the result of a fopen(2) as the second argument. The complete element hierarchy will be saved along with the inter element pad links and the element parameters. Future GStreamer versions will also allow you to store the signals in the XML file. Loading a GstElement from an XML file Before an XML file can be loaded, you must create a GstXML object. A saved XML file can then be loaded with the gst_xml_parse_file (xml, filename, rootelement) method. The root element can optionally left NULL. The following code example loads the previously created XML file and runs it. #include <stdlib.h> #include <gst/gst.h> int main(int argc, char *argv[]) { GstXML *xml; GstElement *bin; gboolean ret; gst_init (&argc, &argv); xml = gst_xml_new (); ret = gst_xml_parse_file(xml, "xmlTest.gst", NULL); g_assert (ret == TRUE); bin = gst_xml_get_element (xml, "bin"); g_assert (bin != NULL); gst_element_set_state (bin, GST_STATE_PLAYING); while (gst_bin_iterate(GST_BIN(bin))); gst_element_set_state (bin, GST_STATE_NULL); exit (0); } gst_xml_get_element (xml, "name") can be used to get a specific element from the XML file. gst_xml_get_topelements (xml) can be used to get a list of all toplevel elements in the XML file. In addition to loading a file, you can also load a from a xmlDocPtr and an in memory buffer using gst_xml_parse_doc and gst_xml_parse_memory respectively. Both of these methods return a gboolean indicating success or failure of the requested action. Adding custom XML tags into the core XML data It is possible to add custom XML tags to the core XML created with gst_xml_write. This feature can be used by an application to add more information to the save plugins. The editor will for example insert the position of the elements on the screen using the custom XML tags. It is strongly suggested to save and load the custom XML tags using a namespace. This will solve the problem of having your XML tags interfere with the core XML tags. To insert a hook into the element saving procedure you can link a signal to the GstElement using the following piece of code: xmlNsPtr ns; ... ns = xmlNewNs (NULL, "http://gstreamer.net/gst-test/1.0/", "test"); ... thread = gst_element_factory_make ("thread", "thread"); g_signal_connect (G_OBJECT (thread), "object_saved", G_CALLBACK (object_saved), g_strdup ("decoder thread")); ... When the thread is saved, the object_save method will be called. Our example will insert a comment tag: static void object_saved (GstObject *object, xmlNodePtr parent, gpointer data) { xmlNodePtr child; child = xmlNewChild (parent, ns, "comment", NULL); xmlNewChild (child, ns, "text", (gchar *)data); } Adding the custom tag code to the above example you will get an XML file with the custom tags in it. Here's an excerpt: ... <gst:element> <gst:name>thread</gst:name> <gst:type>thread</gst:type> <gst:version>0.1.0</gst:version> ... </gst:children> <test:comment> <test:text>decoder thread</test:text> </test:comment> </gst:element> ... To retrieve the custom XML again, you need to attach a signal to the GstXML object used to load the XML data. You can then parse your custom XML from the XML tree whenever an object is loaded. We can extend our previous example with the following piece of code. xml = gst_xml_new (); g_signal_connect (G_OBJECT (xml), "object_loaded", G_CALLBACK (xml_loaded), xml); ret = gst_xml_parse_file (xml, "xmlTest.gst", NULL); g_assert (ret == TRUE); Whenever a new object has been loaded, the xml_loaded function will be called. This function looks like: static void xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data) { xmlNodePtr children = self->xmlChildrenNode; while (children) { if (!strcmp (children->name, "comment")) { xmlNodePtr nodes = children->xmlChildrenNode; while (nodes) { if (!strcmp (nodes->name, "text")) { gchar *name = g_strdup (xmlNodeGetContent (nodes)); g_print ("object %s loaded with comment '%s'\n", gst_object_get_name (object), name); } nodes = nodes->next; } } children = children->next; } } As you can see, you'll get a handle to the GstXML object, the newly loaded GstObject and the xmlNodePtr that was used to create this object. In the above example we look for our special tag inside the XML tree that was used to load the object and we print our comment to the console. Appendices By now, you've learned all about the internals of GStreamer and application programming using the GStreamer framework. This part will go into some random bits that are useful to know if you're going to use GStreamer for serious application programming. It will touch upon things related to integration with popular desktop environments that we run on (GNOME, KDE, OS X, Windows), it will shortly explain how applications included with GStreamer can help making your life easier, and some information on debugging. Things to check when writing an application This chapter contains a fairly random selection of things that can be useful to keep in mind when writing GStreamer-based applications. It's up to you how much you're going to use the information provided here. We will shortly discuss how to debug pipeline problems using GStreamer applications. Also, we will touch upon how to acquire knowledge about plugins and elements and how to test simple pipelines before building applications around them. Good programming habits Always connect to the error signal of your topmost pipeline to be notified of errors in your pipeline. Always check return values of GStreamer functions. Especially, check return values of gst_element_link () and gst_element_set_state (). Always use your pipeline object to keep track of the current state of your pipeline. Don't keep private variables in your application. Also, don't update your user interface if a user presses the play button. Instead, connect to the state-changed signal of your topmost pipeline and update the user interface whenever this signal is triggered. Debugging Applications can make use of the extensive GStreamer debugging system to debug pipeline problems. Elements will write output to this system to log what they're doing. It's not used for error reporting, but it is very useful for tracking what an element is doing exactly, which can come in handy when debugging application issues (such as failing seeks, out-of-sync media, etc.). Most GStreamer-based applications accept the commandline option --gst-debug=LIST and related family members. The list consists of a comma-separated list of category/level pairs, which can set the debugging level for a specific debugging category. For example, --gst-debug=oggdemux:5 would turn on debugging for the Ogg demuxer element. You can use wildcards as well. A debugging level of 0 will turn off all debugging, and a level of 5 will turn on all debugging. Intermediate values only turn on some debugging (based on message severity; 2, for example, will only display errors and warnings). Here's a list of all available options: --gst-debug-help will print available debug categories and exit. --gst-debug-level=LEVEL will set the default debug level (which can range from 0 (no output) to 5 (everything)). --gst-debug=LIST takes a comma-separated list of category_name:level pairs to set specific levels for the individual categories. Example: GST_AUTOPLUG:5,avidemux:3. --gst-debug-no-color will disable color debugging. --gst-debug-disable disables debugging alltogether. --gst-plugin-spew enables printout of errors while loading GStreamer plugins. Conversion plugins GStreamer contains a bunch of conversion plugins that most applications will find useful. Specifically, those are videoscalers (videoscale), colorspace convertors (ffmpegcolorspace), audio format convertors and channel resamplers (audioconvert) and audio samplerate convertors (audioscale). Those convertors don't do anything when not required, they will act in passthrough mode. They will activate when the hardware doesn't support a specific request, though. All applications are recommended to use those elements. Utility applications provided with GStreamer GStreamer comes with a default set of command-line utilities that can help in application development. We will discuss only gst-launch and gst-inspect here. gst-launch gst-launch is a simple script-like commandline application that can be used to test pipelines. For example, the command gst-launch sinesrc ! alsasink will run a pipeline which generates a sine-wave audio stream and plays it to your ALSA audio card. gst-launch also allows the use of threads (using curly brackets, so { and }) and bins (using brackets, so ( and )). You can use dots to imply padnames on elements, or even omit the padname to automatically select a pad. Using all this, the pipeline gst-launch filesrc location=file.ogg ! oggdemux name=d { d. ! theoradec ! ffmpegcolorspace ! xvimagesink } { d. ! vorbisdec ! alsasink } will play an Ogg file containing a Theora video-stream and a Vorbis audio-stream. You can also use autopluggers such as decodebin on the commandline. See the manual page of gst-launch for more information. gst-inspect gst-inspect can be used to inspect all properties, signals, dynamic parameters and the object hierarchy of an element. This can be very useful to see which GObject properties or which signals (and using what arguments) an element supports. Run gst-inspect fakesrc to get an idea of what it does. See the manual page of gst-inspect for more information. Integration GStreamer tries to integrate closely with operating systems (such as Linux and UNIX-like operating systems, OS X or Windows) and desktop environments (such as GNOME or KDE). In this chapter, we'll mention some specific techniques to integrate your application with your operating system or desktop environment of choice. Linux and UNIX-like operating systems GStreamer provides a basic set of elements that are useful when integrating with Linux or a UNIX-like operating system. For audio input and output, GStreamer provides input and output elements for several audio subsystems. Amongst others, GStreamer includes elements for ALSA (alsasrc, alsamixer, alsasink), OSS (osssrc, ossmixer, osssink) and Sun audio (sunaudiosrc, sunaudiomixer, sunaudiosink). For video input, GStreamer contains source elements for Video4linux (v4lsrc, v4lmjpegsrc, v4lelement and v4lmjpegisnk) and Video4linux2 (v4l2src, v4l2element). For video output, GStreamer provides elements for output to X-windows (ximagesink), Xv-windows (xvimagesink; for hardware-accelerated video), direct-framebuffer (dfbimagesink) and openGL image contexts (glsink). GNOME desktop GStreamer has been the media backend of the GNOME desktop since GNOME-2.2 onwards. Nowadays, a whole bunch of GNOME applications make use of GStreamer for media-processing, including (but not limited to) Rhythmbox, Totem and Sound Juicer. Most of these GNOME applications make use of some specific techniques to integrate as closely as possible with the GNOME desktop: GNOME applications call gnome_program_init () to parse command-line options and initialize the necessary gnome modules. GStreamer applications would normally call gst_init () to do the same for GStreamer. This would mean that only one of the two can parse command-line options. To work around this issue, GStreamer can provide a poptOption array which can be passed to gnome_program_init (). #include <gnome.h> #include <gst/gst.h> gint main (gint argc, gchar *argv[]) { struct poptOption options[] = { {NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL}, POPT_TABLEEND }; /* init GStreamer and GNOME using the GStreamer popt tables */ options[0].arg = (void *) gst_init_get_popt_table (); gnome_program_init ("my-application", "0.0.1", LIBGNOMEUI_MODULE, argc, argv, GNOME_PARAM_POPT_TABLE, options, NULL); [..] } GNOME stores the default video and audio sources and sinks in GConf. GStreamer provides a small utility library that can be used to get the elements from the registry using functions such as gst_gconf_get_default_video_sink (). See the header file (gst/gconf/gconf.h) for details. All GNOME applications are recommended to use those variables. GStreamer provides data input/output elements for use with the GNOME-VFS system. These elements are called gnomevfssrc and gnomevfssink. KDE desktop GStreamer has been proposed for inclusion in KDE-4.0. Currently, GStreamer is included as an optional component, and it's used by several KDE applications, including AmaroK and JuK. A backend for KMPlayer is currently under development. Although not yet as complete as the GNOME integration bits, there are already some KDE integration specifics available. This list will probably grow as GStreamer starts to be used in KDE-4.0: AmaroK contains a kiosrc element, which is a source element that integrates with the KDE VFS subsystem KIO. OS X GStreamer provides native video and audio output elements for OS X. It builds using the standard development tools for OS X. Windows GStreamer builds using Microsoft Visual C .NET 2003 and using Cygwin. Licensing advisoryHow to license the applications you build with GStreamer The licensing of GStreamer is no different from a lot of other libraries out there like GTK+ or glibc: we use the LGPL. What complicates things with regards to GStreamer is its plugin-based design and the heavily patented and proprietary nature of many multimedia codecs. While patents on software are currently only allowed in a small minority of world countries (the US and Australia being the most important of those), the problem is that due to the central place the US hold in the world economy and the computing industry, software patents are hard to ignore wherever you are. Due to this situation, many companies, including major GNU/Linux distributions, get trapped in a situation where they either get bad reviews due to lacking out-of-the-box media playback capabilities (and attempts to educate the reviewers have met with little success so far), or go against their own - and the free software movement's - wish to avoid proprietary software. Due to competitive pressure, most choose to add some support. Doing that through pure free software solutions would have them risk heavy litigation and punishment from patent owners. So when the decision is made to include support for patented codecs, it leaves them the choice of either using special proprietary applications, or try to integrate the support for these codecs through proprietary plugins into the multimedia infrastructure provided by GStreamer. Faced with one of these two evils the GStreamer community of course prefer the second option. The problem which arises is that most free software and open source applications developed use the GPL as their license. While this is generally a good thing, it creates a dilemma for people who want to put together a distribution. The dilemma they face is that if they include proprietary plugins in GStreamer to support patented formats in a way that is legal for them, they do risk running afoul of the GPL license of the applications. We have gotten some conflicting reports from lawyers on whether this is actually a problem, but the official stance of the FSF is that it is a problem. We view the FSF as an authority on this matter, so we are inclined to follow their interpretation of the GPL license. So what does this mean for you as an application developer? Well, it means you have to make an active decision on whether you want your application to be used together with proprietary plugins or not. What you decide here will also influence the chances of commercial distributions and Unix vendors shipping your application. The GStreamer community suggest you license your software using a license that will allow proprietary plugins to be bundled with GStreamer and your applications, in order to make sure that as many vendors as possible go with GStreamer instead of less free solutions. This in turn we hope and think will let GStreamer be a vehicle for wider use of free formats like the Xiph.org formats. If you do decide that you want to allow for non-free plugins to be used with your application you have a variety of choices. One of the simplest is using licenses like LGPL, MPL or BSD for your application instead of the GPL. Or you can add a exceptions clause to your GPL license stating that you except GStreamer plugins from the obligations of the GPL. A good example of such a GPL exception clause would be, using the Muine music player project as an example: The Muine project hereby grants permission for non-GPL-compatible GStreamer plugins to be used and distributed together with GStreamer and Muine. This permission goes above and beyond the permissions granted by the GPL license Muine is covered by. Our suggestion among these choices is to use the LGPL license, as it is what resembles the GPL most and it makes it a good licensing fit with the major GNU/Linux desktop projects like GNOME and KDE. It also allows you to share code more openly with projects that have compatible licenses. Obviously, pure GPL code without the above-mentioned clause is not usable in your application as such. By choosing the LGPL, there is no need for an exception clause and thus code can be shared more freely. I have above outlined the practical reasons for why the GStreamer community suggest you allow non-free plugins to be used with your applications. We feel that in the multimedia arena, the free software community is still not strong enough to set the agenda and that blocking non-free plugins to be used in our infrastructure hurts us more than it hurts the patent owners and their ilk. This view is not shared by everyone. The Free Software Foundation urges you to use an unmodified GPL for your applications, so as to push back against the temptation to use non-free plug-ins. They say that since not everyone else has the strength to reject them because they are unethical, they ask your help to give them a legal reason to do so. This advisory is part of a bigger advisory with a FAQ which you can find on the GStreamer website Windows supportBuilding GStreamer under Win32There are different makefiles that can be used to build GStreamer with the usual Microsoft compiling tools.The Makefile is meant to be used with the GNU make program and the free version of the Microsoft compiler (http://msdn.microsoft.com/visualc/vctoolkit2003/). You also have to modify your system environment variables to use it from the command-line. You will also need a working Platform SDK for Windows that is available for free from Microsoft.The projects/makefiles will generate automatically some source files needed to compile GStreamer. That requires that you have installed on your system some GNU tools and that they are available in your system PATH.The GStreamer project depends on other libraries, namely :GLibpoptlibxml2libintllibiconvThere is now an existing package that has all these dependencies built with MSVC7.1. It exists either as precompiled librairies and headers in both Release and Debug mode, or as the source package to build it yourself. You can find it on http://mukoli.free.fr/gstreamer/deps/.NotesGNU tools needed that you can find on http://gnuwin32.sourceforge.net/GNU flex (tested with 2.5.4)GNU bison (tested with 1.35)and http://www.mingw.org/GNU make (tested with 3.80)the generated files from the -auto makefiles will be available soon separately on the net for convenience (people who don't want to install GNU tools).Installation on the systemBy default, GSTreamer needs a registry. You have to generate it using "gst-register.exe". It will create the file in c:\gstreamer\registry.xml that will hold all the plugins you can use.You should install the GSTreamer core in c:\gstreamer\bin and the plugins in c:\gstreamer\plugins. Both directories should be added to your system PATH. The library dependencies should be installed in c:\usrFor example, my current setup is :c:\gstreamer\registry.xmlc:\gstreamer\bin\gst-inspect.exec:\gstreamer\bin\gst-launch.exec:\gstreamer\bin\gst-register.exec:\gstreamer\bin\gstbytestream.dllc:\gstreamer\bin\gstelements.dllc:\gstreamer\bin\gstoptimalscheduler.dllc:\gstreamer\bin\gstspider.dllc:\gstreamer\bin\libgtreamer-0.8.dllc:\gstreamer\plugins\gst-libs.dllc:\gstreamer\plugins\gstmatroska.dllc:\usr\bin\iconv.dllc:\usr\bin\intl.dllc:\usr\bin\libglib-2.0-0.dllc:\usr\bin\libgmodule-2.0-0.dllc:\usr\bin\libgobject-2.0-0.dllc:\usr\bin\libgthread-2.0-0.dllc:\usr\bin\libxml2.dllc:\usr\bin\popt.dllQuotes from the Developers As well as being a cool piece of software, GStreamer is a lively project, with developers from around the globe very actively contributing. We often hang out on the #gstreamer IRC channel on irc.freenode.net: the following are a selection of amusingNo guarantee of sense of humour compatibility is given. quotes from our conversations. 14 Oct 2004 * zaheerm wonders how he can break gstreamer today :) ensonic: zaheerm, spider is always a good starting point 14 Jun 2004 teuf: ok, things work much better when I don't write incredibly stupid and buggy code thaytan: I find that too 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 --- wingo-party is now known as wingo * wingo holds head 16 Feb 2001 wtay: I shipped a few commerical products to >40000 people now but GStreamer is way more exciting... 16 Feb 2001 * tool-man is a gstreamer groupie 14 Jan 2001 Omega: did you run ldconfig? maybe it talks to init? wtay: not sure, don't think so... I did run gstreamer-register though :-) Omega: ah, that did it then ;-) wtay: right Omega: probably not, but in case GStreamer starts turning into an OS, someone please let me know? 9 Jan 2001 wtay: me tar, you rpm? wtay: hehe, forgot "zan" Omega: ? wtay: me tar"zan", you ... 7 Jan 2001 Omega: that means probably building an agreggating, cache-massaging queue to shove N buffers across all at once, forcing cache transfer. wtay: never done that before... Omega: nope, but it's easy to do in gstreamer <g> wtay: sure, I need to rewrite cp with gstreamer too, someday :-) 7 Jan 2001 wtay: GStreamer; always at least one developer is awake... 5/6 Jan 2001 wtay: we need to cut down the time to create an mp3 player down to seconds... richardb: :) Omega: I'm wanting to something more interesting soon, I did the "draw an mp3 player in 15sec" back in October '99. wtay: by the time Omega gets his hands on the editor, you'll see a complete audio mixer in the editor :-) richardb: Well, it clearly has the potential... Omega: Working on it... ;-) 28 Dec 2000 MPAA: We will sue you now, you have violated our IP rights! wtay: hehehe MPAA: How dare you laugh at us? We have lawyers! We have Congressmen! We have LARS! wtay: I'm so sorry your honor MPAA: Hrumph. * wtay bows before thy 4 Jun 2001taaz: you witchdoctors and your voodoo mpeg2 black magic... omega_: um. I count three, no four different cults there <g> ajmitch: hehe omega_: witchdoctors, voodoo, black magic, omega_: and mpeg Done. Copying .css files: base.css Copying .png images: build/images/bin-element-ghost.png build/images/bin-element-noghost.png build/images/bin-element.png build/images/filter-element-multi.png build/images/filter-element.png build/images/hello-world.png build/images/linked-elements.png build/images/mime-world.png build/images/queue.png build/images/sink-element.png build/images/src-element.png build/images/state-diagram.png build/images/thread.png make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' Making all in pwg make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' make[4]: warning: jobserver unavailable: using -j1. Add `+' to parent make rule. cd build && xmllint -noout -valid pwg.xml make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg/build/pwg.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" RichardJohnBoulton richard-gst@tartarus.org ErikWalthinsen omega@temple-baptist.com SteveBaker stevebaker_org@yahoo.co.uk LeifJohnson leif@ambient.2y.net RonaldS.Bultje rbultje@ronald.bitfreak.net This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). GStreamer Plugin Writer's Guide (0.8.11)Introduction GStreamer is an exremely powerful and versatile framework for creating streaming media applications. Many of the virtues of the GStreamer framework come from its modularity: GStreamer can seamlessly incorporate new plugin modules. But because modularity and power often come at a cost of greater complexity (consider, for example, CORBA), writing new plugins is not always easy. This guide is intended to help you understand the GStreamer framework (version 0.8.11) so you can develop new plugins to extend the existing functionality. The guide addresses most issues by following the development of an example plugin - an audio filter plugin - written in C. However, the later parts of the guide also present some issues involved in writing other types of plugins, and the end of the guide describes some of the Python bindings for GStreamer. PrefaceWho Should Read This Guide? This guide explains how to write new modules for GStreamer. The guide is relevant to several groups of people: Anyone who wants to add support for new ways of processing data in GStreamer. For example, a person in this group might want to create a new data format converter, a new visualization tool, or a new decoder or encoder. Anyone who wants to add support for new input and output devices. For example, people in this group might want to add the ability to write to a new video output system or read data from a digital camera or special microphone. Anyone who wants to extend GStreamer in any way. You need to have an understanding of how the plugin system works before you can understand the constraints that the plugin system places on the rest of the code. Also, you might be surprised after reading this at how much can be done with plugins. This guide is not relevant to you if you only want to use the existing functionality of GStreamer, or if you just want to use an application that uses GStreamer. If you are only interested in using existing plugins to write a new application - and there are quite a lot of plugins already - you might want to check the GStreamer Application Development Manual. If you are just trying to get help with a GStreamer application, then you should check with the user manual for that particular application. Preliminary Reading This guide assumes that you are somewhat familiar with the basic workings of GStreamer. For a gentle introduction to programming concepts in GStreamer, you may wish to read the GStreamer Application Development Manual first. Also check out the documentation available on the GStreamer web site. Since GStreamer adheres to the GObject programming model, this guide also assumes that you understand the basics of GObject programming. There are several good introductions to the GObject library, including the GTK+ Tutorial and the Glib Object system. Structure of This Guide To help you navigate through this guide, it is divided into several large parts. Each part addresses a particular broad topic concerning GStreamer plugin development. The parts of this guide are laid out in the following order: - Introduction to the structure of a plugin, using an example audio filter for illustration. This part covers all the basic steps you generally need to perform to build a plugin, such as registering the element with GStreamer and setting up the basics so it can receive data from and send data to neighbour elements. The discussion begins by giving examples of generating the basic structures and registering an element in . Then, you will learn how to write the code to get a basic filter plugin working in , and . After that, we will show some of the GObject concepts on how to make an element configurable for applications and how to do application-element interaction in and . Next, you will learn to build a quick test application to test all that you've just learned in . We will just touch upon basics here. For full-blown application development, you should look at the Application Development Manual. - Information on advanced features of GStreamer plugin development. After learning about the basic steps, you should be able to create a functional audio or video filter plugin with some nice features. However, GStreamer offers more for plugin writers. This part of the guide includes chapters on more advanced topics, such as scheduling, media type definitions in GStreamer, clocks, interfaces and tagging. Since these features are purpose-specific, you can read them in any order, most of them don't require knowledge from other sections. The first chapter, named , will explain some of the basics of element scheduling. It is not very in-depth, but is mostly some sort of an introduction on why other things work as they do. Read this chapter if you're interested in GStreamer internals. Next, we will apply this knowledge and discuss another type of data transmission than what you learned in : . Loop-based elements will give you more control over input rate. This is useful when writing, for example, muxers or demuxers. Next, we will discuss media identification in GStreamer in . You will learn how to define new media types and get to know a list of standard media types defined in GStreamer. In the next chapter, you will learn the concept of request- and sometimes-pads, which are pads that are created dynamically, either because the application asked for it (request) or because the media stream requires it (sometimes). This will be in . The next chapter, , will explain the concept of clocks in GStreamer. You need this information when you want to know how elements should achieve audio/video synchronization. The next few chapters will discuss advanced ways of doing application-element interaction. Previously, we learned on the GObject-ways of doing this in and . We will discuss dynamic parameters, which are a way of defining element behaviour over time in advance, in . Next, you will learn about interfaces in . Interfaces are very target- specific ways of application-element interaction, based on GObject's GInterface. Lastly, you will learn about how metadata is handled in GStreamer in . The last chapter, , will discuss the concept of events in GStreamer. Events are, on the one hand, another way of doing application-element interaction. It takes care of seeking, for example. On the other hand, it is also a way in which elements interact with each other, such as letting each other know about media stream discontinuities, forwarding tags inside a pipeline and so on. - Explanation of writing other plugin types. Because the first two parts of the guide use an audio filter as an example, the concepts introduced apply to filter plugins. But many of the concepts apply equally to other plugin types, including sources, sinks, and autopluggers. This part of the guide presents the issues that arise when working on these more specialized plugin types. The part includes chapters on , , , and . - Further information for plugin developers. The appendices contain some information that stubbornly refuses to fit cleanly in other sections of the guide. Most of this section is not yet finished. The remainder of this introductory part of the guide presents a short overview of the basic concepts involved in GStreamer plugin development. Topics covered include , , and . If you are already familiar with this information, you can use this short overview to refresh your memory, or you can skip to . As you can see, there a lot to learn, so let's get started! Creating compound and complex elements by extending from a GstBin. This will allow you to create plugins that have other plugins embedded in them. Adding new mime-types to the registry along with typedetect functions. This will allow your plugin to operate on a completely new media type. Basic Concepts This chapter of the guide introduces the basic concepts of GStreamer. Understanding these concepts will help you grok the issues involved in extending GStreamer. Many of these concepts are explained in greater detail in the GStreamer Application Development Manual; the basic concepts presented here serve mainly to refresh your memory. Elements and Plugins Elements are at the core of GStreamer. In the context of plugin development, an element is an object derived from the GstElement class. Elements provide some sort of functionality when linked with other elements: For example, a source element provides data to a stream, and a filter element acts on the data in a stream. Without elements, GStreamer is just a bunch of conceptual pipe fittings with nothing to link. A large number of elements ship with GStreamer, but extra elements can also be written. Just writing a new element is not entirely enough, however: You will need to encapsulate your element in a plugin to enable GStreamer to use it. A plugin is essentially a loadable block of code, usually called a shared object file or a dynamically linked library. A single plugin may contain the implementation of several elements, or just a single one. For simplicity, this guide concentrates primarily on plugins containing one element. A filter is an important type of element that processes a stream of data. Producers and consumers of data are called source and sink elements, respectively. Bin elements contain other elements. One type of bin is responsible for scheduling the elements that they contain so that data flows smoothly. Another type of bin, called autoplugger elements, automatically add other elements to the bin and links them together so that they act as a filter between two arbitary stream types. The plugin mechanism is used everywhere in GStreamer, even if only the standard packages are being used. A few very basic functions reside in the core library, and all others are implemented in plugins. A plugin registry is used to store the details of the plugins in an XML file. This way, a program using GStreamer does not have to load all plugins to determine which are needed. Plugins are only loaded when their provided elements are requested. See the GStreamer Library Reference for the current implementation details of GstElement and GstPlugin. Pads Pads are used to negotiate links and data flow between elements in GStreamer. A pad can be viewed as a place or port on an element where links may be made with other elements, and through which data can flow to or from those elements. Pads have specific data handling capabilities: A pad can restrict the type of data that flows through it. Links are only allowed between two pads when the allowed data types of the two pads are compatible. An analogy may be helpful here. A pad is similar to a plug or jack on a physical device. Consider, for example, a home theater system consisting of an amplifier, a DVD player, and a (silent) video projector. Linking the DVD player to the amplifier is allowed because both devices have audio jacks, and linking the projector to the DVD player is allowed because both devices have compatible video jacks. Links between the projector and the amplifier may not be made because the projector and amplifier have different types of jacks. Pads in GStreamer serve the same purpose as the jacks in the home theater system. For the most part, all data in GStreamer flows one way through a link between elements. Data flows out of one element through one or more source pads, and elements accept incoming data through one or more sink pads. Source and sink elements have only source and sink pads, respectively. See the GStreamer Library Reference for the current implementation details of a GstPad. Data, Buffers and Events All streams of data in GStreamer are chopped up into chunks that are passed from a source pad on one element to a sink pad on another element. Data are structures used to hold these chunks of data. Data contains the following important types: An exact type indicating what type of data (control, content, ...) this Data is. A reference count indicating the number of elements currently holding a reference to the buffer. When the buffer reference count falls to zero, the buffer will be unlinked, and its memory will be freed in some sense (see below for more details). There are two types of data defined: events (control) and buffers (content). Buffers may contain any sort of data that the two linked pads know how to handle. Normally, a buffer contains a chunk of some sort of audio or video data that flows from one element to another. Buffers also contain metadata describing the buffer's contents. Some of the important types of metadata are: A pointer to the buffer's data. An integer indicating the size of the buffer's data. A timestamp indicating the preferred display timestamp of the content in the buffer. Events contain information on the state of the stream flowing between the two linked pads. Events will only be sent if the element explicitely supports them, else the core will (try to) handle the events automatically. Events are used to indicate, for example, a clock discontinuity, the end of a media stream or that the cache should be flushed. Events may contain several of the following items: A subtype indicating the type of the contained event. The other contents of the event depend on the specific event type. Events will be discussed extensively in . Until then, the only event that will be used is the EOS event, which is used to indicate the end-of-stream (usually end-of-file). See the GStreamer Library Reference for the current implementation details of a GstData, GstBuffer and GstEvent. Buffer Allocation Buffers are able to store chunks of memory of several different types. The most generic type of buffer contains memory allocated by malloc(). Such buffers, although convenient, are not always very fast, since data often needs to be specifically copied into the buffer. Many specialized elements create buffers that point to special memory. For example, the filesrc element usually maps a file into the address space of the application (using mmap()), and creates buffers that point into that address range. These buffers created by filesrc act exactly like generic buffers, except that they are read-only. The buffer freeing code automatically determines the correct method of freeing the underlying memory. Downstream elements that recieve these kinds of buffers do not need to do anything special to handle or unreference it. Another way an element might get specialized buffers is to request them from a downstream peer. These are called downstream-allocated buffers. Elements can ask a peer connected to a source pad to create an empty buffer of a given size. If a downstream element is able to create a special buffer of the correct size, it will do so. Otherwise GStreamer will automatically create a generic buffer instead. The element that requested the buffer can then copy data into the buffer, and push the buffer to the source pad it was allocated from. Many sink elements have accelerated methods for copying data to hardware, or have direct access to hardware. It is common for these elements to be able to create downstream-allocated buffers for their upstream peers. One such example is ximagesink. It creates buffers that contain XImages. Thus, when an upstream peer copies data into the buffer, it is copying directly into the XImage, enabling ximagesink to draw the image directly to the screen instead of having to copy data into an XImage first. Filter elements often have the opportunity to either work on a buffer in-place, or work while copying from a source buffer to a destination buffer. It is optimal to implement both algorithms, since the GStreamer framework can choose the fastest algorithm as appropriate. Naturally, this only makes sense for strict filters -- elements that have exactly the same format on source and sink pads. Mimetypes and Properties GStreamer uses a type system to ensure that the data passed between elements is in a recognized format. The type system is also important for ensuring that the parameters required to fully specify a format match up correctly when linking pads between elements. Each link that is made between elements has a specified type and optionally a set of properties. The Basic Types GStreamer already supports many basic media types. Following is a table of a few of the the basic types used for buffers in GStreamer. The table contains the name ("mime type") and a description of the type, the properties associated with the type, and the meaning of each property. A full list of supported types is included in . Table of Basic TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Descriptionaudio/* All audio types rateintegergreater than 0 The sample rate of the data, in samples (per channel) per second. channelsintegergreater than 0 The number of channels of audio data. audio/x-raw-int Unstructured and uncompressed raw integer audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). signedbooleanTRUE or FALSE Whether the values of the integer samples are signed or not. Signed samples use one bit to indicate sign (negative or positive) of the value. Unsigned samples are always positive. widthintegergreater than 0 Number of bits allocated per sample. depthintegergreater than 0 The number of bits used per sample. This must be less than or equal to the width: If the depth is less than the width, the low bits are assumed to be the ones used. For example, a width of 32 and a depth of 24 means that each sample is stored in a 32 bit word, but only the low 24 bits are actually used. audio/mpeg Audio data compressed using the MPEG audio encoding scheme. mpegversioninteger1, 2 or 4 The MPEG-version used for encoding the data. The value 1 refers to MPEG-1, -2 and -2.5 layer 1, 2 or 3. The values 2 and 4 refer to the MPEG-AAC audio encoding schemes. framedboolean0 or 1 A true value indicates that each buffer contains exactly one frame. A false value indicates that frames and buffers do not necessarily match up. layerinteger1, 2, or 3 The compression scheme layer used to compress the data (only if mpegversion=1). bitrateintegergreater than 0 The bitrate, in bits per second. For VBR (variable bitrate) MPEG data, this is the average bitrate. audio/x-vorbisVorbis audio data There are currently no specific properties defined for this type. Building a Plugin You are now ready to learn how to build a plugin. In this part of the guide, you will learn how to apply basic GStreamer programming concepts to write a simple plugin. The previous parts of the guide have contained no explicit example code, perhaps making things a bit abstract and difficult to understand. In contrast, this section will present both applications and code by following the development of an example audio filter plugin called ExampleFilter. The example filter element will begin with a single input pad and a single output pad. The filter will, at first, simply pass media and event data from its sink pad to its source pad without modification. But by the end of this part of the guide, you will learn to add some more interesting functionality, including properties and signal handlers. And after reading the next part of the guide, , you will be able to add even more functionality to your plugins. The example code used in this part of the guide can be found in examples/pwg/examplefilter/ in your GStreamer directory. Constructing the Boilerplate In this chapter you will learn how to construct the bare minimum code for a new plugin. Starting from ground zero, you will see how to get the GStreamer template source. Then you will learn how to use a few basic tools to copy and modify a template plugin to create a new plugin. If you follow the examples here, then by the end of this chapter you will have a functional audio filter plugin that you can compile and use in GStreamer applications. Getting the GStreamer Plugin Templates There are currently two ways to develop a new plugin for GStreamer: You can write the entire plugin by hand, or you can copy an existing plugin template and write the plugin code you need. The second method is by far the simpler of the two, so the first method will not even be described here. (Errm, that is, it is left as an exercise to the reader.) The first step is to check out a copy of the gst-template CVS module to get an important tool and the source code template for a basic GStreamer plugin. To check out the gst-template module, make sure you are connected to the internet, and type the following commands at a command console: shell $ cvs -d:pserver:anoncvs@cvs.freedesktop.org/cvs/gstreamer login Logging in to :pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer CVS password: [ENTER] shell $ cvs -z3 -d:pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer co gst-template U gst-template/README U gst-template/gst-app/AUTHORS U gst-template/gst-app/ChangeLog U gst-template/gst-app/Makefile.am U gst-template/gst-app/NEWS U gst-template/gst-app/README U gst-template/gst-app/autogen.sh U gst-template/gst-app/configure.ac U gst-template/gst-app/src/Makefile.am ... After the first command, you will have to press ENTER to log in to the CVS server. (You might have to log in twice.) The second command will check out a series of files and directories into ./gst-template. The template you will be using is in ./gst-template/gst-plugin/ directory. You should look over the files in that directory to get a general idea of the structure of a source tree for a plugin. Using the Project Stamp The first thing to do when making a new element is to specify some basic details about it: what its name is, who wrote it, what version number it is, etc. We also need to define an object to represent the element and to store the data the element needs. These details are collectively known as the boilerplate. The standard way of defining the boilerplate is simply to write some code, and fill in some structures. As mentioned in the previous section, the easiest way to do this is to copy a template and add functionality according to your needs. To help you do so, there are some tools in the ./gst-plugins/tools/ directory. One tool, gst-quick-stamp, is a quick command line tool. The other, gst-project-stamp, is a full GNOME druid application that takes you through the steps of creating a new project (either a plugin or an application). To use pluginstamp.sh, first open up a terminal window. Change to the gst-template directory, and then run the pluginstamp.sh command. The arguments to the pluginstamp.sh are: the name of the plugin, and the directory that should hold a new subdirectory for the source tree of the plugin. Note that capitalization is important for the name of the plugin. Under some operating systems, capitalization is also important when specifying directory names. For example, the following commands create the ExampleFilter plugin based on the plugin template and put the output files in a new directory called ~/src/examplefilter/: shell $ cd gst-template shell $ tools/pluginstamp.sh ExampleFilter ~/src Examining the Basic Code First we will examine the code you would be likely to place in a header file (although since the interface to the code is entirely defined by the plugin system, and doesn't depend on reading a header file, this is not crucial.) The code here can be found in examples/pwg/examplefilter/boiler/gstexamplefilter.h. Example Plugin Header File /* Definition of structure storing data for this element. */ typedef struct _GstExample GstExample; struct _GstExample { GstElement element; GstPad *sinkpad, *srcpad; gboolean silent; }; /* Standard definition defining a class for this element. */ typedef struct _GstExampleClass GstExampleClass; struct _GstExampleClass { GstElementClass parent_class; }; /* Standard macros for defining types for this element. */ #define GST_TYPE_EXAMPLE \ (gst_example_get_type()) #define GST_EXAMPLE(obj) \ (G_TYPE_CHECK_CAST((obj),GST_TYPE_EXAMPLE,GstExample)) #define GST_EXAMPLE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EXAMPLE,GstExample)) #define GST_IS_EXAMPLE(obj) \ (G_TYPE_CHECK_TYPE((obj),GST_TYPE_EXAMPLE)) #define GST_IS_EXAMPLE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE)) /* Standard function returning type information. */ GType gst_example_get_type (void); GstElementDetails The GstElementDetails structure gives a hierarchical type for the element, a human-readable description of the element, as well as author and version data. The entries are: A long, english, name for the element. The type of the element, as a hierarchy. The hierarchy is defined by specifying the top level category, followed by a "/", followed by the next level category, etc. The type should be defined according to the guidelines elsewhere in this document. (FIXME: write the guidelines, and give a better reference to them) A brief description of the purpose of the element. The name of the author of the element, optionally followed by a contact email address in angle brackets. For example: static GstElementDetails example_details = { "An example plugin", "Example/FirstExample", "Shows the basic structure of a plugin", "your name <your.name@your.isp>" }; The element details are registered with the plugin during the _base_init () function, which is part of the GObject system. The _base_init () function should be set for this GObject in the function where you register the type with Glib. static void gst_my_filter_base_init (GstMyFilterClass *klass) { static GstElementDetails my_filter_details = { [..] }; GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] gst_element_class_set_details (element_class, &my_filter_details); } GstStaticPadTemplate A GstStaticPadTemplate is a description of a pad that the element will (or might) create and use. It contains: A short name for the pad.Pad direction. Existence property. This indicates whether the pad exists always (an always pad), only in some cases (a sometimes pad) or only if the application requested such a pad (a request pad). Supported types by this element (capabilities). For example: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); Those pad templates are registered during the _base_init () function. Pads are created from these templates in the element's _init () function using gst_pad_new_from_template (). The template can be retrieved from the element class using gst_element_class_get_pad_template (). See below for more details on this. In order to create a new pad from this template using gst_pad_new_from_template (), you will need to declare the pad template as a global variable. More on this subject in . static GstStaticPadTemplate sink_factory = [..], src_factory = [..]; static void gst_my_filter_base_init (GstMyFilterClass *klass) { [..] GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory)); [..] } The last argument in a template is its type or list of supported types. In this example, we use 'ANY', which means that this element will accept all input. In real-life situations, you would set a mimetype and optionally a set of properties to make sure that only supported input will come in. This representation should be a string that starts with a mimetype, then a set of comma-separates properties with their supported values. In case of an audio filter that supports raw integer 16-bit audio, mono or stereo at any samplerate, the correct template would look like this: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ( "audio/x-raw-int, " "width = (int) 16, " "depth = (int) 16, " "endianness = (int) BYTE_ORDER, " "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]" ) ); Values surrounded by curly brackets ({ and }) are lists, values surrounded by square brackets ([ and ]) are ranges. Multiple sets of types are supported too, and should be separated by a semicolon (;). Later, in the chapter on pads, we will see how to use types to know the exact format of a stream: . Constructor Functions Each element has three functions which are used for construction of an element. These are the _base_init() function which is meant to initialize class and child class properties during each new child class creation; the _class_init() function, which is used to initialise the class only once (specifying what signals, arguments and virtual functions the class has and setting up global state); and the _init() function, which is used to initialise a specific instance of this type. The plugin_init function Once we have written code defining all the parts of the plugin, we need to write the plugin_init() function. This is a special function, which is called as soon as the plugin is loaded, and should return TRUE or FALSE depending on whether it loaded initialized any dependencies correctly. Also, in this function, any supported element type in the plugin should be registered. static gboolean plugin_init (GstPlugin *plugin) { return gst_element_register (plugin, "my_filter", GST_RANK_NONE, GST_TYPE_MY_FILTER); } GST_PLUGIN_DEFINE ( GST_VERSION_MAJOR, GST_VERSION_MINOR, "my_filter", "My filter plugin", plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/" ) Note that the information returned by the plugin_init() function will be cached in a central registry. For this reason, it is important that the same information is always returned by the function: for example, it must not make element factories available based on runtime conditions. If an element can only work in certain conditions (for example, if the soundcard is not being used by some other process) this must be reflected by the element being unable to enter the READY state if unavailable, rather than the plugin attempting to deny existence of the plugin. Specifying the pads As explained before, pads are the port through which data goes in and out of your element, and that makes them a very important item in the process of element creation. In the boilerplate code, we have seen how static pad templates take care of registering pad templates with the element class. Here, we will see how to create actual elements, use _link () and _getcaps () functions to let other elements know their capabilities and how to register functions to let data flow through the element. In the element _init () function, you create the pad from the pad template that has been registered with the element class in the _base_init () function. After creating the pad, you have to set a _link () function pointer and a _getcaps () function pointer. Optionally, you can set a _chain () function pointer (on sink pads in filter and sink elements) through which data will come in to the element, or (on source pads in source elements) a _get () function pointer through which data will be pulled from the element. After that, you have to register the pad with the element. This happens like this: static GstPadLinkReturn gst_my_filter_link (GstPad *pad, const GstCaps *caps); static GstCaps * gst_my_filter_getcaps (GstPad *pad); static void gst_my_filter_chain (GstPad *pad, GstData *data); static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); /* pad through which data comes in to the element */ filter->sinkpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink"); gst_pad_set_link_function (filter->sinkpad, gst_my_filter_link); gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps); gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain); gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); /* pad through which data goes out of the element */ filter->srcpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "src"), "src"); gst_pad_set_link_function (filter->srcpad, gst_my_filter_link); gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps); gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); [..] } The link function The _link () is called during caps negotiation. This is the process where the linked pads decide on the streamtype that will transfer between them. A full list of type-definitions can be found in . A _link () receives a pointer to a GstCaps struct that defines the proposed streamtype, and can respond with either yes (GST_PAD_LINK_OK), no (GST_PAD_LINK_REFUSED) or don't know yet (GST_PAD_LINK_DELAYED). If the element responds positively towards the streamtype, that type will be used on the pad. An example: static GstPadLinkReturn gst_my_filter_link (GstPad *pad, const GstCaps *caps) { GstStructure *structure = gst_caps_get_structure (caps, 0); GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; GstPadLinkReturn ret; const gchar *mime; /* Since we're an audio filter, we want to handle raw audio * and from that audio type, we need to get the samplerate and * number of channels. */ mime = gst_structure_get_name (structure); if (strcmp (mime, "audio/x-raw-int") != 0) { GST_WARNING ("Wrong mimetype %s provided, we only support %s", mime, "audio/x-raw-int"); return GST_PAD_LINK_REFUSED; } /* we're a filter and don't touch the properties of the data. * That means we can set the given caps unmodified on the next * element, and use that negotiation return value as ours. */ ret = gst_pad_try_set_caps (otherpad, gst_caps_copy (caps)); if (GST_PAD_LINK_FAILED (ret)) return ret; /* Capsnego succeeded, get the stream properties for internal * usage and return success. */ gst_structure_get_int (structure, "rate", &filter->samplerate); gst_structure_get_int (structure, "channels", &filter->channels); g_print ("Caps negotiation succeeded with %d Hz @ %d channels\n", filter->samplerate, filter->channels); return ret; } In here, we check the mimetype of the provided caps. Normally, you don't need to do that in your own plugin/element, because the core does that for you. We simply use it to show how to retrieve the mimetype from a provided set of caps. Types are stored in GstStructure internally. A GstCaps is nothing more than a small wrapper for 0 or more structures/types. From the structure, you can also retrieve properties, as is shown above with the function gst_structure_get_int (). If your _link () function does not need to perform any specific operation (i.e. it will only forward caps), you can set it to gst_pad_proxy_link. This is a link forwarding function implementation provided by the core. It is useful for elements such as identity. The getcaps function The _getcaps () funtion is used to request the list of supported formats and properties from the element. In some cases, this will be equal to the formats provided by the pad template, in which case this function can be omitted. In some cases, too, it will not depend on anything inside this element, but it will rather depend on the input from another element linked to this element's sink or source pads. In that case, you can use gst_pad_proxy_getcaps as implementation, it provides getcaps forwarding in the core. However, in many cases, the format supported by this element cannot be defined externally, but is more specific than those provided by the pad template. In this case, you should use a _getcaps () function. In the case as specified below, we assume that our filter is able to resample sound, so it would be able to provide any samplerate (indifferent from the samplerate specified on the other pad) on both pads. It explains how a _getcaps () can be used to do this. static GstCaps * gst_my_filter_getcaps (GstPad *pad) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps; gint n; if (gst_caps_is_empty (othercaps)) return othercaps; /* We support *any* samplerate, indifferent from the samplerate * supported by the linked elements on both sides. */ for (i = 0; i < gst_caps_get_size (othercaps); i++) { GstStructure *structure = gst_caps_get_structure (othercaps, i); gst_structure_remove_field (structure, "rate"); } caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad)); gst_caps_free (othercaps); return caps; } Explicit caps Obviously, many elements will not need this complex mechanism, because they are much simpler than that. They only support one format, or their format is fixed but the contents of the format depend on the stream or something else. In those cases, explicit caps are an easy way of handling caps. Explicit caps are an easy way of specifying one, fixed, supported format on a pad. Pads using explicit caps do not implement their own _getcaps () or _link () functions. When the exact format is known, an elements uses gst_pad_set_explicit_caps () to specify the exact format. This is very useful for demuxers, for example. static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); [..] filter->srcpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "src"), "src"); gst_pad_use_explicit_caps (filter->srcpad); [..] } static void gst_my_filter_somefunction (GstMyFilter *filter) { GstCaps *caps = ..; [..] gst_pad_set_explicit_caps (filter->srcpad, caps); [..] } The chain function The chain function is the function in which all data processing takes place. In the case of a simple filter, _chain () functions are mostly linear functions - so for each incoming buffer, one buffer will go out, too. Below is a very simple implementation of a chain function: static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstBuffer *buf = GST_BUFFER (data); if (!filter->silent) g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); } Obviously, the above doesn't do much useful. Instead of printing that the data is in, you would normally process the data there. Remember, however, that buffers are not always writable. In more advanced elements (the ones that do event processing), the incoming data might not even be a buffer. static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstBuffer *buf, *outbuf; if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (pad, event); break; } return; } buf = GST_BUFFER (data); outbuf = gst_my_filter_process_data (buf); gst_buffer_unref (buf); if (!outbuf) { /* something went wrong - signal an error */ gst_element_error (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL)); return; } gst_pad_push (filter->srcpad, GST_DATA (outbuf)); } In some cases, it might be useful for an element to have control over the input data rate, too. In that case, you probably want to write a so-called loop-based element. Source elements (with only source pads) can also be get-based elements. These concepts will be explained in the advanced section of this guide, and in the section that specifically discusses source pads. What are states? A state describes whether the element instance is initialized, whether it is ready to transfer data and whether it is currently handling data. There are four states defined in GStreamer: GST_STATE_NULL, GST_STATE_READY, GST_STATE_PAUSED and GST_STATE_PLAYING. GST_STATE_NULL (from now on referred to as NULL) is the default state of an element. In this state, it has not allocated any runtime resources, it has not loaded any runtime libraries and it can obviously not handle data. GST_STATE_READY (from now on referred to as READY) is the next state that an element can be in. In the READY state, an element has all default resources (runtime-libraries, runtime-memory) allocated. However, it has not yet allocated or defined anything that is stream-specific. When going from NULL to READY state (GST_STATE_NULL_TO_READY), an element should allocate any non-stream-specific resources and should load runtime-loadable libraries (if any). When going the other way around (from READY to NULL, GST_STATE_READY_TO_NULL), an element should unload these libraries and free all allocated resources. Examples of such resources are hardware devices. Note that files are generally streams, and these should thus be considered as stream-specific resources; therefore, they should not be allocated in this state. GST_STATE_PAUSED (from now on referred to as PAUSED) is a state in which an element is by all means able to handle data; the only 'but' here is that it doesn't actually handle any data. When going from the READY state into the PAUSED state (GST_STATE_READY_TO_PAUSED), the element will usually not do anything at all: all stream-specific info is generally handled in the _link (), which is called during caps negotiation. Exceptions to this rule are, for example, files: these are considered stream-specific data (since one file is one stream), and should thus be opened in this state change. When going from the PAUSED back to READY (GST_STATE_PAUSED_TO_READY), all stream-specific data should be discarded. GST_STATE_PLAYING (from now on referred to as PLAYING) is the highest state that an element can be in. It is similar to PAUSED, except that now, data is actually passing over the pipeline. The transition from PAUSED to PLAYING (GST_STATE_PAUSED_TO_PLAYING) should be as small as possible and would ideally cause no delay at all. The same goes for the reverse transition (GST_STATE_PLAYING_TO_PAUSED). Managing filter state An element can be notified of state changes through a virtual function pointer. Inside this function, the element can initialize any sort of specific data needed by the element, and it can optionally fail to go from one state to another. Do not g_assert for unhandled state changes; this is taken care of by the GstElement base class. static GstElementStateReturn gst_my_filter_change_state (GstElement *element); static void gst_my_filter_class_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); element_class->change_state = gst_my_filter_change_state; } static GstElementStateReturn gst_my_filter_change_state (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: if (!gst_my_filter_allocate_memory (filter)) return GST_STATE_FAILURE; break; case GST_STATE_READY_TO_NULL: gst_my_filter_free_memory (filter); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } Adding Arguments The primary and most important way of controlling how an element behaves, is through GObject properties. GObject properties are defined in the _class_init () function. The element optionally implements a _get_property () and a _set_property () function. These functions will be notified if an application changes or requests the value of a property, and can then fill in the value or take action required for that property to change value internally. /* properties */ enum { ARG_0, ARG_SILENT /* FILL ME */ }; static void gst_my_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_my_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gst_my_filter_class_init (GstMyFilterClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /* define properties */ g_object_class_install_property (object_class, ARG_SILENT, g_param_spec_boolean ("silent", "Silent", "Whether to be very verbose or not", FALSE, G_PARAM_READWRITE)); /* define virtual function pointers */ object_class->set_property = gst_my_filter_set_property; object_class->get_property = gst_my_filter_get_property; } static void gst_my_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (object); switch (prop_id) { case ARG_SILENT: filter->silent = g_value_get_boolean (value); g_print ("Silent argument was changed to %s\n", filter->silent ? "true" : "false"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_my_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (object); switch (prop_id) { case ARG_SILENT: g_value_set_boolean (value, filter->silent); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } The above is a very simple example of how arguments are used. Graphical applications - for example GStreamer Editor - will use these properties and will display a user-controlleable widget with which these properties can be changed. This means that - for the property to be as user-friendly as possible - you should be as exact as possible in the definition of the property. Not only in defining ranges in between which valid properties can be located (for integers, floats, etc.), but also in using very descriptive (better yet: internationalized) strings in the definition of the property, and if possible using enums and flags instead of integers. The GObject documentation describes these in a very complete way, but below, we'll give a short example of where this is useful. Note that using integers here would probably completely confuse the user, because they make no sense in this context. The example is stolen from videotestsrc. typedef enum { GST_VIDEOTESTSRC_SMPTE, GST_VIDEOTESTSRC_SNOW, GST_VIDEOTESTSRC_BLACK } GstVideotestsrcPattern; [..] #define GST_TYPE_VIDEOTESTSRC_PATTERN (gst_videotestsrc_pattern_get_type ()) static GType gst_videotestsrc_pattern_get_type (void) { static GType videotestsrc_pattern_type = 0; if (!videotestsrc_pattern_type) { static GEnumValue pattern_types[] = { { GST_VIDEOTESTSRC_SMPTE, "smpte", "SMPTE 100% color bars" }, { GST_VIDEOTESTSRC_SNOW, "snow", "Random (television snow)" }, { GST_VIDEOTESTSRC_BLACK, "black", "0% Black" }, { 0, NULL, NULL }, }; videotestsrc_pattern_type = g_enum_register_static ("GstVideotestsrcPattern", pattern_types); } return videotestsrc_pattern_type; } [..] static void gst_videotestsrc_class_init (GstvideotestsrcClass *klass) { [..] g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TYPE, g_param_spec_enum ("pattern", "Pattern", "Type of test pattern to generate", GST_TYPE_VIDEOTESTSRC_PATTERN, 1, G_PARAM_READWRITE)); [..] } Signals GObject signals can be used to notify applications of events specific to this object. Note, however, that the application needs to be aware of signals and their meaning, so if you're looking for a generic way for application-element interaction, signals are probably not what you're looking for. In many cases, however, signals can be very useful. See the GObject documentation for all internals about signals. Building a Test Application Often, you will want to test your newly written plugin in an as small setting as possible. Usually, gst-launch is a good first step at testing a plugin. However, you will often need more testing features than gst-launch can provide, such as seeking, events, interactivity and more. Writing your own small testing program is the easiest way to accomplish this. This section explains - in a few words - how to do that. For a complete application development guide, see the Application Development Manual. At the start, you need to initialize the GStreamer core library by calling gst_init (). You can alternatively call gst_init_with_popt_tables (), which will return a pointer to popt tables. You can then use libpopt to handle the given argument table, and this will finish the GStreamer intialization. You can create elements using gst_element_factory_make (), where the first argument is the element type that you want to create, and the second argument is a free-form name. The example at the end uses a simple filesource - decoder - soundcard output pipeline, but you can use specific debugging elements if that's necessary. For example, an identity element can be used in the middle of the pipeline to act as a data-to-application transmitter. This can be used to check the data for misbehaviours or correctness in your test application. Also, you can use a fakesink element at the end of the pipeline to dump your data to the stdout (in order to do this, set the dump property to TRUE). Lastly, you can use the efence element (indeed, an eletric fence memory debugger wrapper element) to check for memory errors. During linking, your test application can use fixation or filtered caps as a way to drive a specific type of data to or from your element. This is a very simple and effective way of checking multiple types of input and output in your element. Running the pipeline happens through the gst_bin_iterate () function. Note that during running, you should connect to at least the error and eos signals on the pipeline and/or your plugin/element to check for correct handling of this. Also, you should add events into the pipeline and make sure your plugin handles these correctly (with respect to clocking, internal caching, etc.). Never forget to clean up memory in your plugin or your test application. When going to the NULL state, your element should clean up allocated memory and caches. Also, it should close down any references held to possible support libraries. Your application should unref () the pipeline and make sure it doesn't crash. #include <gst/gst.h> gint main (gint arcg, gchar *argv[]) { GstElement *pipeline, *filesrc, *decoder, *filter, *sink; /* initialization */ gst_init (&argc, &argv); /* create elements */ pipeline = gst_pipeline_new ("my_pipeline"); filesrc = gst_element_factory_make ("filesrc", "my_filesource"); decoder = gst_element_factory_make ("mad", "my_decoder"); filter = gst_element_factory_make ("my_filter", "my_filter"); sink = gst_element_factory_make ("osssink", "audiosink"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); /* link everything together */ gst_element_link_many (filesrc, decoder, filter, sink, NULL); gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, filter, sink, NULL); /* run */ gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Creating a Filter with a Filter Factory A plan for the future is to create a FilterFactory, to make the process of making a new filter a simple process of specifying a few details, and writing a small amount of code to perform the actual data processing. Ideally, a FilterFactory would perform the tasks of boilerplate creation, code functionality implementation, and filter registration. Unfortunately, this has not yet been implemented. Even when someone eventually does write a FilterFactory, this element will not be able to cover all the possibilities available for filter writing. Thus, some plugins will always need to be manually coded and registered. Here is a rough outline of what is planned: You run the FilterFactory and give the factory a list of appropriate function pointers and data structures to define a filter. With a reasonable measure of preprocessor magic, you just need to provide a name for the filter and definitions of the functions and data structures desired. Then you call a macro from within plugin_init() that registers the new filter. All the fluff that goes into the definition of a filter is thus be hidden from view. Advanced Filter Concepts By now, you should be able to create basic filter elements that can receive and send data. This is the simple model that GStreamer stands for. But GStreamer can do much more than only this! In this chapter, various advanced topics will be discussed, such as scheduling, special pad types, clocking, events, interfaces, tagging and more. These topics are the sugar that makes GStreamer so easy to use for applications. How scheduling works Scheduling is, in short, a method for making sure that every element gets called once in a while to process data and prepare data for the next element. Likewise, a kernel has a scheduler to for processes, and your brain is a very complex scheduler too in a way. Randomly calling elements' chain functions won't bring us far, however, so you'll understand that the schedulers in GStreamer are a bit more complex than this. However, as a start, it's a nice picture. GStreamer currently provides two schedulers: a basic scheduler and an optimal scheduler. As the name says, the basic scheduler (basic) is an unoptimized, but very complete and simple scheduler. The optimal scheduler (opt), on the other hand, is optimized for media processing, but therefore also more complex. Note that schedulers only operate on one thread. If your pipeline contains multiple threads, each thread will run with a separate scheduler. That is the reason why two elements running in different threads need a queue-like element (a DECOUPLED element) in between them. The Basic Scheduler The basic scheduler assumes that each element is its own process. We don't use UNIX processes or POSIX threads for this, however; instead, we use so-called co-threads. Co-threads are threads that run besides each other, but only one is active at a time. The advantage of co-threads over normal threads is that they're lightweight. The disadvantage is that UNIX or POSIX do not provide such a thing, so we need to include our own co-threads stack for this to run. The task of the scheduler here is to control which co-thread runs at what time. A well-written scheduler based on co-threads will let an element run until it outputs one piece of data. Upon pushing one piece of data to the next element, it will let the next element run, and so on. Whenever a running element requires data from the previous element, the scheduler will switch to that previous element and run that element until it has provided data for use in the next element. This method of running elements as needed has the disadvantage that a lot of data will often be queued in between two elements, as the one element has provided data but the other element hasn't actually used it yet. These storages of in-between-data are called bufpens, and they can be visualized as a light queue. Note that since every element runs in its own (co-)thread, this scheduler is rather heavy on your system for larger pipelines. The Optimal Scheduler The optimal scheduler takes advantage of the fact that several elements can be linked together in one thread, with one element controlling the other. This works as follows: in a series of chain-based elements, each element has a function that accepts one piece of data, and it calls a function that provides one piece of data to the next element. The optimal scheduler will make sure that the gst_pad_push () function of the first element directly calls the chain-function of the second element. This significantly decreases the latency in a pipeline. It takes similar advantage of other possibilities of short-cutting the data path from one element to the next. The disadvantage of the optimal scheduler is that it is not fully implemented. Also it is badly documented; for most developers, the opt scheduler is one big black box. Features that are not implemented include pad-unlinking within a group while running, pad-selecting (i.e. waiting for data to arrive on a list of pads), and it can't really cope with multi-input/-output elements (with the elements linked to each of these in-/outputs running in the same thread) right now. Some of our developers are intending to write a new scheduler, similar to the optimal scheduler (but better documented and more completely implemented). How a loopfunc works A _loop () function is a function that is called by the scheduler, but without providing data to the element. Instead, the element will become responsible for acquiring its own data, and it will still be responsible of sending data over to its source pads. This method noticeably complicates scheduling; you should only write loop-based elements when you need to. Normally, chain-based elements are preferred. Examples of elements that have to be loop-based are elements with multiple sink pads. Since the scheduler will push data into the pads as it comes (and this might not be synchronous), you will easily get asynchronous data on both pads, which means that the data that arrives on the first pad has a different display timestamp than the data arriving on the second pad at the same time. To get over these issues, you should write such elements in a loop-based form. Other elements that are easier to write in a loop-based form than in a chain-based form are demuxers and parsers. It is not required to write such elements in a loop-based form, though. Below is an example of the easiest loop-function that one can write: static void gst_my_filter_loopfunc (GstElement *element); static void gst_my_filter_init (GstMyFilter *filter) { [..] gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc); [..] } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstData *data; /* acquire data */ data = gst_pad_pull (filter->sinkpad); /* send data */ gst_pad_push (filter->srcpad, data); } Obviously, this specific example has no single advantage over a chain-based element, so you should never write such elements. However, it's a good introduction to the concept. Multi-Input Elements Elements with multiple sink pads need to take manual control over their input to assure that the input is synchronized. The following example code could (should) be used in an aggregator, i.e. an element that takes input from multiple streams and sends it out intermangled. Not really useful in practice, but a good example, again. typedef struct _GstMyFilterInputContext { gboolean eos; GstBuffer *lastbuf; } GstMyFilterInputContext; [..] static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); GstMyFilterInputContext *context; filter->sinkpad1 = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink_1"); context = g_new0 (GstMyFilterInputContext, 1); gst_pad_set_private_data (filter->sinkpad1, context); [..] filter->sinkpad2 = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink_2"); context = g_new0 (GstMyFilterInputContext, 1); gst_pad_set_private_data (filter->sinkpad2, context); [..] gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc); } [..] static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GList *padlist; GstMyFilterInputContext *first_context = NULL; /* Go over each sink pad, update the cache if needed, handle EOS * or non-responding streams and see which data we should handle * next. */ for (padlist = gst_element_get_padlist (element); padlist != NULL; padlist = g_list_next (padlist)) { GstPad *pad = GST_PAD (padlist->data); GstMyFilterInputContext *context = gst_pad_get_private_data (pad); if (GST_PAD_IS_SRC (pad)) continue; while (GST_PAD_IS_USABLE (pad) && !context->eos && !context->lastbuf) { GstData *data = gst_pad_pull (pad); if (GST_IS_EVENT (data)) { /* We handle events immediately */ GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: context->eos = TRUE; gst_event_unref (event); break; case GST_EVENT_DISCONTINUOUS: g_warning ("HELP! How do I handle this?"); /* fall-through */ default: gst_pad_event_default (pad, event); break; } } else { /* We store the buffer to handle synchronization below */ context->lastbuf = GST_BUFFER (data); } } /* synchronize streams by always using the earliest buffer */ if (context->lastbuf) { if (!first_context) { first_context = context; } else { if (GST_BUFFER_TIMESTAMP (context->lastbuf) < GST_BUFFER_TIMESTAMP (first_context->lastbuf)) first_context = context; } } } /* If we handle no data at all, we're at the end-of-stream, so * we should signal EOS. */ if (!first_context) { gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); return; } /* So we do have data! Let's forward that to our source pad. */ gst_pad_push (filter->srcpad, GST_DATA (first_context->lastbuf)); first_context->lastbuf = NULL; } Note that a loop-function is allowed to return. Better yet, a loop function has to return so the scheduler can let other elements run (this is particularly true for the optimal scheduler). Whenever the scheduler feels right, it will call the loop-function of the element again. The Bytestream Object A second type of elements that wants to be loop-based, are the so-called bytestream-elements. Until now, we've only dealt with elements that receive or pull full buffers of a random size from other elements. Often, however, it is wanted to have control over the stream at a byte-level, such as in stream parsers or demuxers. It is possible to manually pull buffers and merge them until a certain size; it is easier, however, to use bytestream, which wraps this behaviour. To use bytestream, you need to load the bytestream when your plugin is loaded; you should do this before registering the element, which you learned previously in . After that, all functions of the bytestream plugin are available in your plugin as well. #include <gst/bytestream/bytestream.h> static gboolean plugin_init (GstPlugin *plugin) { if (!gst_library_load ("gstbytestream")) return FALSE; /* and now, actually register the element */ [..] } Bytestream-using elements are usually stream parsers or demuxers. For now, we will take a parser as an example. Demuxers require some more magic that will be dealt with later in this guide: . The goal of this parser will be to parse a text-file and to push each line of text as a separate buffer over its source pad. static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); gint n, num; guint8 *data; for (n = 0; ; n++) { num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1); if (num != n + 1) { GstEvent *event = NULL; guint remaining; gst_bytestream_get_status (filter->bs, &remaining, &event); if (event) { if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)) { /* end-of-file */ gst_pad_push (filter->srcpad, GST_DATA (event)); gst_element_set_eos (element); return; } gst_event_unref (event); } /* failed to read - throw error and bail out */ gst_element_error (element, STREAM, READ, (NULL), (NULL)); return; } /* check if the last character is a newline */ if (data[n] == '\n') { GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); /* read the line of text without newline - then flush the newline */ gst_bytestream_peek_data (filter->bs, &data, n); memcpy (GST_BUFFER_DATA (buf), data, n); GST_BUFFER_DATA (buf)[n] = '\0'; gst_bytestream_flush_fast (filter->bs, n + 1); g_print ("Pushing '%s'\n", GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); return; } } } static void gst_my_filter_change_state (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_READY_TO_PAUSED: filter->bs = gst_bytestream_new (filter->sinkpad); break; case GST_STATE_PAUSED_TO_READY: gst_bytestream_destroy (filter->bs); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } In the above example, you'll notice how bytestream handles buffering of data for you. The result is that you can handle the same data multiple times. Event handling in bytestream is currently sort of wacky, but it works quite well. The one big disadvantage of bytestream is that it requires the element to be loop-based. Long-term, we hope to have a chain-based usable version of bytestream, too. Adding a second output WRITEME Modifying the test application WRITEME Types and Properties There is a very large set of possible types that may be used to pass data between elements. Indeed, each new element that is defined may use a new data format (though unless at least one other element recognises that format, it will be most likely be useless since nothing will be able to link with it). In order for types to be useful, and for systems like autopluggers to work, it is necessary that all elements agree on the type definitions, and which properties are required for each type. The GStreamer framework itself simply provides the ability to define types and parameters, but does not fix the meaning of types and parameters, and does not enforce standards on the creation of new types. This is a matter for a policy to decide, not technical systems to enforce. For now, the policy is simple: Do not create a new type if you could use one which already exists. If creating a new type, discuss it first with the other GStreamer developers, on at least one of: IRC, mailing lists. Try to ensure that the name for a new format is as unlikely to conflict with anything else created already, and is not a more generalised name than it should be. For example: "audio/compressed" would be too generalised a name to represent audio data compressed with an mp3 codec. Instead "audio/mp3" might be an appropriate name, or "audio/compressed" could exist and have a property indicating the type of compression used. Ensure that, when you do create a new type, you specify it clearly, and get it added to the list of known types so that other developers can use the type correctly when writing their elements. Building a Simple Format for Testing If you need a new format that has not yet been defined in our , you will want to have some general guidelines on mimetype naming, properties and such. A mimetype would ideally be one defined by IANA; else, it should be in the form type/x-name, where type is the sort of data this mimetype handles (audio, video, ...) and name should be something specific for this specific type. Audio and video mimetypes should try to support the general audio/video properties (see the list), and can use their own properties, too. To get an idea of what properties we think are useful, see (again) the list. Take your time to find the right set of properties for your type. There is no reason to hurry. Also, experimenting with this is generally a good idea. Experience learns that theoretically thought-out types are good, but they still need practical use to assure that they serve their needs. Make sure that your property names do not clash with similar properties used in other types. If they match, make sure they mean the same thing; properties with different types but the same names are not allowed. Typefind Functions and Autoplugging With only defining the types, we're not yet there. In order for a random data file to be recognized and played back as such, we need a way of recognizing their type out of the blue. For this purpose, typefinding was introduced. Typefinding is the process of detecting the type of a datastream. Typefinding consists of two separate parts: first, there's an unlimited number of functions that we call typefind functions, which are each able to recognize one or more types from an input stream. Then, secondly, there's a small engine which registers and calls each of those functions. This is the typefind core. On top of this typefind core, you would normally write an autoplugger, which is able to use this type detection system to dynamically build a pipeline around an input stream. Here, we will focus only on typefind functions. A typefind function ususally lives in gst-plugins/gst/typefind/gsttypefindfunctions.c, unless there's a good reason (like library dependencies) to put it elsewhere. The reason for this centralization is to decreate the number of plugins that need to be loaded in order to detect a stream's type. Below is an example that will recognize AVI files, which start with a RIFF tag, then the size of the file and then an AVI tag: static void gst_my_typefind_function (GstTypeFind *tf, gpointer data) { guint8 *data = gst_type_find_peek (tf, 0, 12); if (data && GUINT32_FROM_LE (&((guint32 *) data)[0]) == GST_MAKE_FOURCC ('R','I','F','F') && GUINT32_FROM_LE (&((guint32 *) data)[2]) == GST_MAKE_FOURCC ('A','V','I',' ')) { gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, gst_caps_new_simple ("video/x-msvideo", NULL)); } } static gboolean plugin_init (GstPlugin *plugin) { static gchar *exts[] = { "avi", NULL }; if (!gst_type_find_register (plugin, "", GST_RANK_PRIMARY, gst_my_typefind_function, exts, gst_caps_new_simple ("video/x-msvideo", NULL), NULL)) return FALSE; } Note that gst-plugins/gst/typefind/gsttypefindfunctions.c has some simplification macros to decrease the amount of code. Make good use of those if you want to submit typefinding patches with new typefind functions. Autoplugging will be discussed in great detail in the chapter called . List of Defined Types Below is a list of all the defined types in GStreamer. They are split up in separate tables for audio, video, container, subtitle and other types, for the sake of readability. Below each table might follow a list of notes that apply to that table. In the definition of each type, we try to follow the types and rules as defined by IANA for as far as possible. Jump directly to a specific table: Note that many of the properties are not required, but rather optional properties. This means that most of these properties can be extracted from the container header, but that - in case the container header does not provide these - they can also be extracted by parsing the stream header or the stream content. The policy is that your element should provide the data that it knows about by only parsing its own content, not another element's content. Example: the AVI header provides samplerate of the contained audio stream in the header. MPEG system streams don't. This means that an AVI stream demuxer would provide samplerate as a property for MPEG audio streams, whereas an MPEG demuxer would not. A decoder needing this data would require a stream parser in between two extract this from the header or calculate it from the stream. Table of Audio TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description All audio types. audio/* All audio types rateintegergreater than 0 The sample rate of the data, in samples (per channel) per second. channelsintegergreater than 0 The number of channels of audio data. All raw audio types. audio/x-raw-int Unstructured and uncompressed raw fixed-integer audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). signedbooleanTRUE or FALSE Whether the values of the integer samples are signed or not. Signed samples use one bit to indicate sign (negative or positive) of the value. Unsigned samples are always positive. widthintegergreater than 0 Number of bits allocated per sample. depthintegergreater than 0 The number of bits used per sample. This must be less than or equal to the width: If the depth is less than the width, the low bits are assumed to be the ones used. For example, a width of 32 and a depth of 24 means that each sample is stored in a 32 bit word, but only the low 24 bits are actually used. audio/x-raw-float Unstructured and uncompressed raw floating-point audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). widthintegergreater than 0 The amount of bits used and allocated per sample. buffer-framesintegerAny The number of frames per buffer. The reason for this property is that the element does not need to reuse buffers or use data spanned over multiple buffers, so this property - when used rightly - will decrease latency. Note that some people think that this property is very ugly, whereas others think it is vital for the use of GStreamer in professional audio applications. The special value zero is reserved and implies that size is variable between buffers. All encoded audio types. audio/x-ac3AC-3 or A52 audio streams. There are currently no specific properties defined or needed for this type. audio/x-adpcmADPCM Audio streams.layoutstring quicktime, dvi, microsoft or 4xm. The layout defines the packing of the samples in the stream. In ADPCM, most formats store multiple samples per channel together. This number of samples differs per format, hence the different layouts. On the long term, we probably want this variable to die and use something more descriptive, but this will do for now. block_aligninteger Any Chunk buffer size. audio/x-cinepakAudio as provided in a Cinepak (Quicktime) stream. There are currently no specific properties defined or needed for this type. audio/x-dvAudio as provided in a Digital Video stream. There are currently no specific properties defined or needed for this type. audio/x-flacFree Lossless Audio codec (FLAC). There are currently no specific properties defined or needed for this type. audio/x-gsmData encoded by the GSM codec. There are currently no specific properties defined or needed for this type. audio/x-alawA-Law Audio. There are currently no specific properties defined or needed for this type. audio/x-mulawMu-Law Audio. There are currently no specific properties defined or needed for this type. audio/x-maceMACE Audio (used in Quicktime).maceversioninteger3 or 6 The version of the MACE audio codec used to encode the stream. audio/mpeg Audio data compressed using the MPEG audio encoding scehem. mpegversioninteger1, 2 or 4 The MPEG-version used for encoding the data. The value 1 refers to MPEG-1, -2 and -2.5 layer 1, 2 or 3. The values 2 and 4 refer to the MPEG-AAC audio encoding schemes. framedboolean0 or 1 A true value indicates that each buffer contains exactly one frame. A false value indicates that frames and buffers do not necessarily match up. layerinteger1, 2, or 3 The compression scheme layer used to compress the data (only if mpegversion=1). bitrateintegergreater than 0 The bitrate, in bits per second. For VBR (variable bitrate) MPEG data, this is the average bitrate. audio/x-qdm2Data encoded by the QDM version 2 codec. There are currently no specific properties defined or needed for this type. audio/x-pn-realaudioRealmedia Audio data.raversioninteger1 or 2 The version of the Real Audio codec used to encode the stream. 1 stands for a 14k4 stream, 2 stands for a 28k8 stream. audio/x-speexData encoded by the Speex audio codec There are currently no specific properties defined or needed for this type. audio/x-vorbisVorbis audio data There are currently no specific properties defined or needed for this type. audio/x-wmaWindows Media Audiowmaversioninteger1,2 or 3 The version of the WMA codec used to encode the stream. audio/x-parisEnsoniq PARIS audio There are currently no specific properties defined or needed for this type. audio/x-svxAmiga IFF / SVX8 / SV16 audio There are currently no specific properties defined or needed for this type. audio/x-nistSphere NIST audio There are currently no specific properties defined or needed for this type. audio/x-vocSound Blaster VOC audio There are currently no specific properties defined or needed for this type. audio/x-ircamBerkeley/IRCAM/CARL audio There are currently no specific properties defined or needed for this type. audio/x-w64Sonic Foundry's 64 bit RIFF/WAV There are currently no specific properties defined or needed for this type. Table of Video TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description All video types. video/* All video types widthintegergreater than 0The width of the video imageheightintegergreater than 0The height of the video imageframeratedoublegreater than 0 The (average) framerate in frames per second. Note that this property does not guarantee in any way that it will actually come close to this value. If you need a fixed framerate, please use an element that provides that (such as videodrop). All raw video types. video/x-raw-yuvYUV (or Y'Cb'Cr) video format.formatfourcc YUY2, YVYU, UYVY, Y41P, IYU2, Y42B, YV12, I420, Y41B, YUV9, YVU9, Y800 The layout of the video. See FourCC definition site for references and definitions. YUY2, YVYU and UYVY are 4:2:2 packed-pixel, Y41P is 4:1:1 packed-pixel and IYU2 is 4:4:4 packed-pixel. Y42B is 4:2:2 planar, YV12 and I420 are 4:2:0 planar, Y41B is 4:1:1 planar and YUV9 and YVU9 are 4:1:0 planar. Y800 contains Y-samples only (black/white). video/x-raw-rgbRed-Green-Blue (RBG) video.bppintegergreater than 0 The number of bits allocated per pixel. This is usually 16, 24 or 32. depthintegergreater than 0 The number of bits used per pixel by the R/G/B components. This is usually 15, 16 or 24. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). For 24/32bpp, this should always be big endian because the byte order can be given in both. red_mask, green_mask and blue_maskintegerany The masks that cover all the bits used by each of the samples. The mask should be given in the endianness specified above. This means that for 24/32bpp, the masks might be opposite to host byte order (if you are working on little-endian computers). All encoded video types. video/x-3ivx3ivx video. There are currently no specific properties defined or needed for this type. video/x-divxDivX video.divxversioninteger3, 4 or 5 Version of the DivX codec used to encode the stream. video/x-dxDigital Video.systemstreambooleanFALSE Indicates that this stream is not a system container stream. video/x-ffvFFMpeg video.ffvversioninteger1 Version of the FFMpeg video codec used to encode the stream. video/x-h263H-263 video. There are currently no specific properties defined or needed for this type. video/x-h264H-264 video. There are currently no specific properties defined or needed for this type. video/x-huffyuvHuffyuv video. There are currently no specific properties defined or needed for this type. video/x-indeoIndeo video.indeoversioninteger3 Version of the Indeo codec used to encode this stream. video/x-jpegMotion-JPEG video. There are currently no specific properties defined or needed for this type. Note that video/x-jpeg only applies to Motion-JPEG pictures (YUY2 colourspace). RGB colourspace JPEG images are referred to as image/jpeg (JPEG image). video/mpegMPEG video.mpegversioninteger1, 2 or 4 Version of the MPEG codec that this stream was encoded with. Note that we have different mimetypes for 3ivx, XviD, DivX and "standard" ISO MPEG-4. This is not a good thing and we're fully aware of this. However, we do not have a solution yet. systemstreambooleanFALSE Indicates that this stream is not a system container stream. video/x-msmpegMicrosoft MPEG-4 video deviations.msmpegversioninteger41, 42 or 43 Version of the MS-MPEG-4-like codec that was used to encode this version. A value of 41 refers to MS MPEG 4.1, 42 to 4.2 and 43 to version 4.3. video/x-msvideocodecMicrosoft Video 1 (oldish codec).msvideoversioninteger1 Version of the codec - always 1. video/x-pn-realvideoRealmedia video.rmversioninteger1, 2 or 3 Version of the Real Video codec that this stream was encoded with. video/x-rleRLE animation format.layoutstring"microsoft" or "quicktime" The RLE format inside the Microsoft AVI container has a different byte layout than the RLE format inside Apple's Quicktime container; this property keeps track of the layout. depthinteger1 to 64 Bitdepth of the used palette. This means that the palette that belongs to this format defines 2^depth colors. palette_dataGstBuffer Buffer containing a color palette (in native-endian RGBA) used by this format. The buffer is of size 4*2^depth. video/x-svqSorensen Video.svqversioninteger1 or 3 Version of the Sorensen codec that the stream was encoded with. video/x-tarkinTarkin video. There are currently no specific properties defined or needed for this type. video/x-theoraTheora video. There are currently no specific properties defined or needed for this type. video/x-vp3VP-3 video. There are currently no specific properties defined or needed for this type. Note that we have different mimetypes for VP-3 and Theora, which is not necessarily a good idea. This could probably be improved. video/x-wmvWindows Media Videowmvversioninteger1,2 or 3 Version of the WMV codec that the stream was encoded with. video/x-xvidXviD video. There are currently no specific properties defined or needed for this type. All image types. image/jpegJoint Picture Expert Group Image. There are currently no specific properties defined or needed for this type. Note that image/jpeg only applies to RGB-colourspace JPEG images; YUY2-colourspace JPEG pictures are referred to as video/x-jpeg ("Motion JPEG"). image/pngPortable Network Graphics Image. There are currently no specific properties defined or needed for this type. Table of Container TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Descriptionvideo/x-ms-asfAdvanced Streaming Format (ASF). There are currently no specific properties defined or needed for this type. video/x-msvideoAVI. There are currently no specific properties defined or needed for this type. video/x-dvDigital Video.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. video/x-matroskaMatroska. There are currently no specific properties defined or needed for this type. video/mpegMotion Pictures Expert Group System Stream.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. application/oggOgg. There are currently no specific properties defined or needed for this type. video/quicktimeQuicktime. There are currently no specific properties defined or needed for this type. video/x-pn-realvideoDigital Video.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. audio/x-wavWAV. There are currently no specific properties defined or needed for this type. Table of Subtitle TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description None defined yet. Table of Other TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description None defined yet. Request and Sometimes pads Until now, we've only dealt with pads that are always available. However, there's also pads that are only being created in some cases, or only if the application requests the pad. The first is called a sometimes; the second is called a request pad. The availability of a pad (always, sometimes or request) can be seen in a pad's template. This chapter will discuss when each of the two is useful, how they are created and when they should be disposed. Sometimes pads A sometimes pad is a pad that is created under certain conditions, but not in all cases. This mostly depends on stream content: demuxers will generally parse the stream header, decide what elementary (video, audio, subtitle, etc.) streams are embedded inside the system stream, and will then create a sometimes pad for each of those elementary streams. At its own choice, it can also create more than one instance of each of those per element instance. The only limitation is that each newly created pad should have a unique name. Sometimes pads are disposed when the stream data is disposed, too (i.e. when going from PAUSED to the READY state). You should not dispose the pad on EOS, because someone might re-activate the pipeline and seek back to before the end-of-stream point. The stream should still stay valid after EOS, at least until the stream data is disposed. In any case, the element is always the owner of such a pad. The example code below will parse a text file, where the first line is a number (n). The next lines all start with a number (0 to n-1), which is the number of the source pad over which the data should be sent. 3 0: foo 1: bar 0: boo 2: bye The code to parse this file and create the dynamic sometimes pads, looks like this: typedef struct _GstMyFilter { [..] gboolean firstrun; GList *srcpadlist; } GstMyFilter; static void gst_my_filter_base_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ( "src_%02d", GST_PAD_SRC, GST_PAD_SOMETIMES, GST_STATIC_CAPS ("ANY") ); [..] gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); [..] } static void gst_my_filter_init (GstMyFilter *filter) { [..] filter->firstrun = TRUE; filter->srcpadlist = NULL; } /* * Get one line of data - without newline. */ static GstBuffer * gst_my_filter_getline (GstMyFilter *filter) { guint8 *data; gint n, num; /* max. line length is 512 characters - for safety */ for (n = 0; n < 512; n++) { num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1); if (num != n + 1) return NULL; /* newline? */ if (data[n] == '\n') { GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); gst_bytestream_peek_bytes (filter->bs, &data, n); memcpy (GST_BUFFER_DATA (buf), data, n); GST_BUFFER_DATA (buf)[n] = '\0'; gst_bytestream_flush_fast (filter->bs, n + 1); return buf; } } } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstBuffer *buf; GstPad *pad; gint num, n; /* parse header */ if (filter->firstrun) { GstElementClass *klass; GstPadTemplate *templ; gchar *padname; if (!(buf = gst_my_filter_getline (filter))) { gst_element_error (element, STREAM, READ, (NULL), ("Stream contains no header")); return; } num = atoi (GST_BUFFER_DATA (buf)); gst_buffer_unref (buf); /* for each of the streams, create a pad */ klass = GST_ELEMENT_GET_CLASS (filter); templ = gst_element_class_get_pad_template (klass, "src_%02d"); for (n = 0; n < num; n++) { padname = g_strdup_printf ("src_%02d", n); pad = gst_pad_new_from_template (templ, padname); g_free (padname); /* here, you would set _getcaps () and _link () functions */ gst_element_add_pad (element, pad); filter->srcpadlist = g_list_append (filter->srcpadlist, pad); } } /* and now, simply parse each line and push over */ if (!(buf = gst_my_filter_getline (filter))) { GstEvent *event = gst_event_new (GST_EVENT_EOS); GList *padlist; for (padlist = srcpadlist; padlist != NULL; padlist = g_list_next (padlist)) { pad = GST_PAD (padlist->data); gst_event_ref (event); gst_pad_push (pad, GST_DATA (event)); } gst_event_unref (event); gst_element_set_eos (element); return; } /* parse stream number and go beyond the ':' in the data */ num = atoi (GST_BUFFER_DATA (buf)); if (num >= 0 && num < g_list_length (filter->srcpadlist)) { pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num); /* magic buffer parsing foo */ for (n = 0; GST_BUFFER_DATA (buf)[n] != ':' && GST_BUFFER_DATA (buf)[n] != '\0'; n++) ; if (GST_BUFFER_DATA (buf)[n] != '\0') { GstBuffer *sub; /* create subbuffer that starts right past the space. The reason * that we don't just forward the data pointer is because the * pointer is no longer the start of an allocated block of memory, * but just a pointer to a position somewhere in the middle of it. * That cannot be freed upon disposal, so we'd either crash or have * a memleak. Creating a subbuffer is a simple way to solve that. */ sub = gst_buffer_create_sub (buf, n + 1, GST_BUFFER_SIZE (buf) - n - 1); gst_pad_push (pad, GST_DATA (sub)); } } gst_buffer_unref (buf); } Note that we use a lot of checks everywhere to make sure that the content in the file is valid. This has two purposes: first, the file could be erronous, in which case we prevent a crash. The second and most important reason is that - in extreme cases - the file could be used maliciously to cause undefined behaviour in the plugin, which might lead to security issues. Always assume that the file could be used to do bad things. Request pads Request pads are similar to sometimes pads, except that request are created on demand of something outside of the element rather than something inside the element. This concept is often used in muxers, where - for each elementary stream that is to be placed in the output system stream - one sink pad will be requested. It can also be used in elements with a variable number of input or outputs pads, such as the tee (multi-output), switch or aggregator (both multi-input) elements. At the time of writing this, it is unclear to me who is responsible for cleaning up the created pad and how or when that should be done. Below is a simple example of an aggregator based on request pads. static GstPad * gst_my_filter_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name); static void gst_my_filter_base_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink_%d", GST_PAD_SINK, GST_PAD_REQUEST, GST_STATIC_CAPS ("ANY") ); [..] gst_element_class_add_pad_template (klass, gst_static_pad_template_get (&sink_factory)); } static void gst_my_filter_class_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] element_class->request_new_pad = gst_my_filter_request_new_pad; } static GstPad * gst_my_filter_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name) { GstPad *pad; GstMyFilterInputContext *context; context = g_new0 (GstMyFilterInputContext, 1); pad = gst_pad_new_from_template (templ, name); gst_element_set_private_data (pad, context); /* normally, you would set _link () and _getcaps () functions here */ gst_element_add_pad (element, pad); return pad; } The _loop () function is the same as the one given previously in . Clocking When playing complex media, each sound and video sample must be played in a specific order at a specific time. For this purpose, GStreamer provides a syncrhonization mechanism. Types of time There are two kinds of time in GStreamer. Clock time is an absolute time. By contrast, element time is the relative time, usually to the start of the current media stream. The element time represents the time that should have a media sample that is being processed by the element at this time. The element time is calculated by adding an offset to the clock time. Clocks GStreamer can use different clocks. Though the system time can be used as a clock, soundcards and other devices provides a better time source. For this reason some elements provide a clock. The method get_clock is implemented in elements that provide one. As clocks return an absolute measure of time, they are not usually used directly. Instead, a reference to a clock is stored in any element that needs it, and it is used internaly by GStreamer to calculate the element time. Flow of data between elements and time Now we will see how time information travels the pipeline in different states. The pipeline starts playing. The source element typically knows the time of each sample. Sometimes it is a parser element the one that knows the time, for instance if a pipeline contains a filesrc element connected to a MPEG decoder element, the former is the one that knows the time of each sample, because the knowledge of when to play each sample is embedded in the MPEG format. In this case this element will be regarded as the source element for this discussion. First, the source element sends a discontinous event. This event carries information about the current relative time of the next sample. This relative time is arbitrary, but it must be consistent with the timestamp that will be placed in buffers. It is expected to be the relative time to the start of the media stream, or whatever makes sense in the case of each media. When receiving it, the other elements adjust their offset of the element time so that this time matches the time written in the event. Then the source element sends media samples in buffers. This element places a timestamp in each buffer saying when the sample should be played. When the buffer reachs the sink pad of the last element, this element compares the current element time with the timestamp of the buffer. If the timestamp is higher or equal it plays the buffer, otherwise it waits until the time to place the buffer arrives with gst_element_wait(). If the stream is seeked, the next samples sent will have a timestamp that is not adjusted with the element time. Therefore, the source element must send a discontinous event. Obligations of each element. Let us clarify the contract between GStreamer and each element in the pipeline. Source elements Source elements (or parsers of formats that provide notion of time, such as MPEG, as explained above) must place a timestamp in each buffer that they deliver. The origin of the time used is arbitrary, but it must match the time delivered in the discontinous event (see below). However, it is expected that the origin is the origin of the media stream. In order to initialize the element time of the rest of the pipeline, a source element must send a discontinous event before starting to play. In addition, after seeking, a discontinious event must be sent, because the timestamp of the next element does not match the element time of the rest of the pipeline. Sink elements If the element is intended to emit samples at a specific time (real time playing), the element should require a clock, and thus implement the method set_clock. In addition, before playing each sample, if the current element time is less than the timestamp in the sample, it wait until the current time arrives should call gst_element_wait() With some schedulers, gst_element_wait() blocks the pipeline. For instance, if there is one audio sink element and one video sink element, while the audio element is waiting for a sample the video element cannot play other sample. This behaviour is under discussion, and might change in a future release. See an example in Supporting Dynamic Parameters Sometimes object properties are not powerful enough to control the parameters that affect the behaviour of your element. When this is the case you can expose these parameters as Dynamic Parameters which can be manipulated by any Dynamic Parameters aware application. Throughout this section, the term dparams will be used as an abbreviation for "Dynamic Parameters". Comparing Dynamic Parameters with GObject Properties Your first exposure to dparams may be to convert an existing element from using object properties to using dparams. The following table gives an overview of the difference between these approaches. The significance of these differences should become apparent later on. Object PropertiesDynamic ParametersParameter definitionClass level at compile timeAny level at run timeGetting and settingImplemented by element subclass as functionsHandled entirely by dparams subsystemExtra objects requiredNone - all functionality is derived from base GObjectElement needs to create and store a GstDParamManager at object creationFrequency and resolution of updatesObject properties will only be updated between calls to _get, _chain or _loopdparams can be updated at any rate independent of calls to _get, _chain or _loop up to sample-level accuracyGetting Started The dparams subsystem is contained within the gstcontrol library. You need to include the header in your element's source file: #include <gst/control/control.h> Even though the gstcontrol library may be linked into the host application, you should make sure it is loaded in your plugin_init function: static gboolean plugin_init (GModule *module, GstPlugin *plugin) { ... /* load dparam support library */ if (!gst_library_load ("gstcontrol")) { gst_info ("example: could not load support library: 'gstcontrol'\n"); return FALSE; } ... } You need to store an instance of GstDParamManager in your element's struct: struct _GstExample { GstElement element; ... GstDParamManager *dpman; ... }; The GstDParamManager can be initialised in your element's init function: static void gst_example_init (GstExample *example) { ... example->dpman = gst_dpman_new ("example_dpman", GST_ELEMENT(example)); ... } Defining Parameter Specifications You can define the dparams you need anywhere within your element but will usually need to do so in only a couple of places: In the element init function, just after the call to gst_dpman_new Whenever a new pad is created so that parameters can affect data going into or out of a specific pad. An example of this would be a mixer element where a separate volume parameter is needed on every pad. There are three different ways the dparams subsystem can pass parameters into your element. Which one you use will depend on how that parameter is used within your element. Each of these methods has its own function to define a required dparam: gst_dpman_add_required_dparam_directgst_dpman_add_required_dparam_callbackgst_dpman_add_required_dparam_array These functions will return TRUE if the required dparam was added successfully. The following function will be used as an example. gboolean gst_dpman_add_required_dparam_direct (GstDParamManager *dpman, GParamSpec *param_spec, gboolean is_log, gboolean is_rate, gpointer update_data) The common parameters to these functions are: GstDParamManager *dpman the element's dparam manager GParamSpec *param_spec the param spec which defines the required dparam gboolean is_log whether this dparam value should be interpreted on a log scale (such as a frequency or a decibel value) gboolean is_rate whether this dparam value is a proportion of the sample rate. For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz. Direct Method This method is the simplest and has the lowest overhead for parameters which change less frequently than the sample rate. First you need somewhere to store the parameter - this will usually be in your element's struct. struct _GstExample { GstElement element; ... GstDParamManager *dpman; gfloat volume; ... }; Then to define the required dparam just call gst_dpman_add_required_dparam_direct and pass in the location of the parameter to change. In this case the location is &(example->volume). gst_dpman_add_required_dparam_direct ( example->dpman, g_param_spec_float("volume","Volume","Volume of the audio", 0.0, 1.0, 0.8, G_PARAM_READWRITE), FALSE, FALSE, &(example->volume) ); You can now use example->volume anywhere in your element knowing that it will always contain the correct value to use. Callback Method This should be used if the you have other values to calculate whenever a parameter changes. If you used the direct method you wouldn't know if a parameter had changed so you would have to recalculate the other values every time you needed them. By using the callback method, other values only have to be recalculated when the dparam value actually changes. The following code illustrates an instance where you might want to use the callback method. If you had a volume dparam which was represented by a gfloat number, your element may only deal with integer arithmetic. The callback could be used to calculate the integer scaler when the volume changes. First you will need somewhere to store these values. struct _GstExample { GstElement element; ... GstDParamManager *dpman; gfloat volume_f; gint volume_i; ... }; When the required dparam is defined, the callback function gst_example_update_volume and some user data (which in this case is our element instance) is passed in to the call to gst_dpman_add_required_dparam_callback. gst_dpman_add_required_dparam_callback ( example->dpman, g_param_spec_float("volume","Volume","Volume of the audio", 0.0, 1.0, 0.8, G_PARAM_READWRITE), FALSE, FALSE, gst_example_update_volume, example ); The callback function needs to conform to this signature typedef void (*GstDPMUpdateFunction) (GValue *value, gpointer data); In our example the callback function looks like this static void gst_example_update_volume(GValue *value, gpointer data) { GstExample *example = (GstExample*)data; g_return_if_fail(GST_IS_EXAMPLE(example)); example->volume_f = g_value_get_float(value); example->volume_i = example->volume_f * 8192; } Now example->volume_i can be used elsewhere and it will always contain the correct value. Array Method This method is quite different from the other two. It could be thought of as a specialised method which should only be used if you need the advantages that it provides. Instead of giving the element a single value it provides an array of values where each item in the array corresponds to a sample of audio in your buffer. There are a couple of reasons why this might be useful. Certain optimisations may be possible since you can iterate over your dparams array and your buffer data together. Some dparams may be able to interpolate changing values at the sample rate. This would allow the array to contain very smoothly changing values which may be required for the stability and quality of some DSP algorithms. The array method is currently the least mature of the three methods and is not yet ready to be used in elements, but plugin writers should be aware of its existence for the future. The Data Processing Loop This is the most critical aspect of the dparams subsystem as it relates to elements. In a traditional audio processing loop, a for loop will usually iterate over each sample in the buffer, processing one sample at a time until the buffer is finished. A simplified loop with no error checking might look something like this. static void example_chain (GstPad *pad, GstBuffer *buf) { ... gfloat *float_data; int j; GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad)); int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat); float_data = (gfloat *)GST_BUFFER_DATA(buf); ... for (j = 0; j < num_samples; j++) { float_data[j] *= example->volume; } ... } To make this dparams aware, a couple of changes are needed. static void example_chain (GstPad *pad, GstBuffer *buf) { ... int j = 0; GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad)); int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat); gfloat *float_data = (gfloat *)GST_BUFFER_DATA(buf); int frame_countdown = GST_DPMAN_PREPROCESS(example->dpman, num_samples, GST_BUFFER_TIMESTAMP(buf)); ... while (GST_DPMAN_PROCESS_COUNTDOWN(example->dpman, frame_countdown, j)) { float_data[j++] *= example->volume; } ... } The biggest changes here are 2 new macros, GST_DPMAN_PREPROCESS and GST_DPMAN_PROCESS_COUNTDOWN. You will also notice that the for loop has become a while loop. GST_DPMAN_PROCESS_COUNTDOWN is called as the condition for the while loop so that any required dparams can be updated in the middle of a buffer if required. This is because one of the required behaviours of dparams is that they can be sample accurate. This means that parameters change at the exact timestamp that they are supposed to - not after the buffer has finished being processed. It may be alarming to see a macro as the condition for a while loop, but it is actually very efficient. The macro expands to the following. #define GST_DPMAN_PROCESS_COUNTDOWN(dpman, frame_countdown, frame_count) \ (frame_countdown-- || \ (frame_countdown = GST_DPMAN_PROCESS(dpman, frame_count))) So as long as frame_countdown is greater than 0, GST_DPMAN_PROCESS will not be called at all. Also in many cases, GST_DPMAN_PROCESS will do nothing and simply return 0, meaning that there is no more data in the buffer to process. The macro GST_DPMAN_PREPROCESS will do the following: Update any dparams which are due to be updated. Calculate how many samples should be processed before the next required update Return the number of samples until next update, or the number of samples in the buffer - whichever is less. In fact GST_DPMAN_PROCESS may do the same things as GST_DPMAN_PREPROCESS depending on the mode that the dparam manager is running in (see below). DParam Manager Modes A brief explanation of dparam manager modes might be useful here even though it doesn't generally affect the way your element is written. There are different ways media applications will be used which require that an element's parameters be updated in differently. These include: Timelined - all parameter changes are known in advance before the pipeline is run. Realtime low-latency - Nothing is known ahead of time about when a parameter might change. Changes need to be propagated to the element as soon as possible. When a dparam-aware application gets the dparam manager for an element, the first thing it will do is set the dparam manager mode. Current modes are "synchronous" and "asynchronous". If you are in a realtime low-latency situation then the "synchronous" mode is appropriate. During GST_DPMAN_PREPROCESS this mode will poll all dparams for required updates and propagate them. GST_DPMAN_PROCESS will do nothing in this mode. To then achieve the desired latency, the size of the buffers needs to be reduced so that the dparams will be polled for updates at the desired frequency. In a timelined situation, the "asynchronous" mode will be required. This mode hasn't actually been implemented yet but will be described anyway. The GST_DPMAN_PREPROCESS call will precalculate when and how often each dparam needs to update for the duration of the current buffer. From then on GST_DPMAN_PROCESS will propagate the calculated updates each time it is called until end of the buffer. If the application is rendering to disk in non-realtime, the render could be sped up by increasing the buffer size. In the "asynchronous" mode this could be done without affecting the sample accuracy of the parameter updates Dynamic Parameters for Video All of the explanation so far has presumed that the buffer contains audio data with many samples. Video should be regarded differently since a video buffer often contains only 1 frame. In this case some of the complexity of dparams isn't required but the other benefits still make it useful for video parameters. If a buffer only contains one frame of video, only a single call to GST_DPMAN_PREPROCESS should be required. For more than one frame per buffer, treat it the same as the audio case. MIDI WRITEME Interfaces Previously, in the chapter , we have introduced the concept of GObject properties of controlling an element's behaviour. This is very powerful, but it has two big disadvantages: first of all, it is too generic, and second, it isn't dynamic. The first disadvantage is related to the customizability of the end-user interface that will be built to control the element. Some properties are more important than others. Some integer properties are better shown in a spin-button widget, whereas others would be better represented by a slider widget. Such things are not possible because the UI has no actual meaning in the application. A UI widget that represents a bitrate property is the same as a UI widget that represents the size of a video, as long as both are of the same GParamSpec type. Another problem, is that things like parameter grouping, function grouping, or parameter coupling are not really possible. The second problem with parameters are that they are not dynamic. In many cases, the allowed values for a property are not fixed, but depend on things that can only be detected at runtime. The names of inputs for a TV card in a video4linux source element, for example, can only be retrieved from the kernel driver when we've opened the device; this only happens when the element goes into the READY state. This means that we cannot create an enum property type to show this to the user. The solution to those problems is to create very specialized types of controls for certain often-used controls. We use the concept of interfaces to achieve this. The basis of this all is the glib GTypeInterface type. For each case where we think it's useful, we've created interfaces which can be implemented by elements at their own will. We've also created a small extension to GTypeInterface (which is static itself, too) which allows us to query for interface availability based on runtime properties. This extension is called GstImplementsInterface. One important note: interfaces do not replace properties. Rather, interfaces should be built next to properties. There are two important reasons for this. First of all, properties can be saved in XML files. Second, properties can be specified on the commandline (gst-launch). How to Implement Interfaces Implementing interfaces is intiated in the _get_type () of your element. You can register one or more interfaces after having registered the type itself. Some interfaces have dependencies on other interfaces or can only be registered by certain types of elements. You will be notified of doing that wrongly when using the element: it will quit with failed assertions, which will explain what went wrong. In the case of GStreamer, the only dependency that some interfaces have is GstImplementsInterface. Per interface, we will indicate clearly when it depends on this extension. If it does, you need to register support for that interface before registering support for the interface that you're wanting to support. The example below explains how to add support for a simple interface with no further dependencies. For a small explanation on GstImplementsInterface, see the next section about the mixer interface: . static void gst_my_filter_some_interface_init (GstSomeInterface *iface); GType gst_my_filter_get_type (void) { static GType my_filter_type = 0; if (!my_filter_type) { static const GTypeInfo my_filter_info = { sizeof (GstMyFilterClass), (GBaseInitFunc) gst_my_filter_base_init, NULL, (GClassInitFunc) gst_my_filter_class_init, NULL, NULL, sizeof (GstMyFilter), 0, (GInstanceInitFunc) gst_my_filter_init }; static const GInterfaceInfo some_interface_info = { (GInterfaceInitFunc) gst_my_filter_some_interface_init, NULL, NULL }; my_filter_type = g_type_register_static (GST_TYPE_MY_FILTER, "GstMyFilter", &my_filter_info, 0); g_type_add_interface_static (my_filter_type, GST_TYPE_SOME_INTERFACE, &some_interface_info); } return my_filter_type; } static void gst_my_filter_some_interface_init (GstSomeInterface *iface) { /* here, you would set virtual function pointers in the interface */ } Mixer Interface The goal of the mixer interface is to provide a simple yet powerful API to applications for audio hardware mixer/volume control. Most soundcards have hardware mixers, where volume can be changed, they can be muted, inputs can be modified to mix their content into what will be read from the device by applications (in our case: audio source plugins). The mixer interface is the way to control those. The mixer interface can also be used for volume control in software (e.g. the volume element). The end goal of this interface is to allow development of hardware volume control applications and for the control of audio volume and input/output settings. The mixer interface requires the GstImplementsInterface interface to be implemented by the element. The example below will feature both, so it serves as an example for the GstImplementsInterface, too. In this interface, it is required to set a function pointer for the supported () function. If you don't, this function will always return FALSE (default implementation) and the mixer interface implementation will not work. For the mixer interface, the only required function is list_tracks (). All other function pointers in the mixer interface are optional, although it is strongly recommended to set function pointers for at least the get_volume () and set_volume () functions. The API reference for this interface documents the goal of each function, so we will limit ourselves to the implementation here. The following example shows a mixer implementation for a software N-to-1 element. It does not show the actual process of stream mixing, that is far too complicated for this guide. #include <gst/mixer/mixer.h> typedef struct _GstMyFilter { [..] gint volume; GList *tracks; } GstMyFilter; static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface); static void gst_my_filter_mixer_interface_init (GstMixerClass *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo implements_interface_info = { (GInterfaceInitFunc) gst_my_filter_implements_interface_init, NULL, NULL }; static const GInterfaceInfo mixer_interface_info = { (GInterfaceInitFunc) gst_my_filter_mixer_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); g_type_add_interface_static (my_filter_type, GST_TYPE_MIXER, &mixer_interface_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GstMixerTrack *track = NULL; [..] filter->volume = 100; filter->tracks = NULL; track = g_object_new (GST_TYPE_MIXER_TRACK, NULL); track->label = g_strdup ("MyTrack"); track->num_channels = 1; track->min_volume = 0; track->max_volume = 100; track->flags = GST_MIXER_TRACK_SOFTWARE; filter->tracks = g_list_append (filter->tracks, track); } static gboolean gst_my_filter_interface_supported (GstImplementsInterface *iface, GType iface_type) { g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); /* for the sake of this example, we'll always support it. However, normally, * you would check whether the device you've opened supports mixers. */ return TRUE; } static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface) { iface->supported = gst_my_filter_interface_supported; } /* * This function returns the list of support tracks (inputs, outputs) * on this element instance. Elements usually build this list during * _init () or when going from NULL to READY. */ static const GList * gst_my_filter_mixer_list_tracks (GstMixer *mixer) { GstMyFilter *filter = GST_MY_FILTER (mixer); return filter->tracks; } /* * Set volume. volumes is an array of size track->num_channels, and * each value in the array gives the wanted volume for one channel * on the track. */ static void gst_my_filter_mixer_set_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes) { GstMyFilter *filter = GST_MY_FILTER (mixer); filter->volume = volumes[0]; g_print ("Volume set to %d\n", filter->volume); } static void gst_my_filter_mixer_get_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes) { GstMyFilter *filter = GST_MY_FILTER (mixer); volumes[0] = filter->volume; } static void gst_my_filter_mixer_interface_init (GstMixerClass *iface) { /* the mixer interface requires a definition of the mixer type: * hardware or software? */ GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE; /* virtual function pointers */ iface->list_tracks = gst_my_filter_mixer_list_tracks; iface->set_volume = gst_my_filter_mixer_set_volume; iface->get_volume = gst_my_filter_mixer_get_volume; } The mixer interface is very audio-centric. However, with the software flag set, the mixer can be used to mix any kind of stream in a N-to-1 element to join (not aggregate!) streams together into one output stream. Conceptually, that's called mixing too. You can always use the element factory's category to indicate type of your element. In a software element that mixes random streams, you would not be required to implement the _get_volume () or _set_volume () functions. Rather, you would only implement the _set_record () to enable or disable tracks in the output stream. to make sure that a mixer-implementing element is of a certain type, check the element factory's category. Tuner Interface As opposed to the mixer interface, that's used to join together N streams into one output stream by mixing all streams together, the tuner interface is used in N-to-1 elements too, but instead of mixing the input streams, it will select one stream and push the data of that stream to the output stream. It will discard the data of all other streams. There is a flag that indicates whether this is a software-tuner (in which case it is a pure software implementation, with N sink pads and 1 source pad) or a hardware-tuner, in which case it only has one source pad, and the whole stream selection process is done in hardware. The software case can be used in elements such as switch. The hardware case can be used in elements with channel selection, such as video source elements (v4lsrc, v4l2src, etc.). If you need a specific element type, use the element factory's category to make sure that the element is of the type that you need. Note that the interface itself is highly analog-video-centric. This interface requires the GstImplemensInterface interface to work correctly. The following example shows how to implement the tuner interface in an element. It does not show the actual process of stream selection, that is irrelevant for this section. #include <gst/tuner/tuner.h> typedef struct _GstMyFilter { [..] gint active_input; GList *channels; } GstMyFilter; static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface); static void gst_my_filter_tuner_interface_init (GstTunerClass *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo implements_interface_info = { (GInterfaceInitFunc) gst_my_filter_implements_interface_init, NULL, NULL }; static const GInterfaceInfo tuner_interface_info = { (GInterfaceInitFunc) gst_my_filter_tuner_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); g_type_add_interface_static (my_filter_type, GST_TYPE_TUNER, &tunerr_interface_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GstTunerChannel *channel = NULL; [..] filter->active_input = 0; filter->channels = NULL; channel = g_object_new (GST_TYPE_TUNER_CHANNEL, NULL); channel->label = g_strdup ("MyChannel"); channel->flags = GST_TUNER_CHANNEL_INPUT; filter->channels = g_list_append (filter->channels, channel); } static gboolean gst_my_filter_interface_supported (GstImplementsInterface *iface, GType iface_type) { g_return_val_if_fail (iface_type == GST_TYPE_TUNER, FALSE); /* for the sake of this example, we'll always support it. However, normally, * you would check whether the device you've opened supports tuning. */ return TRUE; } static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface) { iface->supported = gst_my_filter_interface_supported; } static const GList * gst_my_filter_tuner_list_channels (GstTuner *tuner) { GstMyFilter *filter = GST_MY_FILTER (tuner); return filter->channels; } static GstTunerChannel * gst_my_filter_tuner_get_channel (GstTuner *tuner) { GstMyFilter *filter = GST_MY_FILTER (tuner); return g_list_nth_data (filter->channels, filter->active_input); } static void gst_my_filter_tuner_set_channel (GstTuner *tuner, GstTunerChannel *channel) { GstMyFilter *filter = GST_MY_FILTER (tuner); filter->active_input = g_list_index (filter->channels, channel); g_assert (filter->active_input >= 0); } static void gst_my_filter_tuner_interface_init (GstTunerClass *iface) { iface->list_channels = gst_my_filter_tuner_list_channels; iface->get_channel = gst_my_filter_tuner_get_channel; iface->set_channel = gst_my_filter_tuner_set_channel; } As said, the tuner interface is very analog video-centric. It features functions for selecting an input or output, and on inputs, it features selection of a tuning frequency if the channel supports frequency-tuning on that input. Likewise, it allows signal-strength-acquiring if the input supports that. Frequency tuning can be used for radio or cable-TV tuning. Signal-strength is an indication of the signal and can be used for visual feedback to the user or for autodetection. Next to that, it also features norm selection, which is only useful for analog video elements. Color Balance Interface WRITEME Property Probe Interface Property probing is a generic solution to the problem that properties' value lists in an enumeration are static. We've shown enumerations in . Property probing tries to accomplish a goal similar to enumeration lists: to have a limited, explicit list of allowed values for a property. There are two differences between enumeration lists and probing. Firstly, enumerations only allow strings as values; property probing works for any value type. Secondly, the contents of a probed list of allowed values may change during the life of an element. The contents of an enumeration list are static. Currently, property probing is being used for detection of devices (e.g. for OSS elements, Video4linux elements, etc.). It could - in theory - be used for any property, though. Property probing stores the list of allowed (or recommended) values in a GValueArray and returns that to the user. NULL is a valid return value, too. The process of property probing is separated over two virtual functions: one for probing the property to create a GValueArray, and one to retrieve the current GValueArray. Those two are separated because probing might take a long time (several seconds). Also, this simpliies interface implementation in elements. For the application, there are functions that wrap those two. For more information on this, have a look at the API reference for the GstPropertyProbe interface. Below is a example of property probing for the audio filter element; it will probe for allowed values for the silent property. Indeed, this value is a gboolean so it doesn't make much sense. Then again, it's only an example. #include <gst/propertyprobe/propertyprobe.h> static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo probe_interface_info = { (GInterfaceInitFunc) gst_my_filter_probe_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_PROPERTY_PROBE, &probe_interface_info); [..] } static const GList * gst_my_filter_probe_get_properties (GstPropertyProbe *probe) { GObjectClass *klass = G_OBJECT_GET_CLASS (probe); static GList *props = NULL; if (!props) { GParamSpec *pspec; pspec = g_object_class_find_property (klass, "silent"); props = g_list_append (props, pspec); } return props; } static gboolean gst_my_filter_probe_needs_probe (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { gboolean res = FALSE; switch (prop_id) { case ARG_SILENT: res = FALSE; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } return res; } static void gst_my_filter_probe_probe_property (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { switch (prop_id) { case ARG_SILENT: /* don't need to do much here... */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } } static GValueArray * gst_my_filter_get_silent_values (GstMyFilter *filter) { GValueArray *array = g_value_array_new (2); GValue value = { 0 }; g_value_init (&value, G_TYPE_BOOLEAN); /* add TRUE */ g_value_set_boolean (&value, TRUE); g_value_array_append (array, &value); /* add FALSE */ g_value_set_boolean (&value, FALSE); g_value_array_append (array, &value); g_value_unset (&value); return array; } static GValueArray * gst_my_filter_probe_get_values (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (probe); GValueArray *array = NULL; switch (prop_id) { case ARG_SILENT: array = gst_my_filter_get_silent_values (filter); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } return array; } static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface) { iface->get_properties = gst_my_filter_probe_get_properties; iface->needs_probe = gst_my_filter_probe_needs_probe; iface->probe_property = gst_my_filter_probe_probe_property; iface->get_values = gst_my_filter_probe_get_values; } You don't need to support any functions for getting or setting values. All that is handled via the standard GObject _set_property () and _get_property () functions. X Overlay Interface An X Overlay is basically a video output in a XFree86 drawable. Elements implementing this interface will draw video in a X11 window. Through this interface, applications will be proposed 2 different modes to work with a plugin implemeting it. The first mode is a passive mode where the plugin owns, creates and destroys the X11 window. The second mode is an active mode where the application handles the X11 window creation and then tell the plugin where it should output video. Let's get a bit deeper in those modes... A plugin drawing video output in a X11 window will need to have that window at one stage or another. Passive mode simply means that no window has been given to the plugin before that stage, so the plugin created the window by itself. In that case the plugin is responsible of destroying that window when it's not needed anymore and it has to tell the applications that a window has been created so that the application can use it. This is done using the have_xwindow_id signal that can be emitted from the plugin with the gst_x_overlay_got_xwindow_id method. As you probably guessed already active mode just means sending a X11 window to the plugin so that video output goes there. This is done using the gst_x_overlay_set_xwindow_id method. It is possible to switch from one mode to another at any moment, so the plugin implementing this interface has to handle all cases. There are only 2 methods that plugins writers have to implement and they most probably look like that : static void gst_my_filter_set_xwindow_id (GstXOverlay *overlay, XID xwindow_id) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); if (my_filter->window) gst_my_filter_destroy_window (my_filter->window); my_filter->window = xwindow_id; } static void gst_my_filter_get_desired_size (GstXOverlay *overlay, guint *width, guint *height) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); *width = my_filter->width; *height = my_filter->height; } static void gst_my_filter_xoverlay_init (GstXOverlayClass *iface) { iface->set_xwindow_id = gst_my_filter_set_xwindow_id; iface->get_desired_size = gst_my_filter_get_desired_size; } You will also need to use the interface methods to fire signals when needed such as in the pad link function where you will know the video geometry and maybe create the window. static MyFilterWindow * gst_my_filter_window_create (GstMyFilter *my_filter, gint width, gint height) { MyFilterWindow *window = g_new (MyFilterWindow, 1); ... gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (my_filter), window->win); } static GstPadLinkReturn gst_my_filter_sink_link (GstPad *pad, const GstCaps *caps) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); gint width, height; gboolean ret; ... ret = gst_structure_get_int (structure, "width", &width); ret &= gst_structure_get_int (structure, "height", &height); if (!ret) return GST_PAD_LINK_REFUSED; if (!my_filter->window) my_filter->window = gst_my_filter_create_window (my_filter, width, height); gst_x_overlay_got_desired_size (GST_X_OVERLAY (my_filter), width, height); ... } Navigation Interface WRITEME Tagging (Metadata and Streaminfo) Tags are pieces of information stored in a stream that are not the content itself, but they rather describe the content. Most media container formats support tagging in one way or another. Ogg uses VorbisComment for this, MP3 uses ID3, AVI and WAV use RIFF's INFO list chunk, etc. GStreamer provides a general way for elements to read tags from the stream and expose this to the user. The tags (at least the metadata) will be part of the stream inside the pipeline. The consequence of this is that transcoding of files from one format to another will automatically preserve tags, as long as the input and output format elements both support tagging. Tags are separated in two categories in GStreamer, even though applications won't notice anything of this. The first are called metadata, the second are called streaminfo. Metadata are tags that describe the non-technical parts of stream content. They can be changed without needing to re-encode the stream completely. Examples are author, title or album. The container format might still need to be re-written for the tags to fit in, though. Streaminfo, on the other hand, are tags that describe the stream contents technically. To change them, the stream needs to be re-encoded. Examples are codec or bitrate. Note that some container formats (like ID3) store various streaminfo tags as metadata in the file container, which means that they can be changed so that they don't match the content in the file anymore. Still, they are called metadata because technically, they can be changed without re-encoding the whole stream, even though that makes them invalid. Files with such metadata tags will have the same tag twice: once as metadata, once as streaminfo. A tag reading element is called TagGetter in GStreamer. A tag writer is called TagSetter. An element supporting both can be used in a tag editor for quick tag changing. Reading Tags from Streams The basic object for tags is a GstTagList . An element that is reading tags from a stream should create an empty taglist and fill this with individual tags. Empty tag lists can be created with gst_tag_list_new (). Then, the element can fill the list using gst_tag_list_add_values () . Note that an element probably reads metadata as strings, but values might not necessarily be strings. Be sure to use gst_value_transform () to make sure that your data is of the right type. After data reading, the application can be notified of the new taglist by calling gst_element_found_tags (). The tags should also be part of the datastream, so they should be pushed over all source pads. The function gst_event_new_tag () creates an event from a taglist. This can be pushed over source pads using gst_pad_push (). Simple elements with only one source pad can combine all these steps all-in-one by using the function gst_element_found_tags_for_pad (). The following example program will parse a file and parse the data as metadata/tags rather than as actual content-data. It will parse each line as name:value, where name is the type of metadata (title, author, ...) and value is the metadata value. The _getline () is the same as the one given in . static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstBuffer *buf; GstTagList *taglist = gst_tag_list_new (); /* get each line and parse as metadata */ while ((buf = gst_my_filter_getline (filter))) { gchar *line = GST_BUFFER_DATA (buf), *colon_pos, *type = NULL;a /* get the position of the ':' and go beyond it */ if (!(colon_pos = strchr (line, ':'))) goto next: /* get the string before that as type of metadata */ type = g_strndup (line, colon_pos - line); /* content is one character beyond the ':' */ colon_pos = &colon_pos[1]; if (*colon_pos == '\0') goto next; /* get the metadata category, it's value type, store it in that * type and add it to the taglist. */ if (gst_tag_exists (type)) { GValue from = { 0 }, to = { 0 }; GType to_type; to_type = gst_tag_get_type (type); g_value_init (&from, G_TYPE_STRING); g_value_set_string (&from, colon_pos); g_value_init (&to, to_type); g_value_transform (&from, &to); g_value_unset (&from); gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND, type, &to, NULL); g_value_unset (&to); } next: g_free (type); gst_buffer_unref (buf); } /* signal metadata */ gst_element_found_tags_for_pad (element, filter->srcpad, 0, taglist); gst_tag_list_free (taglist); /* send EOS */ gst_pad_send_event (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); } We currently assume the core to already know the mimetype (gst_tag_exists ()). You can add new tags to the list of known tags using gst_tag_register (). If you think the tag will be useful in more cases than just your own element, it might be a good idea to add it to gsttag.c instead. That's up to you to decide. If you want to do it in your own element, it's easiest to register the tag in one of your class init functions, preferrably _class_init (). static void gst_my_filter_class_init (GstMyFilterClass *klass) { [..] gst_tag_register ("my_tag_name", GST_TAG_FLAG_META, G_TYPE_STRING, _("my own tag"), _("a tag that is specific to my own element"), NULL); [..] } Writing Tags to Streams Tag writers are the opposite of tag readers. Tag writers only take metadata tags into account, since that's the only type of tags that have to be written into a stream. Tag writers can receive tags in three ways: internal, application and pipeline. Internal tags are tags read by the element itself, which means that the tag writer is - in that case - a tag reader, too. Application tags are tags provided to the element via the TagSetter interface (which is just a layer). Pipeline tags are tags provided to the element from within the pipeline. The element receives such tags via the GST_EVENT_TAG event, which means that tags writers should automatically be event aware. The tag writer is responsible for combining all these three into one list and writing them to the output stream. The example below will receive tags from both application and pipeline, combine them and write them to the output stream. It implements the tag setter so applications can set tags, and retrieves pipeline tags from incoming events. GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_TAG_SETTER, &tag_setter_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GST_FLAG_SET (filter, GST_ELEMENT_EVENT_AWARE); [..] } /* * Write one tag. */ static void gst_my_filter_write_tag (const GstTagList *taglist, const gchar *tagname, gpointer data) { GstMyFilter *filter = GST_MY_FILTER (data); GstBuffer *buffer; guint num_values = gst_tag_list_get_tag_size (list, tag_name), n; const GValue *from; GValue to = { 0 }; g_value_init (&to, G_TYPE_STRING); for (n = 0; n < num_values; n++) { from = gst_tag_list_get_value_index (taglist, tagname, n); g_value_transform (from, &to); buf = gst_buffer_new (); GST_BUFFER_DATA (buf) = g_strdup_printf ("%s:%s", tagname, g_value_get_string (&to)); GST_BUFFER_SIZE (buf) = strlen (GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); } g_value_unset (&to); } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstTagSetter *tagsetter = GST_TAG_SETTER (element); GstData *data; GstEvent *event; gboolean eos = FALSE; GstTagList *taglist = gst_tag_list_new (); while (!eos) { data = gst_pad_pull (filter->sinkpad); /* We're not very much interested in data right now */ if (GST_IS_BUFFER (data)) gst_buffer_unref (GST_BUFFER (data)); event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG: gst_tag_list_insert (taglist, gst_event_tag_get_list (event), GST_TAG_MERGE_PREPEND); gst_event_unref (event); break; case GST_EVENT_EOS: eos = TRUE; gst_event_unref (event); break; default: gst_pad_event_default (filter->sinkpad, event); break; } } /* merge tags with the ones retrieved from the application */ if (gst_tag_setter_get_list (tagsetter)) { gst_tag_list_insert (taglist, gst_tag_setter_get_list (tagsetter), gst_tag_setter_get_merge_mode (tagsetter)); } /* write tags */ gst_tag_list_foreach (taglist, gst_my_filter_write_tag, filter); /* signal EOS */ gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); } Note that normally, elements would not read the full stream before processing tags. Rather, they would read from each sinkpad until they've received data (since tags usually come in before the first data buffer) and process that. Events: Seeking, Navigation and More There are many different event types but only 2 ways they can travel across the pipeline: downstream or upstream. It is very important to understand how both of those methods work because if one element in the pipeline is not handling them correctly the whole event system of the pipeline is broken. We will try to explain here how these methods work and how elements are supposed to implement them. Downstream events Downstream events are received through the sink pad's dataflow. Depending if your element is loop or chain based you will receive events in your loop/chain function as a GstData with gst_pad_pull or directly in the function call arguments. So when receiving dataflow from the sink pad you have to check first if this data chunk is an event. If that's the case you check what kind of event it is to react on relevant ones and then forward others downstream using gst_pad_event_default. Here is an example for both loop and chain based elements. /* Chain based element */ static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); ... if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (pad, event); break; } return; } ... } /* Loop based element */ static void gst_my_filter_loop (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstData *data = NULL; data = gst_pad_pull (filter->sinkpad); if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (filter->sinkpad, event); break; } return; } ... } Upstream events Upstream events are generated by an element somewhere in the pipeline and sent using the gst_pad_send_event function. This function simply realizes the pad and call the default event handler of that pad. The default event handler of pads is gst_pad_event_default , it basically sends the event to the peer pad. So upstream events always arrive on the src pad of your element and are handled by the default event handler except if you override that handler to handle it yourself. There are some specific cases where you have to do that : If you have multiple sink pads in your element. In that case you will have to decide which one of the sink pads you will send the event to. If you need to handle that event locally. For example a navigation event that you will want to convert before sending it upstream. The processing you will do in that event handler does not really matter but there are important rules you have to absolutely respect because one broken element event handler is breaking the whole pipeline event handling. Here they are : Always forward events you won't handle upstream using the default gst_pad_event_default method. If you are generating some new event based on the one you received don't forget to gst_event_unref the event you received. Event handler function are supposed to return TRUE or FALSE indicating if the event has been handled or not. Never simply return TRUE/FALSE in that handler except if you really know that you have handled that event. Here is an example of correct upstream event handling for a plugin that wants to modify navigation events. static gboolean gst_my_filter_handle_src_event (GstPad *pad, GstEvent *event) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: GstEvent *new_event = gst_event_new (GST_EVENT_NAVIGATION);; /* Create a new event based on received one and then send it */ ... gst_event_unref (event); return gst_pad_event_default (pad, new_event); default: /* Falling back to default event handling for that pad */ return gst_pad_event_default (pad, event); } } All Events Together In this chapter follows a list of all defined events that are currently being used, plus how they should be used/interpreted. Events are stored in a GstEvent structure, which is simply a big C union with the types for each event in it. For the next development cycle, we intend to switch events over to GstStructure , but you don't need to worry about that too much for now. In this chapter, we will discuss the following events: End of Stream (EOS) End-of-stream events are sent if the stream that an element sends out is finished. An element receiving this event (from upstream, so it receives it on its sinkpad) will generally forward the event further downstream and set itself to EOS (gst_element_set_eos ()). gst_pad_event_default () takes care of all this, so most elements do not need to support this event. Exceptions are elements that explicitly need to close a resource down on EOS, and N-to-1 elements. Note that the stream itself is not a resource that should be closed down on EOS! Applications might seek back to a point before EOS and set the pipeline to PLAYING again. N-to-1 elements have been discussed previously in . The EOS event (GST_EVENT_EOS) has no properties, and that makes it one of the simplest events in GStreamer. It is created using gst_event_new (GST_EVENT_EOS);. Some elements support the EOS event upstream, too. This signals the element to go into EOS as soon as possible and signal the EOS event forward downstream. This is useful for elements that have no concept of end-of-stream themselves. Examples are TV card sources, audio card sources, etc. This is not (yet) part of the official specifications of this event, though. Flush The flush event is being sent downstream if all buffers and caches in the pipeline should be emptied. Queue elements will empty their internal list of buffers when they receive this event, for example. File sink elements (e.g. filesink) will flush the kernel-to-disk cache (fdatasync () or fflush ()) when they receive this event. Normally, elements receiving this event will simply just forward it, since most filter or filter-like elements don't have an internal cache of data. gst_pad_event_default () does just that, so for most elements, it is enough to forward the event using the default event handler. The flush event is created with gst_event_new (GST_EVENT_FLUSH);. Like the EOS event, it has no properties. Stream Discontinuity A discontinuity event is sent downstream to indicate a discontinuity in the data stream. This can happen because the application used the seek event to seek to a different position in the stream, but it can also be because a real-time network source temporarily lost the connection. After the connection is restored, the data stream will continue, but not at the same point where it got lost. Therefore, a discontinuity event is being sent downstream, too. Depending on the element type, the event can simply be forwarded using gst_pad_event_default (), or it should be parsed and a modified event should be sent on. The last is true for demuxers, which generally have a byte-to-time conversion concept. Their input is usually byte-based, so the incoming event will have an offset in byte units (GST_FORMAT_BYTES), too. Elements downstream, however, expect discontinuity events in time units, so that it can be used to update the pipeline clock. Therefore, demuxers and similar elements should not forward the event, but parse it, free it and send a new discontinuity event (in time units, GST_FORMAT_TIME) further downstream. The discontinuity event is created using the function gst_event_new_discontinuous (). It should set a boolean value which indicates if the discontinuity event is sent because of a new media type (this can happen if - during iteration - a new location was set on a network source or on a file source). then, it should give a list of formats and offsets in that format. The list should be terminated by 0 as format. static void my_filter_some_function (GstMyFilter *filter) { GstEvent *event; [..] event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, 0, GST_FORMAT_TIME, 0, 0); gst_pad_push (filter->srcpad, GST_DATA (event)); [..] } Elements parsing this event can use macros and functions to access the various properties. GST_EVENT_DISCONT_NEW_MEDIA (event) checks the new-media boolean value. gst_event_discont_get_value (event, format, &value) gets the offset of the new stream position in the specified format. If that format was not specified when creating the event, the function returns FALSE. Seek Request Seek events are meant to request a new stream position to elements. This new position can be set in several formats (time, bytes or units [a term indicating frames for video, samples for audio, etc.]). Seeking can be done with respect to the end-of-file, start-of-file or current position, and can happen in both upstream and downstream direction. Elements receiving seek events should, depending on the element type, either forward it (filters, decoders), change the format in which the event is given and forward it (demuxers), handle the event by changing the file pointer in their internal stream resource (file sources) or something else. Seek events are, like discontinuity events, built up using positions in specified formats (time, bytes, units). They are created using the function gst_event_new_seek (), where the first argument is the seek type (indicating with respect to which position [current, end, start] the seek should be applied, and the format in which the new position is given (time, bytes, units), and an offset which is the requested position in the specified format. static void my_filter_some_function (GstMyFilter *filter) { GstEvent *event; [..] /* seek to the start of a resource */ event = gst_event_new_seek (GST_SEEK_SET | GST_FORMAT_BYTES, 0); gst_pad_push (filter->srcpad, GST_DATA (event)); [..] } Elements parsing this event can use macros and functions to access the properties. The seek type can be retrieved using GST_EVENT_SEEK_TYPE (event). This seek type contains both the indicator of with respect to what position the seek should be applied, and the format in which the seek event is given. To get either one of these properties separately, use GST_EVENT_SEEK_FORMAT (event) or GST_EVENT_SEEK_METHOD (event). The requested position is available through GST_EVENT_SEEK_OFFSET (event), and is given in the specified format. Stream Filler The filler event is, as the name says, a filler of the stream which has no special meaning associated with itself. It is used to provide data to downstream elements and should be interpreted as a way of assuring that the normal data flow will continue further downstream. The event is especially intended for real-time MIDI source elements, which only generate data when something changes. MIDI decoders will therefore stall if nothing changes for several seconds, and therefore playback will stop. The filler event is sent downstream to assure the MIDI decoder that nothing changed, so that the normal decoding process will continue and playback will, too. Unless you intend to work with MIDI or other control-language-based data types, you don't need this event. You can mostly simply forward it with gst_pad_event_default (). The stream filler is created using gst_event_new (GST_EVENT_FILLER);. It has no properties. Interruption The interrupt event is generated by queue elements and sent downstream if a timeout occurs on the stream. The scheduler will use this event to get back in its own main loop and schedule other elements. This prevents deadlocks or a stream stall if no data is generated over a part of the pipeline for a considerable amount of time. The scheduler will process this event internally, so any normal elements do not need to generate or handle this event at all. The difference between the filler event and the interrupt event is that the filler event is a real part of a pipeline, so it will reach fellow elements, which can use it to "do nothing else than what I used to do". The interrupt event never reaches fellow elements. The interrupt event (gst_event_new (GST_EVENT_INTERRUPT);) has no properties. Navigation WRITEME Tag (metadata) Tagging events are being sent downstream to indicate the tags as parsed from the stream data. This is currently used to preserve tags during stream transcoding from one format to the other. Tags are discussed extensively in . Most elements will simply forward the event by calling gst_pad_event_default (). The tag event is created using the function gst_event_new_tag (). It requires a filled taglist as argument. Elements parsing this event can use the function gst_event_tag_get_list (event) to acquire the taglist that was parsed. Other Element Types By now, we have looked at pretty much any feature that can be embedded into a GStreamer element. However, we have limited ourselves to the simple model of a filter element. In this chapter, we will look at the specific difficulties and things to keep in mind when writing specific types of elements. We will discuss output elements (sinks), input elements (sources), 1-to-N elements, N-to-1 elements, N-to-N elements, autopluggers and managers. Some of these represent elements that don't actually exist. Rather, they represent a general concept. Writing a Source Source elements are the start of a data streaming pipeline. Source elements have no sink pads and have one or more source pads. We will focus on single-sourcepad elements here, but the concepts apply equally well to multi-sourcepad elements. This chapter will explain the essentials of source elements, which features it should implement and which it doesn't have to, and how source elements will interact with other elements in a pipeline. The get()-function Source elements have the special option of having a _get ()-function rather than a _loop ()- or _chain ()-function. A _get ()-function is called by the scheduler every time the next elements needs data. Apart from corner cases, every source element will want to be _get ()-based. static GstData * gst_my_source_get (GstPad *pad); static void gst_my_source_init (GstMySource *src) { [..] gst_pad_set_get_function (src->srcpad, gst_my_source_get); } static GstData * gst_my_source_get (GstPad *pad) { GstBuffer *buffer; buffer = gst_buffer_new (); GST_BUFFER_DATA (buf) = g_strdup ("hello pipeline!"); GST_BUFFER_SIZE (buf) = strlen (GST_BUFFER_DATA (buf)); /* terminating '/0' */ GST_BUFFER_MAZSIZE (buf) = GST_BUFFER_SIZE (buf) + 1; return GST_DATA (buffer); } Events, querying and converting One of the most important functions of source elements is to implement correct query, convert and event handling functions. Those will continuously describe the current state of the stream. Query functions can be used to get stream properties such as current position and length. This can be used by fellow elements to convert this same value into a different unit, or by appliations to provide information about the length/position of the stream to the user. Conversion functions are used to convert such values from one unit to another. Lastly, events are mostly used to seek to positions inside the stream. Any function is essentially optional, but the element should try to provide as much information as it knows. Note that elements providing an event function should also list their supported events in an _get_event_mask () function. Elements supporting query operations should list the supported operations in a _get_query_types () function. Elements supporting either conversion or query operations should also implement a _get_formats () function. An example source element could, for example, be an element that continuously generates a wave tone at 44,1 kHz, mono, 16-bit. This element will generate 44100 audio samples per second or 88,2 kB/s. This information can be used to implement such functions: static GstFormat * gst_my_source_format_list (GstPad *pad); static GstQueryType * gst_my_source_query_list (GstPad *pad); static gboolean gst_my_source_convert (GstPad *pad, GstFormat from_fmt, gint64 from_val, GstFormat *to_fmt, gint64 *to_val); static gboolean gst_my_source_query (GstPad *pad, GstQueryType type, GstFormat *to_fmt, gint64 *to_val); static void gst_my_source_init (GstMySource *src) { [..] gst_pad_set_convert_function (src->srcpad, gst_my_source_convert); gst_pad_set_formats_function (src->srcpad, gst_my_source_format_list); gst_pad_set_query_function (src->srcpad, gst_my_source_query); gst_pad_set_query_type_function (src->srcpad, gst_my_source_query_list); } /* * This function returns an enumeration of supported GstFormat * types in the query() or convert() functions. See gst/gstformat.h * for a full list. */ static GstFormat * gst_my_source_format_list (GstPad *pad) { static const GstFormat formats[] = { GST_FORMAT_TIME, GST_FORMAT_DEFAULT, /* means "audio samples" */ GST_FORMAT_BYTES, 0 }; return formats; } /* * This function returns an enumeration of the supported query() * operations. Since we generate audio internally, we only provide * an indication of how many samples we've played so far. File sources * or such elements could also provide GST_QUERY_TOTAL for the total * stream length, or other things. See gst/gstquery.h for details. */ static GstQueryType * gst_my_source_query_list (GstPad *pad) { static const GstQueryType query_types[] = { GST_QUERY_POSITION, 0, }; return query_types; } /* * And below are the logical implementations. */ static gboolean gst_my_source_convert (GstPad *pad, GstFormat from_fmt, gint64 from_val, GstFormat *to_fmt, gint64 *to_val) { gboolean res = TRUE; GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (from_fmt) { case GST_FORMAT_TIME: switch (*to_fmt) { case GST_FORMAT_TIME: /* nothing */ break; case GST_FORMAT_BYTES: *to_val = from_val / (GST_SECOND / (44100 * 2)); break; case GST_FORMAT_DEFAULT: *to_val = from_val / (GST_SECOND / 44100); break; default: res = FALSE; break; } break; case GST_FORMAT_BYTES: switch (*to_fmt) { case GST_FORMAT_TIME: *to_val = from_val * (GST_SECOND / (44100 * 2)); break; case GST_FORMAT_BYTES: /* nothing */ break; case GST_FORMAT_DEFAULT: *to_val = from_val / 2; break; default: res = FALSE; break; } break; case GST_FORMAT_DEFAULT: switch (*to_fmt) { case GST_FORMAT_TIME: *to_val = from_val * (GST_SECOND / 44100); break; case GST_FORMAT_BYTES: *to_val = from_val * 2; break; case GST_FORMAT_DEFAULT: /* nothing */ break; default: res = FALSE; break; } break; default: res = FALSE; break; } return res; } static gboolean gst_my_source_query (GstPad *pad, GstQueryType type, GstFormat *to_fmt, gint64 *to_val) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); gboolean res = TRUE; switch (type) { case GST_QUERY_POSITION: res = gst_pad_convert (pad, GST_FORMAT_BYTES, src->total_bytes, to_fmt, to_val); break; default: res = FALSE; break; } return res; } Be sure to increase src->total_bytes after each call to your _get () function. Event handling has already been explained previously in the events chapter. Time, clocking and synchronization The above example does not provide any timing info, but will suffice for elementary data sources such as a file source or network data source element. Things become slightly more complicated, but still very simple, if we create artificial video or audio data sources, such as a video test image source or an artificial audio source (e.g. sinesrc or silence). It will become more complicated if we want the element to be a realtime capture source, such as a video4linux source (for reading video frames from a TV card) or an ALSA source (for reading data from soundcards supported by an ALSA-driver). Here, we will need to make the element aware of timing and clocking. Timestamps can essentially be generated from all the information given above without any difficulty. We could add a very small amount of code to generate perfectly timestamped buffers from our _get ()-function: static void gst_my_source_init (GstMySource *src) { [..] src->total_bytes = 0; } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; GstFormat fmt = GST_FORMAT_TIME; [..] GST_BUFFER_DURATION (buf) = GST_BUFFER_SIZE (buf) * (GST_SECOND / (44100 * 2)); GST_BUFFER_TIMESTAMP (buf) = src->total_bytes * (GST_SECOND / (44100 * 2)); src->total_bytes += GST_BUFFER_SIZE (buf); return GST_DATA (buf); } static GstStateReturn gst_my_source_change_state (GstElement *element) { GstMySource *src = GST_MY_SOURCE (element); switch (GST_STATE_PENDING (element)) { case GT_STATE_PAUSED_TO_READY: src->total_bytes = 0; break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } That wasn't too hard. Now, let's assume real-time elements. Those can either have hardware-timing, in which case we can rely on backends to provide sync for us (in which case you probably want to provide a clock), or we will have to emulate that internally (e.g. to acquire sync in artificial data elements such as sinesrc). Let's first look at the second option (software sync). The first option (hardware sync + providing a clock) does not require any special code with respect to timing, and the clocking section already explained how to provide a clock. enum { ARG_0, [..] ARG_SYNC, [..] }; static void gst_my_source_class_init (GstMySourceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); [..] g_object_class_install_property (object_class, ARG_SYNC, g_param_spec_boolean ("sync", "Sync", "Synchronize to clock", FALSE, G_PARAM_READWRITE)); [..] } static void gst_my_source_init (GstMySource *src) { [..] src->sync = FALSE; } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; [..] if (src->sync) { /* wait on clock */ gst_element_wait (GST_ELEMENT (src), GST_BUFFER_TIMESTAMP (buf)); } return GST_DATA (buf); } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: g_value_set_boolean (value, src->sync); break; [..] } } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, const GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: src->sync = g_value_get_boolean (value); break; [..] } } Most of this is GObject wrapping code. The actual code to do software-sync (in the _get ()-function) is relatively small. Using special memory In some cases, it might be useful to use specially allocated memory (e.g. mmap ()'ed DMA'able memory) in your buffers, and those will require special handling when they are being dereferenced. For this, GStreamer uses the concept of buffer-free functions. Those are special functions pointers that an element can set on buffers that it created itself. The given function will be called when the buffer has been dereferenced, so that the element can clean up or re-use memory internally rather than using the default implementation (which simply calls g_free () on the data pointer). static void gst_my_source_buffer_free (GstBuffer *buf) { GstMySource *src = GST_MY_SOURCE (GST_BUFFER_PRIVATE (buf)); /* do useful things here, like re-queueing the buffer which * makes it available for DMA again. The default handler will * not free this buffer because of the GST_BUFFER_DONTFREE * flag. */ } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; [..] buf = gst_buffer_new (); GST_BUFFER_FREE_DATA_FUNC (buf) = gst_my_source_buffer_free; GST_BUFFER_PRIVATE (buf) = src; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY | GST_BUFFER_DONTFREE); [..] return GST_DATA (buf); } Note that this concept should not be used to decrease the number of calls made to functions such as g_malloc () inside your element. We have better ways of doing that elsewhere (GStreamer core, Glib, Glibc, Linux kernel, etc.). Writing a Sink Sinks are output elements that, opposite to sources, have no source pads and one or more (usually one) sink pad. They can be sound card outputs, disk writers, etc. This chapter will discuss the basic implementation of sink elements. Data processing, events, synchronization and clocks Except for corner cases, sink elements will be _chain ()-based elements. The concept of such elements has been discussed before in detail, so that will be skipped here. What is very important in sink elements, specifically in real-time audio and video sources (such as osssink or ximagesink), is event handling in the _chain ()-function, because most elements rely on EOS-handling of the sink element, and because A/V synchronization can only be perfect if the element takes this into account. How to achieve synchronization between streams depends on whether you're a clock-providing or a clock-receiving element. If you're the clock provider, you can do with time whatever you want. Correct handling would mean that you check whether the end of the previous buffer (if any) and the start of the current buffer are the same. If so, there's no gap between the two and you can continue playing right away. If there is a gap, then you'll need to wait for your clock to reach that time. How to do that depends on the element type. In the case of audio output elements, you would output silence for a while. In the case of video, you would show background color. In case of subtitles, show no subtitles at all. In the case that the provided clock and the received clock are not the same (or in the case where your element provides no clock, which is the same), you simply wait for the clock to reach the timestamp of the current buffer and then you handle the data in it. A simple data handling function would look like this: static void gst_my_sink_chain (GstPad *pad, GstData *data) { GstMySink *sink = GST_MY_SINK (gst_pad_get_parent (pad)); GstBuffer *buf; GstClockTime time; /* only needed if the element is GST_EVENT_AWARE */ if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: [ if your element provides a clock, disable (inactivate) it here ] /* pass-through */ default: /* the default handler handles discontinuities, even if your * element provides a clock! */ gst_pad_event_default (pad, event); break; } return; } buf = GST_BUFFER (data); if (GST_BUFFER_TIME_IS_VALID (buf)) time = GST_BUFFER_TIMESTAMP (buf); else time = sink->expected_next_time; /* Synchronization - the property is only useful in case the * element has the option of not syncing. So it is not useful * for hardware-sync (clock-providing) elements. */ if (sink->sync) { /* This check is only needed if you provide a clock. Else, * you can always execute the 'else' clause. */ if (sink->provided_clock == sink->received_clock) { /* GST_SECOND / 10 is 0,1 sec, it's an arbitrary value. The * casts are needed because else it'll be unsigned and we * won't detect negative values. */ if (llabs ((gint64) sink->expected_next_time - (gint64) time) > (GST_SECOND / 10)) { /* so are we ahead or behind? */ if (time > sink->expected_time) { /* we need to wait a while... In case of audio, output * silence. In case of video, output background color. * In case of subtitles, display nothing. */ [..] } else { /* Drop data. */ [..] } } } else { /* You could do more sophisticated things here, but we'll * keep it simple for the purpose of the example. */ gst_element_wait (GST_ELEMENT (sink), time); } } /* And now handle the data. */ [..] } Special memory Like source elements, sink elements can sometimes provide externally allocated (such as X-provided or DMA'able) memory to elements earlier in the pipeline, and thereby prevent the need for memcpy () for incoming data. We do this by providing a pad-allocate-buffer function. static GstBuffer * gst_my_sink_buffer_allocate (GstPad *pad, guint64 offset, guint size); static void gst_my_sink_init (GstMySink *sink) { [..] gst_pad_set_bufferalloc_function (sink->sinkpad, gst_my_sink_buffer_allocate); } static void gst_my_sink_buffer_free (GstBuffer *buf) { GstMySink *sink = GST_MY_SINK (GST_BUFFER_PRIVATE (buf)); /* Do whatever is needed here. */ [..] } static GstBuffer * gst_my_sink_buffer_allocate (GstPad *pad, guint64 offset, guint size) { GstBuffer *buf = gst_buffer_new (); /* So here it's up to you to wrap your private buffers and * return that. */ GST_BUFFER_FREE_DATA_FUNC (buf) = gst_my_sink_buffer_free; GST_BUFFER_PRIVATE (buf) = sink; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE); [..] return buf; } Writing a 1-to-N Element, Demuxer or Parser 1-to-N elements don't have much special needs or requirements that haven't been discussed already. The most important thing to take care of in 1-to-N elements (things like tee-elements or so) is to use proper buffer refcounting and caps negotiation. If those two are taken care of (see the tee element if you need example code), there's little that can go wrong. Demuxers are the 1-to-N elements that need very special care, though. They are responsible for timestamping raw, unparsed data into elementary video or audio streams, and there are many things that you can optimize or do wrong. Here, several culprits will be mentioned and common solutions will be offered. Parsers are demuxers with only one source pad. Also, they only cut the stream into buffers, they don't touch the data otherwise. Demuxer Caps Negotiation Demuxers will usually contain several elementary streams, and each of those streams' properties will be defined in a stream header at the start of the file (or, rather, stream) that you're parsing. Since those are fixed and there is no possibility to negotiate stream properties with elements earlier in the pipeline, you should always use explicit caps on demuxer source pads. This prevents a whole lot of caps negotiation or re-negotiation errors. Data processing and downstream events Data parsing, pulling this into subbuffers and sending that to the source pads of the elementary streams is the one single most important task of demuxers and parsers. Usually, an element will have a _loop () function using the bytestream object to read data. Try to have a single point of data reading from the bytestream object. In this single point, do proper event handling (in case there is any) and proper error handling in case that's needed. Make your element as fault-tolerant as possible, but do not go further than possible. Parsing versus interpreting One particular convention that GStreamer demuxers follow is that of separation of parsing and interpreting. The reason for this is maintainability, clarity and code reuse. An easy example of this is something like RIFF, which has a chunk header of 4 bytes, then a length indicator of 4 bytes and then the actual data. We write special functions to read one chunk, to peek a chunk ID and all those; that's the parsing part of the demuxer. Then, somewhere else, we like to write the main data processing function, which calls this parse function, reads one chunk and then does with the data whatever it needs to do. Some example code for RIFF-reading to illustrate the above two points: static gboolean gst_my_demuxer_peek (GstMyDemuxer *demux, guint32 *id, guint32 *size) { guint8 *data; while (gst_bytestream_peek_bytes (demux->bs, &data, 4) != 4) { guint32 remaining; GstEvent *event; gst_bytestream_get_status (demux->bs, &remaining, &event); if (event) { GstEventType type = GST_EVENT_TYPE (event); /* or maybe custom event handling, up to you - we lose reference! */ gst_pad_event_default (demux->sinkpad, event); if (type == GST_EVENT_EOS) return FALSE; } else { GST_ELEMENT_ERROR (demux, STREAM, READ, (NULL), (NULL)); return FALSE; } } *id = GUINT32_FROM_LE (((guint32 *) data)[0]); *size = GUINT32_FROM_LE (((guint32 *) data)[0]); return TRUE; } static void gst_my_demuxer_loop (GstElement *element) { GstMyDemuxer *demux = GST_MY_DEMUXER (element); guint32 id, size; if (!gst_my_demuxer_peek (demux, &id, &size)) return; switch (id) { [.. normal chunk handling ..] } } Reason for this is that event handling is now centralized in one place and the _loop () function is a lot cleaner and more readable. Those are common code practices, but since the mistake of not using such common code practices has been made too often, we explicitely mention this here. Simple seeking and indexes Sources will generally receive a seek event in the exact supported format by the element. Demuxers, however, can not seek in themselves directly, but need to convert from one unit (e.g. time) to the other (e.g. bytes) and send a new event to its sink pad. Given this, the _convert ()-function (or, more general: unit conversion) is the most important function in a demuxer. Some demuxers (AVI, Matroska) and parsers will keep an index of all chunks in a stream, firstly to improve seeking precision and secondly so they won't lose sync. Some other demuxers will seek the stream directly without index (e.g. MPEG, Ogg) - usually based on something like a cumulative bitrate - and then find the closest next chunk from their new position. The best choice depends on the format. Note that it is recommended for demuxers to implement event, conversion and query handling functions (using time units or so), in addition to the ones (usually in byte units) provided by the pipeline source element. Writing a N-to-1 Element or Muxer N-to-1 elements have been previously mentioned and discussed in both and in . The main noteworthy thing about N-to-1 elements is that they should always, without any single exception, be _loop ()-based. Apart from that, there is not much general that you need to know. We will discuss one special type of N-to-1 elements here, these being muxers. The first two of these sections apply to N-to-1 elements in general, though. The Data Loop Function As previously mentioned in , N-to-1 elements generally try to have one buffer from each sink pad and then handle the one with the earliest timestamp. There's some exceptions to this rule, we will come to those later. This only works if all streams actually continuously provide input. There might be cases where this is not true, for example subtitles (there might be no subtitle for a while), overlay images and so forth. For this purpose, there is a _select () function in GStreamer. It checks whether input is available on a (list of) pad(s). In this way, you can skip over the pads that are 'non- continuous'. /* Pad selection is currently broken, FIXME some day */ Events in the Loop Function N-to-1 elements using a cache will sometimes receive events, and it is often unclear how to handle those. For example, how do you seek to a frame in an output file (and what's the point of it anyway)? So, do discontinuity or seek events make sense, and should you use them? Discontinuities and flushes Don't do anything. They specify a discontinuity in the output, and you should continue to playback as you would otherwise. You generally do not need to put a discontinuity in the output stream in muxers; you would have to manually start adapting timestamps of output frames (if appliccable) to match the previous timescale, though. Note that the output data stream should be continuous. For other types of N-to-1-elements, it is generally fine to forward the discontinuity once it has been received from all pads. This depends on the specific element. Seeks Depends on the element. Muxers would generally not implement this, because the concept of seeking in an output stream at frame level is not very useful. Seeking at byte level can be useful, but that is more generally done by muxers on sink elements. End-of-Stream Speaks for itself. Negotiation Most container formats will have a fair amount of issues with changing content on an elementary stream. Therefore, you should not allow caps to be changed once you've started using data from them. The easiest way to achieve this is by using explicit caps, which have been explained before. However, we're going to use them in a slightly different way then what you're used to, having the core do all the work for us. The idea is that, as long as the stream/file headers have not been written yet and no data has been processed yet, a stream is allowed to renegotiate. After that point, the caps should be fixed, because we can only use a stream once. Caps may then only change within an allowed range (think MPEG, where changes in FPS are allowed), or sometimes not at all (such as AVI audio). In order to do that, we will, after data retrieval and header writing, set an explicit caps on each sink pad, that is the minimal caps describing the properties of the format that may not change. As an example, for MPEG audio inside an MPEG system stream, this would mean a wide caps of audio/mpeg with mpegversion=1 and layer=[1,2]. For the same audio type in MPEG, though, the samplerate, bitrate, layer and number of channels would become static, too. Since the (request) pads will be removed when the stream ends, the static caps will cease to exist too, then. While the explicit caps exist, the _link ()- function will not be called, since the core will do all necessary checks for us. Note that the property of using explicit caps should be added along with the actual explicit caps, not any earlier. Below here follows the simple example of an AVI muxer's audio caps negotiation. The _link ()-function is fairly normal, but the -Loop ()-function does some of the tricks mentioned above. There is no _getcaps ()- function since the pad template contains all that information already (not shown). static GstPadLinkReturn gst_avi_mux_audio_link (GstPad *pad, const GstCaps *caps) { GstAviMux *mux = GST_AVI_MUX (gst_pad_get_parent (pad)); GstStructure *str = gst_caps_get_structure (caps, 0); const gchar *mime = gst_structure_get_name (str); if (!strcmp (str, "audio/mpeg")) { /* get version, make sure it's 1, get layer, make sure it's 1-3, * then create the 2-byte audio tag (0x0055) and fill an audio * stream structure (strh/strf). */ [..] return GST_PAD_LINK_OK; } else if !strcmp (str, "audio/x-raw-int")) { /* See above, but now with the raw audio tag (0x0001). */ [..] return GST_PAD_LINK_OK; } else [..] [..] } static void gst_avi_mux_loop (GstElement *element) { GstAviMux *mux = GST_AVI_MUX (element); [..] /* As we get here, we should have written the header if we hadn't done * that before yet, and we're supposed to have an internal buffer from * each pad, also from the audio one. So here, we check again whether * this is the first run and if so, we set static caps. */ if (mux->first_cycle) { const GList *padlist = gst_element_get_pad_list (element); GList *item; for (item = padlist; item != NULL; item = item->next) { GstPad *pad = item->data; GstCaps *caps; if (!GST_PAD_IS_SINK (pad)) continue; /* set static caps here */ if (!strncmp (gst_pad_get_name (pad), "audio_", 6)) { /* the strf is the struct you filled in the _link () function. */ switch (strf->format) { case 0x0055: /* mp3 */ caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, "bitrate", G_TYPE_INT, strf->av_bps, "rate", G_TYPE_INT, strf->rate, "channels", G_TYPE_INT, strf->channels, NULL); break; case 0x0001: /* pcm */ caps = gst_caps_new_simple ("audio/x-raw-int", [..]); break; [..] } } else if (!strncmp (gst_pad_get_name (pad), "video_", 6)) { [..] } else { g_warning ("oi!"); continue; } /* set static caps */ gst_pad_use_explicit_caps (pad); gst_pad_set_explicit_caps (pad, caps); } } [..] /* Next runs will never be the first again. */ mux->first_cycle = FALSE; } Note that there are other ways to achieve that, which might be useful for more complex cases. This will do for the simple cases, though. This method is provided to simplify negotiation and renegotiation in muxers, it is not a complete solution, nor is it a pretty one. Markup vs. data processing As we noted on demuxers before, we love common programming paradigms such as clean, lean and mean code. To achieve that in muxers, it's generally a good idea to separate the actual data stream markup from the data processing. To illustrate, here's how AVI muxers should write out RIFF tag chunks: static void gst_avi_mux_write_chunk (GstAviMux *mux, guint32 id, GstBuffer *data) { GstBuffer *hdr; hdr = gst_buffer_new_and_alloc (8); ((guint32 *) GST_BUFFER_DATA (buf))[0] = GUINT32_TO_LE (id); ((guint32 *) GST_BUFFER_DATA (buf))[1] = GUINT32_TO_LE (GST_BUFFER_SIZE (data)); gst_pad_push (mux->srcpad, hdr); gst_pad_push (mux->srcpad, data); } static void gst_avi_mux_loop (GstElement *element) { GstAviMux *mux = GST_AVI_MUX (element); GstBuffer *buf; [..] buf = gst_pad_pull (mux->sinkpad[0]); [..] gst_avi_mux_write_chunk (GST_MAKE_FOURCC ('0','0','d','b'), buf); } In general, try to program clean code, that should cover pretty much everything. Writing a N-to-N element FIXME: write. Writing an Autoplugger FIXME: write. Writing a Manager Managers are elements that add a function or unify the function of another (series of) element(s). Managers are generally a GstBin with one or more ghostpads. Inside them is/are the actual element(s) that matters. There is several cases where this is useful. For example: To add support for private events with custom event handling to another element. To add support for custom pad _query () or _convert () handling to another element. To add custom data handling before or after another element's data handler function (generally its _chain () function). This chapter will explain the setup of managers. As a specific example, we will try to add EOS event support to source elements. This can be used to finish capturing an audio stream to a file. Source elements normally don't do any EOS handling at all, so a manager is perfect to extend those element's functionalities. Specifically, this element will contain two child elements: the actual source element and a helper element that implement an event handler on its source pad. This event handler will respond to EOS events by storing them internally and returning the event (rather than data) on the next call to the _get () function. After that, it will go into EOS and set the parent (and thereby the contained source element) to EOS as well. Other events will be forwarded to the source element, which will handle them as usual. .. Appendices This chapter contains things that don't belong anywhere else. Things to check when writing an element This chapter contains a fairly random selection of things to take care of when writing an element. It's up to you how far you're going to stick to those guidelines. However, keep in mind that when you're writing an element and hope for it to be included in the mainstream GStreamer distribution, it has to meet those requirements. As far as possible, we will try to explain why those requirements are set. About states Make sure the state of an element gets reset when going to NULL. Ideally, this should set all object properties to their original state. This function should also be called from _init. Make sure an element forgets everything about its contained stream when going from PAUSED to READY. In READY, all stream states are reset. An element that goes from PAUSED to READY and back to PAUSED should start reading the stream from he start again. People that use gst-launch for testing have the tendency to not care about cleaning up. This is wrong. An element should be tested using various applications, where testing not only means to make sure it doesn't crash, but also to test for memory leaks using tools such as valgrind. Elements have to be reusable in a pipeline after having been reset. Debugging Elements should never use their standard output for debugging (using functions such as printf () or g_print ()). Instead, elements should use the logging functions provided by GStreamer, named GST_DEBUG (), GST_LOG (), GST_INFO (), GST_WARNING () and GST_ERROR (). The various logging levels can be turned on and off at runtime and can thus be used for solving issues as they turn up. Instead of GST_LOG () (as an example), you can also use GST_LOG_OBJECT () to print the object that you're logging output for. Ideally, elements should use their own debugging category. Most elements use the following code to do that: GST_DEBUG_CATEGORY_STATIC (myelement_debug); #define GST_CAT_DEFAULT myelement_debug [..] static void gst_myelement_class_init (GstMyelementClass *klass) { [..] GST_DEBUG_CATEGORY_INIT (myelement_debug, "myelement", 0, "My own element"); } At runtime, you can turn on debugging using the commandline option --gst-debug=myelement:5. Querying, events and the like All elements to which it applies (sources, sinks, demuxers) should implement query functions on their pads, so that applications and neighbour elements can request the current position, the stream length (if known) and so on. All elements that are event-aware (their GST_ELEMENT_EVENT_AWARE flag is set) should implement event handling for all events, either specifically or using gst_pad_event_default (). Elements that you should handle specifically are the interrupt event, in order to properly bail out as soon as possible if state is changed. Events may never be dropped unless specifically intended. Loop-based elements should always implement event handling, in order to prevent hangs (infinite loop) on state changes. Testing your element gst-launch is not a good tool to show that your element is finished. Applications such as Rhythmbox and Totem (for GNOME) or AmaroK (for KDE) are. gst-launch will not test various things such as proper clean-up on reset, interrupt event handling, querying and so on. Parsers and demuxers should make sure to check their input. Input cannot be trusted. Prevent possible buffer overflows and the like. Feel free to error out on unrecoverable stream errors. Test your demuxer using stream corruption elements such as breakmydata (included in gst-plugins). It will randomly insert, delete and modify bytes in a stream, and is therefore a good test for robustness. If your element crashes when adding this element, your element needs fixing. If it errors out properly, it's good enough. Ideally, it'd just continue to work and forward data as much as possible. Demuxers should not assume that seeking works. Be prepared to work with unseekable input streams (e.g. network sources) as well. Sources and sinks should be prepared to be assigned another clock then the one they expose themselves. Always use the provided clock for synchronization, else you'll get A/V sync issues. GStreamer licensingHow to license the code you write for GStreamer GStreamer is a plugin-based framework licensed under the LGPL. The reason for this choice in licensing is to ensure that everyone can use GStreamer to build applications using licenses of their choice. To keep this policy viable, the GStreamer community has made a few licensing rules for code to be included in GStreamer's core or GStreamer's official modules, like our plugin packages. We require that all code going into our core package is LGPL. For the plugin code, we require the use of the LGPL for all plugins written from scratch or linking to external libraries. The only exception to this is when plugins contain older code under more liberal licenses (like the MPL or BSD). They can use those licenses instead and will still be considered for inclusion. We do not accept GPL code to be added to our plugins module, but we do accept LGPL-licensed plugins using an external GPL library. The reason for demanding plugins be licensed under the LGPL, even when using a GPL library, is that other developers might want to use the plugin code as a template for plugins linking to non-GPL libraries. We also plan on splitting out the plugins using GPL libraries into a separate package eventually and implement a system which makes sure an application will not be able to access these plugins unless it uses some special code to do so. The point of this is not to block GPL-licensed plugins from being used and developed, but to make sure people are not unintentionally violating the GPL license of said plugins. This advisory is part of a bigger advisory with a FAQ which you can find on the GStreamer website Done. Copying .css files: base.css make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' Making all in gst make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/gst' *** Scanning header files *** if grep -l '^..*$' ./gstreamer.types > /dev/null; \ then \ if test x"." != x. ; then \ cp ./gstreamer.types . ; \ chmod u+w gstreamer.types ; \ fi ; \ CC="/bin/sh ../../libtool --mode=compile gcc" LD="/bin/sh ../../libtool --mode=link gcc" \ CFLAGS="-pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -I../.." LDFLAGS="../../gst/libgstreamer-0.8.la -lpopt " \ gtkdoc-scangobj --nogtkinit --type-init-func="gst_init(NULL,NULL)" \ --module=gstreamer ; \ else \ cd . ; \ for i in gstreamer.args gstreamer.hierarchy gstreamer.interfaces gstreamer.prerequisites .libs/gstreamer-scan.o gstreamer.signals ; do \ test -f $i || touch $i ; \ done \ fi mkdir .libs gcc -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -I../.. -c gstreamer-scan.c -fPIC -DPIC -o .libs/gstreamer-scan.o gcc -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -I../.. -c gstreamer-scan.c -o gstreamer-scan.o >/dev/null 2>&1 gcc -o .libs/gstreamer-scan .libs/gstreamer-scan.o ../../gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lm -lpopt creating gstreamer-scan if test "x../.." != "x../.."; \ then \ export BUILT_OPTIONS="--source-dir=../../gst"; \ fi; \ gtkdoc-scan \ --deprecated-guards="GST_DISABLE_DEPRECATED" \ --module=gstreamer \ --source-dir=../../gst \ $BUILT_OPTIONS \ --ignore-headers="gettext.h gst-i18n-lib.h gst-i18n-app.h gst_private.h gstatomic_impl.h gstdata_private.h gstarch.h cothreads.h cothreads_compat.h gthread-cothreads.h faircothreads.h types.h grammar.tab.h gstmarshal.h gstaggregator.h gstbufferstore.h gstfakesink.h gstfakesrc.h gstfdsink.h gstfdsrc.h gstfilesink.h gstfilesrc.h gstidentity.h gstlibxmlregistry.h gstmd5sink.h gstmultifilesrc.h gstmultifdsink.h gstpipefilter.h gstshaper.h gststatistics.h gsttee.h gsttypefindelement.h gstspider.h gstspideridentity.h gstsearchfuncs.h gstxmlregistry.h" touch scan-build.stamp *** Rebuilding template files *** if test x"." != x. ; then \ cp ./gstreamer-sections.txt . ; \ touch gstreamer-decl.txt ; \ fi gtkdoc-mktmpl --module=gstreamer | tee tmpl-build.log ============================================================================= WARNING: 1 unused declarations. These can be found in gstreamer-unused.txt. They should be added to gstreamer-sections.txt in the appropriate place. ============================================================================= GstPoptOption rm -f tmpl-build.log touch tmpl-build.stamp *** Building XML *** gtkdoc-mkdb --module=gstreamer --source-dir=../../gst --main-sgml-file=./gstreamer-docs.sgml --output-format=xml --sgml-mode --ignore-files=parse | tee sgml-build.log Use of uninitialized value in split at /usr/bin/gtkdoc-mkdb line 608. 82% symbol docs coverage (1098 symbols documented, 19 symbols incomplete, 242 not documented) See gstreamer-undocumented.txt for a list of missing docs. The doc coverage percentage doesn't include intro sections. rm sgml-build.log touch sgml-build.stamp *** Building HTML *** if test -d html; then rm -rf html; fi mkdir html cp ./gstreamer-docs.sgml html cp -pr xml html cp ../version.entities html cd html && gtkdoc-mkhtml gstreamer gstreamer-docs.sgml Computing chunks... Writing gstreamer-Gst.html for refentry(gstreamer-Gst) Writing GstBin.html for refentry(GstBin) Writing gstreamer-GstBuffer.html for refentry(gstreamer-GstBuffer) Writing gstreamer-GstCaps.html for refentry(gstreamer-GstCaps) Writing GstClock.html for refentry(GstClock) Writing gstreamer-gstconfig.html for refentry(gstreamer-gstconfig) Writing gstreamer-GstCPU.html for refentry(gstreamer-GstCPU) Writing gstreamer-GstData.html for refentry(gstreamer-GstData) Writing GstElement.html for refentry(GstElement) Writing gstreamer-GstElementDetails.html for refentry(gstreamer-GstElementDetails) Writing GstElementFactory.html for refentry(GstElementFactory) Writing gstreamer-GstGError.html for refentry(gstreamer-GstGError) Writing gstreamer-GstEvent.html for refentry(gstreamer-GstEvent) Writing gstreamer-GstFilter.html for refentry(gstreamer-GstFilter) Writing gstreamer-GstFormat.html for refentry(gstreamer-GstFormat) Writing GstGhostPad.html for refentry(GstGhostPad) Writing GstImplementsInterface.html for refentry(GstImplementsInterface) Writing GstIndex.html for refentry(GstIndex) Writing GstIndexFactory.html for refentry(GstIndexFactory) Writing gstreamer-GstInfo.html for refentry(gstreamer-GstInfo) Writing GstObject.html for refentry(GstObject) Writing GstPad.html for refentry(GstPad) Writing GstPadTemplate.html for refentry(GstPadTemplate) Writing gstreamer-GstParse.html for refentry(gstreamer-GstParse) Writing GstPipeline.html for refentry(GstPipeline) Writing gstreamer-GstPlugin.html for refentry(gstreamer-GstPlugin) Writing GstPluginFeature.html for refentry(GstPluginFeature) Writing gstreamer-GstProbe.html for refentry(gstreamer-GstProbe) Writing gstreamer-GstQuery.html for refentry(gstreamer-GstQuery) Writing GstQueue.html for refentry(GstQueue) Writing GstRealPad.html for refentry(GstRealPad) Writing GstRegistry.html for refentry(GstRegistry) Writing gstreamer-GstRegistryPool.html for refentry(gstreamer-GstRegistryPool) Writing GstScheduler.html for refentry(GstScheduler) Writing GstSchedulerFactory.html for refentry(GstSchedulerFactory) Writing gstreamer-GstStructure.html for refentry(gstreamer-GstStructure) Writing gstreamer-GstSystemClock.html for refentry(gstreamer-GstSystemClock) Writing gstreamer-GstTagList.html for refentry(gstreamer-GstTagList) Writing GstTagSetter.html for refentry(GstTagSetter) Writing GstThread.html for refentry(GstThread) Writing gstreamer-GstTypeFind.html for refentry(gstreamer-GstTypeFind) Writing GstTypeFindFactory.html for refentry(GstTypeFindFactory) Writing gstreamer-GstTypes.html for refentry(gstreamer-GstTypes) Writing gstreamer-GstUriHandler.html for refentry(gstreamer-GstUriHandler) Writing gstreamer-GstUriType.html for refentry(gstreamer-GstUriType) Writing gstreamer-GstUtils.html for refentry(gstreamer-GstUtils) Writing gstreamer-GstValue.html for refentry(gstreamer-GstValue) Writing gstreamer-GstVersion.html for refentry(gstreamer-GstVersion) Writing GstXML.html for refentry(GstXML) Writing gstreamer.html for chapter(gstreamer) Writing gstreamer-GstAtomic.html for refentry(gstreamer-GstAtomic) Writing gstreamer-GstMacros.html for refentry(gstreamer-GstMacros) Writing gstreamer-GstMemChunk.html for refentry(gstreamer-GstMemChunk) Writing gstreamer-support.html for chapter(gstreamer-support) Writing gstreamer-GstCompat.html for refentry(gstreamer-GstCompat) Writing gstreamer-compat.html for chapter(gstreamer-compat) Writing gstreamer-hierarchy.html for chapter(gstreamer-hierarchy) Writing api-index.html for index(api-index) Writing index.html for book(index) Writing index.sgml for book(index) Writing gstreamer.devhelp for book(index) rm -f html/gstreamer-docs.sgml rm -rf html/xml rm -f html/version.entities test "x" = "x" || for i in "" ; do \ if test "$i" != ""; then cp ./$i html ; fi; done -- Fixing Crossreferences LANG=C && gtkdoc-fixxref --module-dir=html --html-dir=/var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html touch html-build.stamp make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/gst' Making all in libs make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/libs' *** Scanning header files *** if grep -l '^..*$' ./gstreamer-libs.types > /dev/null; \ then \ if test x"." != x. ; then \ cp ./gstreamer-libs.types . ; \ chmod u+w gstreamer-libs.types ; \ fi ; \ CC="/bin/sh ../../libtool --mode=compile gcc" LD="/bin/sh ../../libtool --mode=link gcc" \ CFLAGS="-pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -I../.." LDFLAGS="../../gst/libgstreamer-0.8.la -lpopt ../../libs/gst/control/libgstcontrol-0.8.la" \ gtkdoc-scangobj --nogtkinit --type-init-func="gst_init(NULL,NULL)" \ --module=gstreamer-libs ; \ else \ cd . ; \ for i in gstreamer-libs.args gstreamer-libs.hierarchy gstreamer-libs.interfaces gstreamer-libs.prerequisites .libs/gstreamer-libs-scan.o gstreamer-libs.signals ; do \ test -f $i || touch $i ; \ done \ fi mkdir .libs gcc -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -I../.. -c gstreamer-libs-scan.c -fPIC -DPIC -o .libs/gstreamer-libs-scan.o gcc -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-common -g -Wall -DGST_DISABLE_DEPRECATED -I../../libs -I../.. -I../.. -c gstreamer-libs-scan.c -o gstreamer-libs-scan.o >/dev/null 2>&1 gcc -o .libs/gstreamer-libs-scan .libs/gstreamer-libs-scan.o ../../gst/.libs/libgstreamer-0.8.so ../../libs/gst/control/.libs/libgstcontrol-0.8.so /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/.libs/libgstreamer-0.8.so -lxml2 -lz -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lpopt -lm creating gstreamer-libs-scan if test "x../.." != "x../.."; \ then \ export BUILT_OPTIONS="--source-dir=../../libs/gst"; \ fi; \ gtkdoc-scan \ --deprecated-guards="GST_DISABLE_DEPRECATED" \ --module=gstreamer-libs \ --source-dir=../../libs/gst \ $BUILT_OPTIONS \ --ignore-headers="gstgetbits_inl.h dp-private.h" touch scan-build.stamp *** Rebuilding template files *** if test x"." != x. ; then \ cp ./gstreamer-libs-decl.txt . ; \ cp ./gstreamer-libs-sections.txt . ; \ fi gtkdoc-mktmpl --module=gstreamer-libs ============================================================================= WARNING: 112 unused declarations. These can be found in gstreamer-libs-unused.txt. They should be added to gstreamer-libs-sections.txt in the appropriate place. ============================================================================= touch tmpl-build.stamp *** Building XML *** gtkdoc-mkdb --module=gstreamer-libs --source-dir=../../libs/gst --main-sgml-file=./gstreamer-libs-docs.sgml --output-format=xml --sgml-mode --ignore-files=trio | tee sgml-build.log Use of uninitialized value in split at /usr/bin/gtkdoc-mkdb line 608. 45% symbol docs coverage (76 symbols documented, 0 symbols incomplete, 94 not documented) See gstreamer-libs-undocumented.txt for a list of missing docs. The doc coverage percentage doesn't include intro sections. rm sgml-build.log touch sgml-build.stamp *** Building HTML *** if test -d html; then rm -rf html; fi mkdir html cp -pr xml html cp ../version.entities html cd html && gtkdoc-mkhtml gstreamer-libs gstreamer-libs-docs.sgml Computing chunks... Writing gstreamer-libs-gstadapter.html for refentry(gstreamer-libs-gstadapter) Writing gstreamer-libs-gstbytestream.html for refentry(gstreamer-libs-gstbytestream) Writing gstreamer-libs-gstdataprotocol.html for refentry(gstreamer-libs-gstdataprotocol) Writing gstreamer-libs-gstgetbits.html for refentry(gstreamer-libs-gstgetbits) Writing gstreamer-libs-GstControl.html for refentry(gstreamer-libs-GstControl) Writing GstDParamManager.html for refentry(GstDParamManager) Writing GstDParam.html for refentry(GstDParam) Writing GstDParamSmooth.html for refentry(GstDParamSmooth) Writing GstDParamLinInterp.html for refentry(GstDParamLinInterp) Writing GstUnitConvert.html for refentry(GstUnitConvert) Writing gstreamer-control.html for chapter(gstreamer-control) Writing gstreamer-libs.html for part(gstreamer-libs) Writing gstreamer-libs-hierarchy.html for part(gstreamer-libs-hierarchy) Writing api-index.html for index(api-index) Writing index.html for book(index) Writing index.sgml for book(index) Writing gstreamer-libs.devhelp for book(index) rm -f html/gstreamer-libs-docs.sgml rm -rf html/xml rm -f html/version.entities test "x" = "x" || for i in "" ; do \ if test "$i" != ""; then cp ./$i html ; fi; done -- Fixing Crossreferences LANG=C && gtkdoc-fixxref --module-dir=html --html-dir=/var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html --extra-dir=../gst/html touch html-build.stamp make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/libs' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[3]: Nothing to be done for `all-am'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' cp ./gst-element-check.m4 gst-element-check-0.8.m4 make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.27363 + umask 022 + cd /usr/src/rpm/BUILD + cd gstreamer-0.8.11 + LANG=C + export LANG + unset DISPLAY + rm -rf /var/tmp/gstreamer08-0.8.11-root ++ pwd + /usr/bin/make prefix=/var/tmp/gstreamer08-0.8.11-root/usr exec_prefix=/var/tmp/gstreamer08-0.8.11-root/usr bindir=/var/tmp/gstreamer08-0.8.11-root/usr/bin sbindir=/var/tmp/gstreamer08-0.8.11-root/usr/sbin sysconfdir=/var/tmp/gstreamer08-0.8.11-root/etc datadir=/var/tmp/gstreamer08-0.8.11-root/usr/share includedir=/var/tmp/gstreamer08-0.8.11-root/usr/include libdir=/var/tmp/gstreamer08-0.8.11-root/usr/lib libexecdir=/var/tmp/gstreamer08-0.8.11-root/usr/libexec localstatedir=/var/tmp/gstreamer08-0.8.11-root/var sharedstatedir=/var/tmp/gstreamer08-0.8.11-root/usr/com mandir=/var/tmp/gstreamer08-0.8.11-root/usr/share/man infodir=/var/tmp/gstreamer08-0.8.11-root/usr/share/info install docdir=/usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc Making install in include make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/include' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/include' make[2]: Nothing to be done for `install-exec-am'. make[2]: Nothing to be done for `install-data-am'. make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/include' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/include' Making install in gst make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' /usr/bin/make install-recursive make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' Making install in parse make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/parse' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/parse' make[4]: Nothing to be done for `install-exec-am'. make[4]: Nothing to be done for `install-data-am'. make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/parse' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/parse' Making install in registries make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/registries' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/registries' make[4]: Nothing to be done for `install-exec-am'. make[4]: Nothing to be done for `install-data-am'. make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/registries' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/registries' Making install in . make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib" /bin/sh ../libtool --mode=install /usr/bin/install -c 'libgstreamer-0.8.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.la' /usr/bin/install -c .libs/libgstreamer-0.8.so.1.4.0 /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.so.1.4.0 (cd /var/tmp/gstreamer08-0.8.11-root/usr/lib && { ln -s -f libgstreamer-0.8.so.1.4.0 libgstreamer-0.8.so.1 || { rm -f libgstreamer-0.8.so.1 && ln -s libgstreamer-0.8.so.1.4.0 libgstreamer-0.8.so.1; }; }) (cd /var/tmp/gstreamer08-0.8.11-root/usr/lib && { ln -s -f libgstreamer-0.8.so.1.4.0 libgstreamer-0.8.so || { rm -f libgstreamer-0.8.so && ln -s libgstreamer-0.8.so.1.4.0 libgstreamer-0.8.so; }; }) /usr/bin/install -c .libs/libgstreamer-0.8.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.la /usr/bin/install -c .libs/libgstreamer-0.8.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.a libtool: install: warning: remember to run `libtool --finish /usr/lib' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst" /usr/bin/install -c -m 644 'gst.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gst.h' /usr/bin/install -c -m 644 'gstatomic.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstatomic.h' /usr/bin/install -c -m 644 'gstobject.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstobject.h' /usr/bin/install -c -m 644 'gstbin.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstbin.h' /usr/bin/install -c -m 644 'gstbuffer.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstbuffer.h' /usr/bin/install -c -m 644 'gstcaps.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstcaps.h' /usr/bin/install -c -m 644 'gstclock.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstclock.h' /usr/bin/install -c -m 644 'gstcompat.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstcompat.h' /usr/bin/install -c -m 644 'gstcpu.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstcpu.h' /usr/bin/install -c -m 644 'gstdata.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstdata.h' /usr/bin/install -c -m 644 'gstelement.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstelement.h' /usr/bin/install -c -m 644 'gsterror.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsterror.h' /usr/bin/install -c -m 644 'gstevent.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstevent.h' /usr/bin/install -c -m 644 'gstfilter.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstfilter.h' /usr/bin/install -c -m 644 'gstformat.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstformat.h' /usr/bin/install -c -m 644 'gstindex.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstindex.h' /usr/bin/install -c -m 644 'gstinfo.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstinfo.h' /usr/bin/install -c -m 644 'gstinterface.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstinterface.h' /usr/bin/install -c -m 644 'gstmacros.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstmacros.h' /usr/bin/install -c -m 644 'gstmemchunk.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstmemchunk.h' /usr/bin/install -c -m 644 'gstpad.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstpad.h' /usr/bin/install -c -m 644 'gstchildproxy.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstchildproxy.h' /usr/bin/install -c -m 644 'gstpipeline.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstpipeline.h' /usr/bin/install -c -m 644 'gstplugin.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstplugin.h' /usr/bin/install -c -m 644 'gstpluginfeature.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstpluginfeature.h' /usr/bin/install -c -m 644 'gstprobe.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstprobe.h' /usr/bin/install -c -m 644 'gstqueue.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstqueue.h' /usr/bin/install -c -m 644 'gstquery.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstquery.h' /usr/bin/install -c -m 644 'gstscheduler.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstscheduler.h' /usr/bin/install -c -m 644 'gststructure.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gststructure.h' /usr/bin/install -c -m 644 'gstsystemclock.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstsystemclock.h' /usr/bin/install -c -m 644 'gsttag.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsttag.h' /usr/bin/install -c -m 644 'gsttaginterface.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsttaginterface.h' /usr/bin/install -c -m 644 'gstthread.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstthread.h' /usr/bin/install -c -m 644 'gsttrace.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsttrace.h' /usr/bin/install -c -m 644 'gsttrashstack.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsttrashstack.h' /usr/bin/install -c -m 644 'gsttypefind.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsttypefind.h' /usr/bin/install -c -m 644 'gsttypes.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsttypes.h' /usr/bin/install -c -m 644 'gsturi.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsturi.h' /usr/bin/install -c -m 644 'gsturitype.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gsturitype.h' /usr/bin/install -c -m 644 'gstutils.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstutils.h' /usr/bin/install -c -m 644 'gstvalue.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstvalue.h' /usr/bin/install -c -m 644 'gstregistry.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstregistry.h' /usr/bin/install -c -m 644 'gstregistrypool.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstregistrypool.h' /usr/bin/install -c -m 644 'gstparse.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstparse.h' /usr/bin/install -c -m 644 'gstxml.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstxml.h' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst" /usr/bin/install -c -m 644 'gstconfig.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstconfig.h' /usr/bin/install -c -m 644 'gstversion.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstversion.h' /usr/bin/install -c -m 644 'gstenumtypes.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstenumtypes.h' /usr/bin/install -c -m 644 'gstmarshal.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/gstmarshal.h' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' Making install in autoplug make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/autoplug' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/autoplug' make[4]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstspider.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.la' libtool: install: warning: relinking `libgstspider.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/autoplug; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstspider.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstspider_la-gstspider.lo libgstspider_la-gstspideridentity.lo libgstspider_la-gstsearchfuncs.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstspider.la' nm .libs/libgstspider_la-gstspider.o .libs/libgstspider_la-gstspideridentity.o .libs/libgstspider_la-gstsearchfuncs.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstspider.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstspider.exp" > ".libs/libgstspider.expT" mv -f ".libs/libgstspider.expT" ".libs/libgstspider.exp" echo "{ global:" > .libs/libgstspider.ver cat .libs/libgstspider.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstspider.ver echo "local: *; };" >> .libs/libgstspider.ver gcc -shared .libs/libgstspider_la-gstspider.o .libs/libgstspider_la-gstspideridentity.o .libs/libgstspider_la-gstsearchfuncs.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstspider.so -Wl,-version-script -Wl,.libs/libgstspider.ver -o .libs/libgstspider.so /usr/bin/install -c .libs/libgstspider.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.so /usr/bin/install -c .libs/libgstspider.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.la /usr/bin/install -c .libs/libgstspider.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/autoplug' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/autoplug' Making install in elements make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/elements' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/elements' make[4]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstelements.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.la' libtool: install: warning: relinking `libgstelements.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/elements; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstelements.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstelements_la-gstaggregator.lo libgstelements_la-gstbufferstore.lo libgstelements_la-gstelements.lo libgstelements_la-gstfakesink.lo libgstelements_la-gstfakesrc.lo libgstelements_la-gstfilesink.lo libgstelements_la-gstfilesrc.lo libgstelements_la-gstfdsink.lo libgstelements_la-gstfdsrc.lo libgstelements_la-gstidentity.lo libgstelements_la-gstmd5sink.lo libgstelements_la-gstmultifilesrc.lo libgstelements_la-gstpipefilter.lo libgstelements_la-gstshaper.lo libgstelements_la-gststatistics.lo libgstelements_la-gsttee.lo libgstelements_la-gsttypefindelement.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstelements.la' nm .libs/libgstelements_la-gstaggregator.o .libs/libgstelements_la-gstbufferstore.o .libs/libgstelements_la-gstelements.o .libs/libgstelements_la-gstfakesink.o .libs/libgstelements_la-gstfakesrc.o .libs/libgstelements_la-gstfilesink.o .libs/libgstelements_la-gstfilesrc.o .libs/libgstelements_la-gstfdsink.o .libs/libgstelements_la-gstfdsrc.o .libs/libgstelements_la-gstidentity.o .libs/libgstelements_la-gstmd5sink.o .libs/libgstelements_la-gstmultifilesrc.o .libs/libgstelements_la-gstpipefilter.o .libs/libgstelements_la-gstshaper.o .libs/libgstelements_la-gststatistics.o .libs/libgstelements_la-gsttee.o .libs/libgstelements_la-gsttypefindelement.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstelements.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstelements.exp" > ".libs/libgstelements.expT" mv -f ".libs/libgstelements.expT" ".libs/libgstelements.exp" echo "{ global:" > .libs/libgstelements.ver cat .libs/libgstelements.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstelements.ver echo "local: *; };" >> .libs/libgstelements.ver gcc -shared .libs/libgstelements_la-gstaggregator.o .libs/libgstelements_la-gstbufferstore.o .libs/libgstelements_la-gstelements.o .libs/libgstelements_la-gstfakesink.o .libs/libgstelements_la-gstfakesrc.o .libs/libgstelements_la-gstfilesink.o .libs/libgstelements_la-gstfilesrc.o .libs/libgstelements_la-gstfdsink.o .libs/libgstelements_la-gstfdsrc.o .libs/libgstelements_la-gstidentity.o .libs/libgstelements_la-gstmd5sink.o .libs/libgstelements_la-gstmultifilesrc.o .libs/libgstelements_la-gstpipefilter.o .libs/libgstelements_la-gstshaper.o .libs/libgstelements_la-gststatistics.o .libs/libgstelements_la-gsttee.o .libs/libgstelements_la-gsttypefindelement.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstelements.so -Wl,-version-script -Wl,.libs/libgstelements.ver -o .libs/libgstelements.so /usr/bin/install -c .libs/libgstelements.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.so /usr/bin/install -c .libs/libgstelements.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.la /usr/bin/install -c .libs/libgstelements.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/elements' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/elements' Making install in schedulers make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers' make[4]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstbasicomegascheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.la' libtool: install: warning: relinking `libgstbasicomegascheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstbasicomegascheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstbasicomegascheduler_la-gstbasicscheduler.lo ../../gst/libgstreamer-0.8.la ../libcothreads.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstbasicomegascheduler.la' nm .libs/libgstbasicomegascheduler_la-gstbasicscheduler.o ../.libs/libcothreads.a | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstbasicomegascheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstbasicomegascheduler.exp" > ".libs/libgstbasicomegascheduler.expT" mv -f ".libs/libgstbasicomegascheduler.expT" ".libs/libgstbasicomegascheduler.exp" echo "{ global:" > .libs/libgstbasicomegascheduler.ver cat .libs/libgstbasicomegascheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstbasicomegascheduler.ver echo "local: *; };" >> .libs/libgstbasicomegascheduler.ver gcc -shared .libs/libgstbasicomegascheduler_la-gstbasicscheduler.o -Wl,--whole-archive ../.libs/libcothreads.a -Wl,--no-whole-archive -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstbasicomegascheduler.so -Wl,-version-script -Wl,.libs/libgstbasicomegascheduler.ver -o .libs/libgstbasicomegascheduler.so /usr/bin/install -c .libs/libgstbasicomegascheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.so /usr/bin/install -c .libs/libgstbasicomegascheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.la /usr/bin/install -c .libs/libgstbasicomegascheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstentryomegascheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.la' libtool: install: warning: relinking `libgstentryomegascheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstentryomegascheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstentryomegascheduler_la-entryscheduler.lo ../../gst/libgstreamer-0.8.la ../libcothreads.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstentryomegascheduler.la' nm .libs/libgstentryomegascheduler_la-entryscheduler.o ../.libs/libcothreads.a | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstentryomegascheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstentryomegascheduler.exp" > ".libs/libgstentryomegascheduler.expT" mv -f ".libs/libgstentryomegascheduler.expT" ".libs/libgstentryomegascheduler.exp" echo "{ global:" > .libs/libgstentryomegascheduler.ver cat .libs/libgstentryomegascheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstentryomegascheduler.ver echo "local: *; };" >> .libs/libgstentryomegascheduler.ver gcc -shared .libs/libgstentryomegascheduler_la-entryscheduler.o -Wl,--whole-archive ../.libs/libcothreads.a -Wl,--no-whole-archive -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstentryomegascheduler.so -Wl,-version-script -Wl,.libs/libgstentryomegascheduler.ver -o .libs/libgstentryomegascheduler.so /usr/bin/install -c .libs/libgstentryomegascheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.so /usr/bin/install -c .libs/libgstentryomegascheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.la /usr/bin/install -c .libs/libgstentryomegascheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstoptomegascheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.la' libtool: install: warning: relinking `libgstoptomegascheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstoptomegascheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstoptomegascheduler_la-gstoptimalscheduler.lo ../../gst/libgstreamer-0.8.la ../libcothreads.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstoptomegascheduler.la' nm .libs/libgstoptomegascheduler_la-gstoptimalscheduler.o ../.libs/libcothreads.a | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstoptomegascheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstoptomegascheduler.exp" > ".libs/libgstoptomegascheduler.expT" mv -f ".libs/libgstoptomegascheduler.expT" ".libs/libgstoptomegascheduler.exp" echo "{ global:" > .libs/libgstoptomegascheduler.ver cat .libs/libgstoptomegascheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstoptomegascheduler.ver echo "local: *; };" >> .libs/libgstoptomegascheduler.ver gcc -shared .libs/libgstoptomegascheduler_la-gstoptimalscheduler.o -Wl,--whole-archive ../.libs/libcothreads.a -Wl,--no-whole-archive -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstoptomegascheduler.so -Wl,-version-script -Wl,.libs/libgstoptomegascheduler.ver -o .libs/libgstoptomegascheduler.so /usr/bin/install -c .libs/libgstoptomegascheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.so /usr/bin/install -c .libs/libgstoptomegascheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.la /usr/bin/install -c .libs/libgstoptomegascheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstbasicgthreadscheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.la' libtool: install: warning: relinking `libgstbasicgthreadscheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstbasicgthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstbasicgthreadscheduler_la-gstbasicscheduler.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstbasicgthreadscheduler.la' nm .libs/libgstbasicgthreadscheduler_la-gstbasicscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstbasicgthreadscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstbasicgthreadscheduler.exp" > ".libs/libgstbasicgthreadscheduler.expT" mv -f ".libs/libgstbasicgthreadscheduler.expT" ".libs/libgstbasicgthreadscheduler.exp" echo "{ global:" > .libs/libgstbasicgthreadscheduler.ver cat .libs/libgstbasicgthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstbasicgthreadscheduler.ver echo "local: *; };" >> .libs/libgstbasicgthreadscheduler.ver gcc -shared .libs/libgstbasicgthreadscheduler_la-gstbasicscheduler.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstbasicgthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstbasicgthreadscheduler.ver -o .libs/libgstbasicgthreadscheduler.so /usr/bin/install -c .libs/libgstbasicgthreadscheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.so /usr/bin/install -c .libs/libgstbasicgthreadscheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.la /usr/bin/install -c .libs/libgstbasicgthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstentrygthreadscheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.la' libtool: install: warning: relinking `libgstentrygthreadscheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstentrygthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstentrygthreadscheduler_la-entryscheduler.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstentrygthreadscheduler.la' nm .libs/libgstentrygthreadscheduler_la-entryscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstentrygthreadscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstentrygthreadscheduler.exp" > ".libs/libgstentrygthreadscheduler.expT" mv -f ".libs/libgstentrygthreadscheduler.expT" ".libs/libgstentrygthreadscheduler.exp" echo "{ global:" > .libs/libgstentrygthreadscheduler.ver cat .libs/libgstentrygthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstentrygthreadscheduler.ver echo "local: *; };" >> .libs/libgstentrygthreadscheduler.ver gcc -shared .libs/libgstentrygthreadscheduler_la-entryscheduler.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstentrygthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstentrygthreadscheduler.ver -o .libs/libgstentrygthreadscheduler.so /usr/bin/install -c .libs/libgstentrygthreadscheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.so /usr/bin/install -c .libs/libgstentrygthreadscheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.la /usr/bin/install -c .libs/libgstentrygthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstoptscheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.la' libtool: install: warning: relinking `libgstoptscheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstoptscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstoptscheduler_la-gstoptimalscheduler.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstoptscheduler.la' nm .libs/libgstoptscheduler_la-gstoptimalscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstoptscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstoptscheduler.exp" > ".libs/libgstoptscheduler.expT" mv -f ".libs/libgstoptscheduler.expT" ".libs/libgstoptscheduler.exp" echo "{ global:" > .libs/libgstoptscheduler.ver cat .libs/libgstoptscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstoptscheduler.ver echo "local: *; };" >> .libs/libgstoptscheduler.ver gcc -shared .libs/libgstoptscheduler_la-gstoptimalscheduler.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstoptscheduler.so -Wl,-version-script -Wl,.libs/libgstoptscheduler.ver -o .libs/libgstoptscheduler.so /usr/bin/install -c .libs/libgstoptscheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.so /usr/bin/install -c .libs/libgstoptscheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.la /usr/bin/install -c .libs/libgstoptscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstoptgthreadscheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.la' libtool: install: warning: relinking `libgstoptgthreadscheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstoptgthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstoptgthreadscheduler_la-gstoptimalscheduler.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstoptgthreadscheduler.la' nm .libs/libgstoptgthreadscheduler_la-gstoptimalscheduler.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstoptgthreadscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstoptgthreadscheduler.exp" > ".libs/libgstoptgthreadscheduler.expT" mv -f ".libs/libgstoptgthreadscheduler.expT" ".libs/libgstoptgthreadscheduler.exp" echo "{ global:" > .libs/libgstoptgthreadscheduler.ver cat .libs/libgstoptgthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstoptgthreadscheduler.ver echo "local: *; };" >> .libs/libgstoptgthreadscheduler.ver gcc -shared .libs/libgstoptgthreadscheduler_la-gstoptimalscheduler.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstoptgthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstoptgthreadscheduler.ver -o .libs/libgstoptgthreadscheduler.so /usr/bin/install -c .libs/libgstoptgthreadscheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.so /usr/bin/install -c .libs/libgstoptgthreadscheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.la /usr/bin/install -c .libs/libgstoptgthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstfairgthreadscheduler.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.la' libtool: install: warning: relinking `libgstfairgthreadscheduler.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstfairgthreadscheduler.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstfairgthreadscheduler_la-fairscheduler.lo libgstfairgthreadscheduler_la-faircothreads.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstfairgthreadscheduler.la' nm .libs/libgstfairgthreadscheduler_la-fairscheduler.o .libs/libgstfairgthreadscheduler_la-faircothreads.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstfairgthreadscheduler.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstfairgthreadscheduler.exp" > ".libs/libgstfairgthreadscheduler.expT" mv -f ".libs/libgstfairgthreadscheduler.expT" ".libs/libgstfairgthreadscheduler.exp" echo "{ global:" > .libs/libgstfairgthreadscheduler.ver cat .libs/libgstfairgthreadscheduler.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstfairgthreadscheduler.ver echo "local: *; };" >> .libs/libgstfairgthreadscheduler.ver gcc -shared .libs/libgstfairgthreadscheduler_la-fairscheduler.o .libs/libgstfairgthreadscheduler_la-faircothreads.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstfairgthreadscheduler.so -Wl,-version-script -Wl,.libs/libgstfairgthreadscheduler.ver -o .libs/libgstfairgthreadscheduler.so /usr/bin/install -c .libs/libgstfairgthreadscheduler.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.so /usr/bin/install -c .libs/libgstfairgthreadscheduler.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.la /usr/bin/install -c .libs/libgstfairgthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/schedulers' Making install in indexers make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/indexers' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/indexers' make[4]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" /bin/sh ../../libtool --mode=install /usr/bin/install -c 'libgstindexers.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.la' libtool: install: warning: relinking `libgstindexers.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/gst/indexers; /bin/sh ../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstindexers.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstindexers_la-gstindexers.lo libgstindexers_la-gstmemindex.lo libgstindexers_la-gstfileindex.lo ../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstindexers.la' nm .libs/libgstindexers_la-gstindexers.o .libs/libgstindexers_la-gstmemindex.o .libs/libgstindexers_la-gstfileindex.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstindexers.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstindexers.exp" > ".libs/libgstindexers.expT" mv -f ".libs/libgstindexers.expT" ".libs/libgstindexers.exp" echo "{ global:" > .libs/libgstindexers.ver cat .libs/libgstindexers.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstindexers.ver echo "local: *; };" >> .libs/libgstindexers.ver gcc -shared .libs/libgstindexers_la-gstindexers.o .libs/libgstindexers_la-gstmemindex.o .libs/libgstindexers_la-gstfileindex.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstindexers.so -Wl,-version-script -Wl,.libs/libgstindexers.ver -o .libs/libgstindexers.so /usr/bin/install -c .libs/libgstindexers.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.so /usr/bin/install -c .libs/libgstindexers.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.la /usr/bin/install -c .libs/libgstindexers.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/indexers' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/indexers' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst' Making install in libs make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' Making install in gst make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' Making install in bytestream make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/bytestream' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/bytestream' make[4]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/bytestream" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/bytestream" /usr/bin/install -c -m 644 'bytestream.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/bytestream/bytestream.h' /usr/bin/install -c -m 644 'adapter.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/bytestream/adapter.h' /usr/bin/install -c -m 644 'filepad.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/bytestream/filepad.h' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" /bin/sh ../../../libtool --mode=install /usr/bin/install -c 'libgstbytestream.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.la' /usr/bin/install -c .libs/libgstbytestream.so /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.so /usr/bin/install -c .libs/libgstbytestream.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.la /usr/bin/install -c .libs/libgstbytestream.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/bytestream' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/bytestream' Making install in control make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/control' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/control' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib" /bin/sh ../../../libtool --mode=install /usr/bin/install -c 'libgstcontrol-0.8.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.la' libtool: install: warning: relinking `libgstcontrol-0.8.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/control; /bin/sh ../../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstcontrol-0.8.la -rpath /usr/lib -version-info 5:0:4 -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstcontrol_0.8_la-control.lo libgstcontrol_0.8_la-dparammanager.lo libgstcontrol_0.8_la-dparam.lo libgstcontrol_0.8_la-dparam_smooth.lo libgstcontrol_0.8_la-unitconvert.lo libgstcontrol_0.8_la-dplinearinterp.lo ../../../gst/libgstreamer-0.8.la -lm -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstcontrol-0.8.la' nm .libs/libgstcontrol_0.8_la-control.o .libs/libgstcontrol_0.8_la-dparammanager.o .libs/libgstcontrol_0.8_la-dparam.o .libs/libgstcontrol_0.8_la-dparam_smooth.o .libs/libgstcontrol_0.8_la-unitconvert.o .libs/libgstcontrol_0.8_la-dplinearinterp.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstcontrol-0.8.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstcontrol-0.8.exp" > ".libs/libgstcontrol-0.8.expT" mv -f ".libs/libgstcontrol-0.8.expT" ".libs/libgstcontrol-0.8.exp" echo "{ global:" > .libs/libgstcontrol-0.8.ver cat .libs/libgstcontrol-0.8.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstcontrol-0.8.ver echo "local: *; };" >> .libs/libgstcontrol-0.8.ver gcc -shared .libs/libgstcontrol_0.8_la-control.o .libs/libgstcontrol_0.8_la-dparammanager.o .libs/libgstcontrol_0.8_la-dparam.o .libs/libgstcontrol_0.8_la-dparam_smooth.o .libs/libgstcontrol_0.8_la-unitconvert.o .libs/libgstcontrol_0.8_la-dplinearinterp.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -lm -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstcontrol-0.8.so.1 -Wl,-version-script -Wl,.libs/libgstcontrol-0.8.ver -o .libs/libgstcontrol-0.8.so.1.4.0 /usr/bin/install -c .libs/libgstcontrol-0.8.so.1.4.0T /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.so.1.4.0 (cd /var/tmp/gstreamer08-0.8.11-root/usr/lib && { ln -s -f libgstcontrol-0.8.so.1.4.0 libgstcontrol-0.8.so.1 || { rm -f libgstcontrol-0.8.so.1 && ln -s libgstcontrol-0.8.so.1.4.0 libgstcontrol-0.8.so.1; }; }) (cd /var/tmp/gstreamer08-0.8.11-root/usr/lib && { ln -s -f libgstcontrol-0.8.so.1.4.0 libgstcontrol-0.8.so || { rm -f libgstcontrol-0.8.so && ln -s libgstcontrol-0.8.so.1.4.0 libgstcontrol-0.8.so; }; }) /usr/bin/install -c .libs/libgstcontrol-0.8.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.la /usr/bin/install -c .libs/libgstcontrol-0.8.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.a libtool: install: warning: remember to run `libtool --finish /usr/lib' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control" /usr/bin/install -c -m 644 'control.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control/control.h' /usr/bin/install -c -m 644 'dparammanager.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control/dparammanager.h' /usr/bin/install -c -m 644 'dparam.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control/dparam.h' /usr/bin/install -c -m 644 'dparam_smooth.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control/dparam_smooth.h' /usr/bin/install -c -m 644 'unitconvert.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control/unitconvert.h' /usr/bin/install -c -m 644 'dparamcommon.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control/dparamcommon.h' /usr/bin/install -c -m 644 'dplinearinterp.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/control/dplinearinterp.h' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/control' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/control' Making install in dataprotocol make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/dataprotocol' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/dataprotocol' make[4]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/dataprotocol" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/dataprotocol" /usr/bin/install -c -m 644 'dataprotocol.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/dataprotocol/dataprotocol.h' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" /bin/sh ../../../libtool --mode=install /usr/bin/install -c 'libgstdataprotocol.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.la' libtool: install: warning: relinking `libgstdataprotocol.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/dataprotocol; /bin/sh ../../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstdataprotocol.la -rpath /usr/lib/gstreamer-0.8 -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstdataprotocol_la-dataprotocol.lo ../../../gst/libgstreamer-0.8.la -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstdataprotocol.la' nm .libs/libgstdataprotocol_la-dataprotocol.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstdataprotocol.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstdataprotocol.exp" > ".libs/libgstdataprotocol.expT" mv -f ".libs/libgstdataprotocol.expT" ".libs/libgstdataprotocol.exp" echo "{ global:" > .libs/libgstdataprotocol.ver cat .libs/libgstdataprotocol.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstdataprotocol.ver echo "local: *; };" >> .libs/libgstdataprotocol.ver gcc -shared .libs/libgstdataprotocol_la-dataprotocol.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstdataprotocol.so -Wl,-version-script -Wl,.libs/libgstdataprotocol.ver -o .libs/libgstdataprotocol.so /usr/bin/install -c .libs/libgstdataprotocol.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.so /usr/bin/install -c .libs/libgstdataprotocol.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.la /usr/bin/install -c .libs/libgstdataprotocol.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/dataprotocol' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/dataprotocol' Making install in getbits make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/getbits' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/getbits' make[4]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/getbits" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/getbits" /usr/bin/install -c -m 644 'getbits.h' '/var/tmp/gstreamer08-0.8.11-root/usr/include/gstreamer-0.8/gst/getbits/getbits.h' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8" /bin/sh ../../../libtool --mode=install /usr/bin/install -c 'libgstgetbits.la' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.la' libtool: install: warning: relinking `libgstgetbits.la' (cd /usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/getbits; /bin/sh ../../../libtool --tag=CC --mode=relink gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o libgstgetbits.la -rpath /usr/lib/gstreamer-0.8 ../../../gst/libgstreamer-0.8.la -module -avoid-version -export-symbols-regex "_*(gst_|Gst|GST_).*" libgstgetbits_la-getbits.lo libgstgetbits_la-gstgetbits_generic.lo gstgetbits_i386.lo -inst-prefix-dir /var/tmp/gstreamer08-0.8.11-root) generating symbol list for `libgstgetbits.la' nm .libs/libgstgetbits_la-getbits.o .libs/libgstgetbits_la-gstgetbits_generic.o .libs/gstgetbits_i386.o | sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' | /bin/sed 's/.* //' | sort | uniq > .libs/libgstgetbits.exp grep -E -e "_*(gst_|Gst|GST_).*" ".libs/libgstgetbits.exp" > ".libs/libgstgetbits.expT" mv -f ".libs/libgstgetbits.expT" ".libs/libgstgetbits.exp" echo "{ global:" > .libs/libgstgetbits.ver cat .libs/libgstgetbits.exp | sed -e "s/\(.*\)/\1;/" >> .libs/libgstgetbits.ver echo "local: *; };" >> .libs/libgstgetbits.ver gcc -shared .libs/libgstgetbits_la-getbits.o .libs/libgstgetbits_la-gstgetbits_generic.o .libs/gstgetbits_i386.o -L/var/tmp/gstreamer08-0.8.11-root/usr/lib -L/usr/lib -lgstreamer-0.8 -m32 -march=i386 -mtune=pentium4 -Wl,-soname -Wl,libgstgetbits.so -Wl,-version-script -Wl,.libs/libgstgetbits.ver -o .libs/libgstgetbits.so /usr/bin/install -c .libs/libgstgetbits.soT /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.so /usr/bin/install -c .libs/libgstgetbits.lai /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.la /usr/bin/install -c .libs/libgstgetbits.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.a ranlib /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.a chmod 644 /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.a libtool: install: warning: remember to run `libtool --finish /usr/lib/gstreamer-0.8' make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/getbits' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst/getbits' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[4]: Nothing to be done for `install-exec-am'. make[4]: Nothing to be done for `install-data-am'. make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs/gst' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' make[3]: Nothing to be done for `install-exec-am'. make[3]: Nothing to be done for `install-data-am'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/libs' Making install in tools make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/tools' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/tools' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/bin" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/bin" /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-complete' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-complete' /usr/bin/install -c gst-complete /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-complete /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-compprep' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-compprep' /usr/bin/install -c gst-compprep /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-compprep /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-xmllaunch' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmllaunch' /usr/bin/install -c gst-xmllaunch /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmllaunch /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-complete-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-complete-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-complete-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-complete-0.8 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-compprep-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-compprep-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-compprep-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-compprep-0.8 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-xmllaunch-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmllaunch-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-xmllaunch-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmllaunch-0.8 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-feedback' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-feedback' /usr/bin/install -c gst-feedback /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-feedback /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-inspect' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-inspect' /usr/bin/install -c gst-inspect /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-inspect /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-launch' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-launch' /usr/bin/install -c gst-launch /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-launch /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-md5sum' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-md5sum' /usr/bin/install -c gst-md5sum /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-md5sum /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-typefind' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-typefind' /usr/bin/install -c gst-typefind /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-typefind /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-xmlinspect' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmlinspect' /usr/bin/install -c gst-xmlinspect /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmlinspect /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-inspect-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-inspect-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' libtool: install: warning: `../libs/gst/control/libgstcontrol-0.8.la' has not been installed in `/usr/lib' libtool: install: warning: `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-inspect-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-inspect-0.8 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-launch-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-launch-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-launch-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-launch-0.8 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-md5sum-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-md5sum-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-md5sum-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-md5sum-0.8 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-typefind-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-typefind-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-typefind-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-typefind-0.8 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-xmlinspect-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmlinspect-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' libtool: install: warning: `../libs/gst/control/libgstcontrol-0.8.la' has not been installed in `/usr/lib' libtool: install: warning: `/usr/src/rpm/BUILD/gstreamer-0.8.11/gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-xmlinspect-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmlinspect-0.8 test -z "/var/tmp/gstreamer08-0.8.11-root/usr/bin" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/bin" /usr/bin/install -c 'gst-feedback-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-feedback-0.8' /usr/bin/install -c 'gst-register' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-register' /usr/bin/install -c 'gst-register-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-register-0.8' test -z "/var/tmp/gstreamer08-0.8.11-root/usr/libexec" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/libexec" /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-register-i686' '/var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-i686' /usr/bin/install -c gst-register-i686 /var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-i686 /bin/sh ../libtool --mode=install /usr/bin/install -c 'gst-register-i686-0.8' '/var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-i686-0.8' libtool: install: warning: `../gst/libgstreamer-0.8.la' has not been installed in `/usr/lib' /usr/bin/install -c .libs/gst-register-i686-0.8 /var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-i686-0.8 test -z "/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1" /usr/bin/install -c -m 644 './gst-register-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-register-0.8.1' /usr/bin/install -c -m 644 './gst-complete-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-complete-0.8.1' /usr/bin/install -c -m 644 './gst-compprep-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-compprep-0.8.1' /usr/bin/install -c -m 644 './gst-xmllaunch-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-xmllaunch-0.8.1' /usr/bin/install -c -m 644 './gst-feedback-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-feedback-0.8.1' /usr/bin/install -c -m 644 './gst-inspect-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-inspect-0.8.1' /usr/bin/install -c -m 644 './gst-launch-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-launch-0.8.1' /usr/bin/install -c -m 644 './gst-md5sum-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-md5sum-0.8.1' /usr/bin/install -c -m 644 './gst-typefind-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-typefind-0.8.1' /usr/bin/install -c -m 644 './gst-xmlinspect-0.8.1' '/var/tmp/gstreamer08-0.8.11-root/usr/share/man/man1/gst-xmlinspect-0.8.1' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/tools' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/tools' Making install in pkgconfig make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/pkgconfig' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/pkgconfig' make[2]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/lib/pkgconfig" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/lib/pkgconfig" /usr/bin/install -c -m 644 'gstreamer-0.8.pc' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/pkgconfig/gstreamer-0.8.pc' /usr/bin/install -c -m 644 'gstreamer-control-0.8.pc' '/var/tmp/gstreamer08-0.8.11-root/usr/lib/pkgconfig/gstreamer-control-0.8.pc' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/pkgconfig' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/pkgconfig' Making install in po make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/po' /bin/sh `case "./mkinstalldirs" in /*) echo "./mkinstalldirs" ;; *) echo ".././mkinstalldirs" ;; esac` /var/tmp/gstreamer08-0.8.11-root/usr/share mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/af mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/af/LC_MESSAGES installing af.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/af/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/az mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/az/LC_MESSAGES installing az.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/az/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/ca mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/ca/LC_MESSAGES installing ca.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/ca/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/cs mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/cs/LC_MESSAGES installing cs.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/cs/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/de mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/de/LC_MESSAGES installing de.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/de/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/en_GB mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/en_GB/LC_MESSAGES installing en_GB.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/en_GB/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/fr mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/fr/LC_MESSAGES installing fr.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/fr/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/it mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/it/LC_MESSAGES installing it.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/it/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/nb mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/nb/LC_MESSAGES installing nb.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/nb/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/nl mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/nl/LC_MESSAGES installing nl.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/nl/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/ru mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/ru/LC_MESSAGES installing ru.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/ru/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sq mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sq/LC_MESSAGES installing sq.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sq/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sr mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sr/LC_MESSAGES installing sr.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sr/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sv mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sv/LC_MESSAGES installing sv.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/sv/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/tr mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/tr/LC_MESSAGES installing tr.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/tr/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/uk mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/uk/LC_MESSAGES installing uk.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/uk/LC_MESSAGES/gstreamer-0.8.mo mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/vi mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/vi/LC_MESSAGES installing vi.gmo as /var/tmp/gstreamer08-0.8.11-root/usr/share/locale/vi/LC_MESSAGES/gstreamer-0.8.mo if test "gstreamer" = "gettext"; then \ /bin/sh `case "./mkinstalldirs" in /*) echo "./mkinstalldirs" ;; *) echo ".././mkinstalldirs" ;; esac` /var/tmp/gstreamer08-0.8.11-root/usr/share/gettext/po; \ for file in Makefile.in.in Makevars remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot ; do \ /usr/bin/install -c -m 644 ./$file \ /var/tmp/gstreamer08-0.8.11-root/usr/share/gettext/po/$file; \ done; \ else \ : ; \ fi make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/po' Making install in common make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' Making install in m4 make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common/m4' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common/m4' make[3]: Nothing to be done for `install-exec-am'. make[3]: Nothing to be done for `install-data-am'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common/m4' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common/m4' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' make[3]: Nothing to be done for `install-exec-am'. make[3]: Nothing to be done for `install-data-am'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/common' Making install in docs make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' Making install in faq make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' cd build && xmllint -noout -valid faq.xml make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq/build/faq.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" GStreamer FAQ (0.8.11) This is the FAQ for GStreamer, a multimedia framework. Questions and answers range from general information to deep-down-and-dirty compilation issues. 0.1.12003-04-24Added Q&A about developing with uninstalled copy.0.1.02002-10-01Initial conversion from FAQ database.Getting Started So you're eager to get started learning about GStreamer. There's a few ways you can get started. If you want to learn by reading about it, start with If you'd rather learn by trying it out, start with If you want to live on the bleeding edge and develop and use CVS, see GeneralIs GStreamer a media player ? No, GStreamer is a development framework for creating applications like media players, video editors, streaming media broadcasters and so on. That said, very good media players can easily be built on top of GStreamer and we even include a simple yet functional media player with GStreamer, called gst-player. Why is GStreamer written in C ? Why not C++/Objective-C/... ? We like C. Aside from "personal preference", there are a number of technical reasons why C is nice in this project: C is extremely portable.C is fast.It is easy to make language bindings for libraries written in C. The GObject object system provided by GLib implements objects in C, in a portable, powerful way. This library provides for introspection and runtime dynamic typing. It is a full OO system, but without the syntactic sugar. If you want sugar, take a look at GOB.Use of C integrates nicely with Gtk+ and GNOME. Some people like this a lot, but neither Gtk+ nor GNOME are required by GStreamer. So, in closing, we like C. If you don't, that's fine; if you still want to help out on GStreamer, we always need more language binding people. And if not, don't bother us; we're working :-) What applications are available for GStreamer ? GStreamer is still very early in its development, but already we see some really nice applications being developed in parallel with GStreamer. Both gst-player and gst-editor are very closely linked to GStreamer itself for obvious reasons. Does GStreamer support the format of my media files? GStreamer aims to support every format imaginable, but that doesn't mean the developers have managed to achieve that aim yet. If a GStreamer enabled application doesn't play back your files, you can help us solve that problem by filing an enhancement request bug for that format. If you have it, please provide: links to other players, preferrably Open Source and working on Unixlinks to explanations of the format.ways to obtain mediafiles in that format to test. What are the exact licensing terms for GStreamer and its plugins ? All of GStreamer, including our own plugin code, is licensed under the GNU LGPL license. Some of the libraries we use for some of the plugins are however under the GPL, which means that those plugins can not be used by a non-GPL-compatible application. As part of the GStreamer source download you find a file called LICENSE_readme in gst-plugins package. That file contains information in the exact licensing terms of the libraries we use. As a general rule, GStreamer aims at using only LGPL or BSD licensed libraries if available and only use GPL or proprietary libraries where no good LGPL or BSD alternatives are available. From GStreamer 0.4.2 on, we implemented a license field for all of the plugins, and in the future we might have the application enforce a stricter policy (much like tainting in the kernel). Is GStreamer a sound server ? No, GStreamer is not a soundserver. GStreamer does however have plugins supporting most of the major soundservers available today, including ESD, aRTSd, and to some extent Jack. Support for MAS is also planned. Will GStreamer be available for platforms other than Unix ? Depends. Our main target is the Unix platform. That said, interest has been expressed in porting GStreamer to other platforms and the GStreamer core team will gladly accept patches to accomplish this. What is GStreamer's relationship with the GNOME community ? While GStreamer is operated as an independent project, we do have a close relationship with the GNOME community. Many of our hackers consider themselves also to be members of the GNOME community. There are plans to make (some part of) GStreamer an official part of the development framework of GNOME. This does not exclude use of GStreamer by other communities at all, of course. What is GStreamer's relationship with the KDE community ? The GStreamer community wants to have as good a relationship as possible with KDE, and we hope that someday KDE decides to adopt GStreamer as their multimedia API, just like the GNOME community plans on doing. There have been contacts from time to time between the GStreamer community and KDE and we do already have support for the aRTSd sound server used by KDE. Also, some of the KDE hackers have created Qt bindings of GStreamer and made a simple video player. I'm considering adding GStreamer output to my application... That doesn't really make sense. GStreamer is not a sound server, so you don't output directly to GStreamer, and it's not an intermediate API between audio data and different kinds of audio sinks. It is a fundamental design decision to use GStreamer in your app; there are no easy ways of somehow 'transfering' data from your app to GStreamer. Instead, your app would have to use or implement a number of GStreamer elements, string them together, and tell them to run. In that manner the data would all be internal to the GStreamer pipeline. That said, it is possible to write a plugin specific to your app that can get at the audio data. DependenciesWhy are there so many dependencies ? Making a full-featured media framework is a huge undertaking in itself. By using the work done by others, we both reduce the amount of redundant work being done and leave ourselves free to work on the architecture itself instead of working on the low-level stuff. We would be stupid not to reuse the code others have written. However, do realize that in no way you are forced to have all dependencies installed. None of the core developers has all of them installed. GStreamer has only a few obligate dependencies : GLib 2.0, popt >= 1.6.0, and very common stuff like glibc, a C compiler, and so on. All of the other dependencies are optional. So, in closing, let's rephrase the question to Why are you giving me so many choices and such a rich environment ? Does GStreamer use GTK+ 1.2/GLib 1.2 or GLib 2.0 ? Since the 0.3.3 release of GStreamer, we use GLib 2.0 as the core library for GStreamer, which features a move of GObject from GTK+ 2.0 to GLib 2.0. If you want to compile using GTK+ 1.2/GLib 1.2, you need to get the 0.3.1 or earlier release. It is of course not supported. Does GStreamer offer support for DVD decoder cards like dxr2/3 ? We do have support for the dxr3, although dxr2 support is unknown. GStreamer can easily accomodate hardware acceleration by writing new device-specific elements. Is GStreamer X independent ? Yes, we have no X dependency in any of our core modules. There are GStreamer applications that run fine without any need for X. However, until our Linux Framebuffer or libsvga plugin is ready, you will not be able to play videos without X. In the future, there will probably be lots of different output plugins for video available. What is GStreamer's position on efforts such as LADSPA ? GStreamer actively supports such efforts, and in the case of LADPSA, we already have a wrapper plugin. This wrapper plug-in detects the LADSPA plugins present on your system at register time. Does GStreamer support MIDI ? Not yet. The GStreamer architecture should be able to support the needs of MIDI applications very well however. If you are a developer interested in adding MIDI support to GStreamer we are very interested in getting in touch with you. Does GStreamer depend on GNOME ? No. But many of the applications developed for GStreamer do, including our sample applications. There is nothing hindering people from developing applications using other toolkits however and we would happily help promote such efforts. A good example of an application using GStreamer, but which is not using GNOME is the Mozstreamer which uses Mozilla XUL. Getting GStreamerHow do I get GStreamer ? Generally speaking, you have three options, ranging from easy to hard : distribution-specific packages source tarballs CVS How can I install GStreamer from source ? We provide tarballs of our releases on our own site, at http://gstreamer.freedesktop.org/src/ When compiling from source, make sure you specify PKG_CONFIG_PATH correctly when building against GStreamer. For example, if you configured GStreamer with the default prefix (which is /usr/local), then you need to export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig before building gst-plugins. Are there premade binaries available ? Yes, we currently provide precompiled packages for Red Hat, Debian and Linux Mandrake. We provide RPMS for Red Hat and Fedora Core through our Apt for rpm page. We usually support the last 2-3 releases of Red Hat. (RH9 and FC1) GStreamer is already in Debian experimental, so if you are a debian user you should be able to get the Debian packages from there.GStreamer is also in Mandrake Cooker so if you are using a recent release of Linux Mandrake you should be able to get GStreamer from there. To learn howto get packages from Mandrake cooker the Mandrake cooker page has more info For other RPM based distributions we recommend getting the source tarball and doing 'rpm -ta gstreamer-0.X.X' to create rpms. We keep our SPEC file constantly up to date so you should always be able to build GStreamer rpms from a tarball. The SPEC file is aimed at Red Hat however, so there might be some need for you to edit the Requirements list if your distribution name these packages differently.Why don't you provide premade binaries for distribution XY ? GStreamer is run on a volunteer basis. The package that are provided are made by non-paid people who do this on their own time. The distributions we support with binaries are the distributions that we have people who have volunteered to make binaries for. If you are interested in maintaining GStreamer binaries for other distributions or Unices we would be happy to hear from you. Contact us through the GStreamer-devel mailing list. I am having trouble compiling GStreamer on my LFS installation, why ? If you are running LFS our basic opinion is that you should be knowledgeable enough to solve any build issues you get on your own. Being volunteered based we can't promise support to anyone of course, but are you using LFS consider yourself extra unsupported. We neither can or want to know enough, about how your unique system is configured, to be able to help you. That said, if you come to the #gstreamer channel on irc.openprojects.net we might of course be able to give you some general hints and pointers. How do I get GStreamer through CVS ? see this page : http://gstreamer.freedesktop.org/dev/ for CVS access. (anonymous and developer) Using GStreamerOk, I've installed GStreamer. What can I do next ? First of all, verify that you have a working registry and that you can inspect them by typing $ gst-inspect fakesrc This should print out a bunch of information about this particular element. If this tells you that there is "no such element or plugin", you haven't installed GStreamer correctly. Please check how to get GStreamer If this fails with any other message, we would appreciate a bug report. It's time to try out a few things. Start with gst-launch and two plug-ins that you really should have : fakesrc and fakesink. They do nothing except pass empty buffers. Type this at the command-line : $ gst-launch -v fakesrc num-buffers=3 ! fakesink This will print out output that looks similar to this : RUNNING pipeline ... fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 0) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 0) 0x8057510" fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 1) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 1) 0x8057510" fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 2) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 2) 0x8057510" execution ended after 5 iterations (sum 301479000 ns, average 60295800 ns, min 3000 ns, max 105482000 ns) (Some parts of output have been removed for clarity) If it looks similar, then GStreamer itself is running correctly. Can my system play sound through GStreamer ? You can test this by trying to play a sine tone. For this, you need to link the sinesrc plug-in to an output plug-in that matches your hardware. A (non-complete) list of output plug-ins for audio is osssink for OSS outputesdsink for ESound outputartsdsink for aRTs outputalsasink for ALSA outputjacksink for JACK output First of all, run gst-inspect on the output plug-in you want to use to make sure you have it installed. For example, if you use OSS, run $ gst-inspect osssink and see if that prints out a bunch of properties for the plug-in. Then try to play the sine tone by running $ gst-launch sinesrc ! osssink and see if you hear something. Make sure your volume is turned up, but also make sure it is not too loud and you are not wearing your headphones. In GNOME, you can configure audio output for most applications by running $ gstreamer-properties which can also be found in the start menu (Applications -> Preferences -> Multimedia Systems Selector). In KDE, there is not yet a shared way of setting audio output for all applications; however, applications such as Amarok allow you to specify an audio output in their preferences dialog. How can I see what GStreamer plugins I have on my system ? To do this you use the gst-inspect command-line tool, which comes standard with GStreamer. Invoked without any arguments, $ gst-inspect will print out a listing of installed plugins. To learn more about a particular plugin, pass its name on the command line. For example, $ gst-inspect volume will give you information about the volume plugin. Also, if you install the gst-editor package, you will have a graphical plugin browser available, gst-inspect-gui. Where should I report bugs ? Bug management is now hosted on GNOME's Bugzilla at http://bugzilla.gnome.org, under the product GStreamer. Using bugzilla you can view past bug history, report new bugs, etc. Bugzilla requires you to make an account here, which might seem cumbersome, but allows us to at least have a chance at contacting you for further information, as we will most likely have to. How should I report bugs ? When doing a bug report, you should at least describe your distribution how you installed GStreamer (from cvs, source, packages, which ?)if you installed GStreamer before It also is useful for us if you attach output of the gst-feedback command to your bug report. If you're having problem with a specific application (either one of ours, somebody else's, or your own), please also provide a log of gst-mask by running myapp --gst-mask=-1 > mask.log 2>&1 gzip mask.log (interrupting the program if it doesn't stop by itself) and attach mask.log.gz to your bug report. If the application you are having problems with is segfaulting, then provide us with the necessary gdb output. See How do I use the GStreamer command line interface ? You access the GStreamer command line interface using the command gst-launch. To decode an mp3 and play it through OSS, you could use gst-launch filesrc location=thesong.mp3 ! mad ! osssink . More examples can be found in the gst-launch man page. To automatically detect the right codec in a pipeline, try gst-launch filesrc location=my-random-media-file.mpeg ! spider ! osssink . Try replacing osssink with sdlvideosink and see what happens. We also have a simple tool called gst-launch-ext used for debugging, which has predefined pipelines for you. This means you can just write gst-launch-ext (filename) and it will play the file if the extension is supported. Note that no effort has been made for uninterrupted synchronized playback using this tool. Troubleshooting GStreamer My GStreamer-based application crashes on startup with errors about unfound schedulers on the command-line. I get undefined behaviour as soon as any GStreamer element is being initialized. Your registry is probably missing, or it is outdated (i.e. not updated after a recent upgrade). Fix this by running gst-register yourself: gst-register In the worst case, you might have to run it both as user and as root. Note that package managers are suggested to run this automatically during the post-installation. Our RPMs and Debian packages do just that. Some application is telling me that I am missing a plug-in. What do I do ? Well, start by checking if you really are missing the plug-in. gst-inspect (plug-in) and replace (plug-in) with the plug-in you think is missing. If this doesn't return any result, then you either don't have it or your registry cannot find it. If you're not sure either way, then chances are good that you don't have it. You should get the plug-in and run gst-register to register it. How to get the plug-in depends on your distribution. if you run GStreamer using packages for your distribution, you should check what packages are available for your distribution and see if any of the available packages contains the plug-in. if you run GStreamer from a source install, there's a good chance the plug-in didn't get built because you are missing an external library. When you ran configure, you should have gotten output of what plug-ins are going to be built. You can re-run configure to see if it's there. If it isn't, there is a good reason why it is not getting built. The most likely is that you're missing the library you need for it. Check the README file in gst-plugins to see what library you need. Make sure to remember to re-run configure after installing the supporting library ! if you run GStreamer from CVS, the same logic applies as for a source install. Go over the reasons why the plug-in didn't get configured for build. Check output of config.log for a clue as to why it doesn't get built if you're sure you have the library needed installed in a sane place. I get an error that says something like (process:26626): GLib-GObject-WARNING **: specified instance size for type `DVDReadSrc' is smaller than the parent type's `GstElement' instance size What's wrong ? If you run GStreamer CVS uninstalled, it means that something changed in the core that requires a recompilation in the plugins. Recompile the plugins by doing "make clean && make". If you run GStreamer installed, it probably means that you run the plugins against a different (incompatible) version than they were compiled against, which ususally means that you run multiple installations of GStreamer. Remove the old ones and - if needed - recompile again to ensure that it is using the right version. Note that we strongly recommend using Debian or RPM packages, since you will not get such issues if you use provided packages. The GStreamer application I used stops with a segmentation fault. What can I do ? There are two things you can do. If you compiled GStreamer with specific optimization compilation flags, you should try recompiling GStreamer, the application and the plug-ins without any optimization flags. This allows you to verify if the problem is due to optimization or due to bad code. Second, it will also allow you to provide a reasonable backtrace in case the segmentation fault still occurs. The second thing you can do is look at the backtrace to get an idea of where things are going wrong, or give us an idea of what is going wrong. To provide a backtrace, you should run the application in gdb by starting it with gdb (gst-application) (If the application is in a source tree instead of installed on the system, you might want to put "libtool" before "gdb") Pass on the command line arguments to the application by typing set args (the arguments to the application) at the (gdb) prompt Type "run" at the (gdb) prompt and wait for the application to segfault. The application will run a lot slower, however. After the segfault, type "bt" to get a backtrace. This is a stack of function calls detailing the path from main () to where the code is currently at. If the application you're trying to debug contains threads, it is also useful to do info threads and get backtraces of all of the threads involved, by switching to a different thread using "thread (number)" and then again requesting a backtrace using "bt". If you can't or don't want to work out the problem yourself, a copy and paste of all this information should be included in your bug report. Building GStreamer from CVS How do I check out GStreamer from CVS ? GStreamer is hosted on Freedesktop.org. GStreamer consists of various parts. In the beginning, you will be interested in the "gstreamer" module, containing the core, and "gst-plugins", containing the basic set of plugins. To check out the HEAD version of the core, use cvs -d:pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer co gstreamer This will create a directory "gstreamer" in your current directory. If you want to get another module, replace the last "gstreamer" with the name of the module. How do I get developer access to GStreamer CVS ? If you want to gain developer access to GStreamer CVS, you should ask for it on the development lists, or ask one of the maintainers directly. If you are not already a registered developer with a user account on Freedesktop.org, You will then have to provide them with: your desired unix usernameyour full nameyour e-mail addressa copy of your public sshv2 identity. If you do not have this yet, you can generate it by running "ssh-keygen -t dsa". The resulting public key will be in .ssh/id_dsa.pub(optionally) your GPG fingerprint. This would allow you to add and remove ssh keys to your account. I ran autogen.sh, but it fails with something like this: + running aclocal -I m4 -I common/m4 ... aclocal: configure.ac: 8: macro `AM_DISABLE_STATIC' not found in library aclocal: configure.ac: 17: macro `AM_PROG_LIBTOOL' not found in library aclocal failed What's wrong ? aclocal is unable to find two macros installed by libtool in a file called libtool.m4. Normally this would indicate that you don't have libtool, but that would mean autogen.sh would have failed on not finding libtool. It is more likely that you installed automake (which provides aclocal) in a different prefix than libtool. You can check this by examining in what prefix both aclocal and libtool are installed. You can do three things to fix this : install automake in the same prefix as libtoolforce use of the automake installed in the same prefix as libtool by using the --with-automake optionfigure out what prefix libtool has been installed to and point aclocal to the right location by running export ACLOCAL_FLAGS="-I $(prefix)/share/aclocal" where you replace prefix with the prefix where libtool was installed. Developing applications with GStreamerHow do I compile programs that use GStreamer ? GStreamer uses pkg-config to assist applications with compilationa and linking flags. pkg-config is already used by GTK+, GNOME, SDL, and others; so if you are familiar with using it for any of those, you're set. If you're not familiar with pkg-config to compile and link a small one-file program, pass the --cflags and --libs arguments to pkg-config. For example: $ libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.8` -o myprog myprog.c would be sufficient for a gstreamer-only program. If (for example) your app also used GTK+ 2.0, you could use $ libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.8 gtk+-2.0` -o myprog myprog.c Those are back-ticks (on the same key with the tilde on US keyboards), not single quotes. For bigger projects, you should integrate pkg-config use in your Makefile, or integrate with autoconf using the pkg.m4 macro. How do I develop against an uninstalled GStreamer copy ? It is possible to develop and compile against an uninstalled copy of gstreamer and gst-plugins (for example, against CVS copies). The easiest way to do this is to use a script like this (for bash): #!/bin/bash -i # # this script is in CVS as gstreamer/docs/faq/gst-uninstalled # # set up environment to use and develop gstreamer and friends uninstalled # # set up PATH, LD_LIBRARY_PATH, PKG_CONFIG_PATH, GST_PLUGIN_PATH, MANPATH, # PYTHONPATH # # prefer uninstalled versions, but also put installed ones on the path # # this script assumes that the relevant modules are checked out one by one # under a given tree specified below in MYGST # # symlink this script in a directory in your path (for example $HOME/bin) # to a name that reflects the version of your checkout # # e.g.: # - mkdir $HOME/gst/head # - ln -sf gst-uninstalled $HOME/bin/gst-head # - checkout copies of gstreamer modules in $HOME/gst/head # - gst-head # this script is run -i so that PS1 doesn't get cleared # change this variable to a different location depending on where you # store your cvs checkouts MYGST=$HOME/gst # extract version from $0 # if this script is called "gst-head" then version will be "head" VERSION=`echo $0 | sed s/.*gst-//g` # base path under which dirs are installed GST=$MYGST/$VERSION if test ! -e $GST; then echo "$GST does not exist !" exit fi # set up a bunch of paths PATH=$GST/gstreamer/tools:$GST/gst-plugins/tools:$GST/gst-player/src:$GST/gst-editor/src:$GST/prefix/bin:$PATH # /some/path: makes the dynamic linker look in . too, so avoid this export LD_LIBRARY_PATH=$GST/prefix/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} export PKG_CONFIG_PATH=$GST/prefix/lib/pkgconfig:$GST/gstreamer/pkgconfig:$GST/gst-plugins/pkgconfig:$GST/gst-python/pkgconfig:$PKG_CONFIG_PATH export GST_PLUGIN_PATH=$GST/gstreamer:$GST/gst-plugins:$GST/gst-ffmpeg:$GST/gst-monkeysaudio:$GST_PLUGIN_PATH export MANPATH=$GST/gstreamer/tools:$GST/prefix/share/man:$MANPATH pythonver=`python -c "import sys; print sys.version[:3]"` export PYTHONPATH=$GST/gst-python:$GST/prefix/lib/python$pythonver/site-packages:$PYTHONPATH # if we got a command, run it, else start a shell if test ! -z "$1"; then $@ exit $? fi # set up prompt to help us remember we're in a subshell, cd to # the gstreamer base dir and start $SHELL cd $GST PS1="[gst-$VERSION] $PS1" $SHELL If you put this script in your path, and symlink it to gst-cvs (if you want to develop against cvs HEAD) or to gst-0.6 (if you want to develop against the 0.6 branch), it will automatically use the uninstalled version from that directory. This requires you to have put your checkouts of gstreamer and gst-plugins under ~/gst/cvs (for the HEAD version). The program is easily modifiable if this isn't the case. After running this script, you'll be in an environment where you can use the uninstalled tools, and where gst-register registers the uninstalled plugins by default. Also, pkg-config wil detect the uninstalled copies before any installed copies. How can I use GConf to get the system-wide defaults ? It's a good idea to use GConf to use default ways of outputting audio and video. Since GStreamer's GConf keys can be more than just one element, but a whole pipeline, it would be a good idea to use the gstgconf library. It provides functions to parse the GConf key to a usable pipeline. To link against gstgconf, use pkg-config to query the gstreamer-libs-0.8.pc file for link flags, and add -lgstgconf to the link flags. This fragment of configure.ac shows how to use pkg-config to get the LIBS: dnl check for GStreamer helper libs PKG_CHECK_MODULES(GST_HELPLIBS, gstreamer-libs-0.8 >= $GSTREAMER_REQ,,exit) AC_SUBST(GST_HELPLIBS_LIBS) AC_SUBST(GST_HELPLIBS_CFLAGS) This fragment of a Makefile.am file shows how to make your application link to it: bin_PROGRAMS = application application_LDADD = $(GST_LIBS) $(GST_HELPLIBS_LIBS) -lgstgconf application_CFLAGS = $(GST_CFLAGS) $(GST_HELPLIBS_CFLAGS) How do I debug these funny shell scripts that libtool makes ? When you link a program against uninstalled GStreamer using libtool, funny shell scripts are made to modify your shared object search path and then run your program. For instance, to debug gst-launch, try libtool gdb /path/to/gstreamer-launch . If this does not work, you're probably using a broken version of libtool. Why is mail traffic so low on gstreamer-devel ? Our main arena for coordination and discussion is IRC, not email. Join us in #gstreamer on irc.freenode.net For larger picture questions or getting more input from more persons, a mail to gstreamer-devel is never a bad idea. However, we do archive our IRC discussions, which you may find in the gstreamer-daily mailing list archives. What kind of versioning scheme does GStreamer use ? For public releases, GStreamer uses a standard MAJOR.MINOR.MICRO version scheme. If the release consists of mostly bug fixes or incremental changes, the MICRO version is incremented. If the release contains big changes, the MINOR version is incremented. If we're particularly giddy, we might even increase the MAJOR number. Don't hold your breath for that though. During the development cycle, GStreamer also uses a fourth or NANO number. If this number is 1, then it's a CVS version. Any tarball or package that has a nano number of 1 is made from CVS and thus not supported. Additionally, if you didn't get this package or tarball from the GStreamer team, don't have high hopes on it doing whatever you want it to do. If the number is 2 or higher, it's an official pre-release in preparation of an actual complete release. Your help in testing these tarballs and packages is very much appreciated. What is the coding style for GStreamer core ? The core is basically coded in K&R with 2-space indenting. Just follow what's already there and you'll be fine. The core could use a code cleanup though at this point. Individual plugins in gst-plugins or plugins that you want considered for addition to the gst-plugins module should be coded in the same style. It's easier if everything is consistent. Consistency is, of course, the goal. If you use emacs, try these lines: (defun gstreamer-c-mode () "C mode with adjusted defaults for use with GStreamer." (interactive) (c-mode) (c-set-style "K&R") (setq c-basic-offset 2)) (setq auto-mode-alist (cons '("gst.*/.*\\.[ch]$" . gstreamer-c-mode) auto-mode-alist)) Or, run your code through indent -br -bad -cbi0 -cli2 -bls -l100 -ut -ce before submitting a patch (FIXME: check if these are indeed the proper options). As for the code itself, the GNOME coding guidelines is a good read. Where possible, we try to adhere to the spirit of GObject and use similar coding idioms. GStreamer Legal Issues This part of the FAQ is based on a series of questions we asked the FSF to understand how the GPL works and how patents affects the GPL. These questions were answered by the FSF lawyers, so we view them as the final interpretation on how the GPL and LGPL interact with patents in our opinion. This consultancy was paid for by Fluendo in order to obtain clear and quotable answers. These answers were certified by the FSF lawyer team and verified by FSF lawyer and law professor Eben Moglen. Can someone distribute the combination of GStreamer, the LGPL libraryTotem, a GPL playback applicationThe binary-only Sorenson decoder together in one distribution/operating system ? If not, what needs to be changed to make this possible ? This would be a problem, because the GStreamer and Totem licenses would forbid it. In order to link GStreamer to Totem, you need to use section 3 of the LGPL to convert GStreamer to GPL. The GPL version of GStreamer forbids linking to the Sorenson decoder. Anyway, the Totem GPL license forbids this. If the authors of Totem want to permit this, we have an exception for them: the controlled interface exception from the FAQ. The idea of this is that you can't get around the GPL just by including a LGPL bit in the middle. Suppose Apple wants to write a binary-only proprietary plugin for GStreamer to decode Sorenson video, which will be shipped stand-alone, not part of a package like in the question above. Can Apple distribute this binary-only plugin ? Yes, modulo certain reverse engineering requirements in section 6 of the LGPL. If a program released under the GPL uses a library that is LGPL, and this library can dlopen plug-ins at runtime, what are the requirements for the license of the plug-in ? You may not distribute the plug-in with the GPL application. Distributing the plug-in alone, with the knowledge that it will be used primarily by GPL software is a bit of an edge case. We will not advise you that it would be safe to do so, but we also will not advise you that it would be absolutely forbidden. Can someone in a country that does not have software patents distribute code covered by US patents under the GPL to people in, for example, Norway ? If he/she visits the US, can he/she be arrested ? Yes, he can. No, there are no criminal penalties for patent infringement in the US. Can someone from the US distribute software covered by US patents under the GPL to people in Norway ? To people in the US ? This might infringe some patents, but the GPL would not forbid it absent some actual restriction, such as a court judgement or agreement. The US government is empowered to refuse importation of patent infringing devices, including software. There are a lot of GPL- or LGPL-licensed libraries that handle media codecs which have patents. Take mad, an mp3 decoding library, as an example. It is licensed under the GPL. In countries where patents are valid, does this invalidate the GPL license for this project ? The mere existence of a patent which might read on the program does not change anything. However, if a court judgement or other agreement prevents you from distributing libmad under GPL terms, you can not distribute it at all. The GPL and LGPL say (sections 7 and 11): If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. So let's say there is a court judgement. Does this mean that the GPL license is invalid for the project everywhere, or only in the countries where it conflicts with the applicable patents ? The GPL operates on a per-action, not per-program basis. That is, if you are in a country which has software patents, and a court tells you that you cannot distribute (say) libmad in source code form, then you cannot distribute libmad at all. This doesn't affect anyone else. Patented decoding can be implemented in GStreamer either by having a binary-only plugin do the decoding, or by writing a plugin (with any applicable license) that links to a binary-only library. Does this affect the licensing issues involved in regards to GPL/LGPL? No. Is it correct that you cannot distribute the GPL mad library to decode mp3's, *even* in the case where you have obtained a valid license for decoding mp3 ? The only GPL-compatible patent licenses are those which are open to all parties posessing copies of GPL software which practices the teachings of the patent. If you take a license which doesn't allow others to distribute original or modified versions of libmad practicing the same patent claims as the version you distribute, then you may not distribute at all. Done. Copying .css files: base.css make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' make[3]: Nothing to be done for `install-exec-am'. make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' cd build && xmllint -noout -valid faq.xml make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq/build/faq.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" GStreamer FAQ (0.8.11) This is the FAQ for GStreamer, a multimedia framework. Questions and answers range from general information to deep-down-and-dirty compilation issues. 0.1.12003-04-24Added Q&A about developing with uninstalled copy.0.1.02002-10-01Initial conversion from FAQ database.Getting Started So you're eager to get started learning about GStreamer. There's a few ways you can get started. If you want to learn by reading about it, start with If you'd rather learn by trying it out, start with If you want to live on the bleeding edge and develop and use CVS, see GeneralIs GStreamer a media player ? No, GStreamer is a development framework for creating applications like media players, video editors, streaming media broadcasters and so on. That said, very good media players can easily be built on top of GStreamer and we even include a simple yet functional media player with GStreamer, called gst-player. Why is GStreamer written in C ? Why not C++/Objective-C/... ? We like C. Aside from "personal preference", there are a number of technical reasons why C is nice in this project: C is extremely portable.C is fast.It is easy to make language bindings for libraries written in C. The GObject object system provided by GLib implements objects in C, in a portable, powerful way. This library provides for introspection and runtime dynamic typing. It is a full OO system, but without the syntactic sugar. If you want sugar, take a look at GOB.Use of C integrates nicely with Gtk+ and GNOME. Some people like this a lot, but neither Gtk+ nor GNOME are required by GStreamer. So, in closing, we like C. If you don't, that's fine; if you still want to help out on GStreamer, we always need more language binding people. And if not, don't bother us; we're working :-) What applications are available for GStreamer ? GStreamer is still very early in its development, but already we see some really nice applications being developed in parallel with GStreamer. Both gst-player and gst-editor are very closely linked to GStreamer itself for obvious reasons. Does GStreamer support the format of my media files? GStreamer aims to support every format imaginable, but that doesn't mean the developers have managed to achieve that aim yet. If a GStreamer enabled application doesn't play back your files, you can help us solve that problem by filing an enhancement request bug for that format. If you have it, please provide: links to other players, preferrably Open Source and working on Unixlinks to explanations of the format.ways to obtain mediafiles in that format to test. What are the exact licensing terms for GStreamer and its plugins ? All of GStreamer, including our own plugin code, is licensed under the GNU LGPL license. Some of the libraries we use for some of the plugins are however under the GPL, which means that those plugins can not be used by a non-GPL-compatible application. As part of the GStreamer source download you find a file called LICENSE_readme in gst-plugins package. That file contains information in the exact licensing terms of the libraries we use. As a general rule, GStreamer aims at using only LGPL or BSD licensed libraries if available and only use GPL or proprietary libraries where no good LGPL or BSD alternatives are available. From GStreamer 0.4.2 on, we implemented a license field for all of the plugins, and in the future we might have the application enforce a stricter policy (much like tainting in the kernel). Is GStreamer a sound server ? No, GStreamer is not a soundserver. GStreamer does however have plugins supporting most of the major soundservers available today, including ESD, aRTSd, and to some extent Jack. Support for MAS is also planned. Will GStreamer be available for platforms other than Unix ? Depends. Our main target is the Unix platform. That said, interest has been expressed in porting GStreamer to other platforms and the GStreamer core team will gladly accept patches to accomplish this. What is GStreamer's relationship with the GNOME community ? While GStreamer is operated as an independent project, we do have a close relationship with the GNOME community. Many of our hackers consider themselves also to be members of the GNOME community. There are plans to make (some part of) GStreamer an official part of the development framework of GNOME. This does not exclude use of GStreamer by other communities at all, of course. What is GStreamer's relationship with the KDE community ? The GStreamer community wants to have as good a relationship as possible with KDE, and we hope that someday KDE decides to adopt GStreamer as their multimedia API, just like the GNOME community plans on doing. There have been contacts from time to time between the GStreamer community and KDE and we do already have support for the aRTSd sound server used by KDE. Also, some of the KDE hackers have created Qt bindings of GStreamer and made a simple video player. I'm considering adding GStreamer output to my application... That doesn't really make sense. GStreamer is not a sound server, so you don't output directly to GStreamer, and it's not an intermediate API between audio data and different kinds of audio sinks. It is a fundamental design decision to use GStreamer in your app; there are no easy ways of somehow 'transfering' data from your app to GStreamer. Instead, your app would have to use or implement a number of GStreamer elements, string them together, and tell them to run. In that manner the data would all be internal to the GStreamer pipeline. That said, it is possible to write a plugin specific to your app that can get at the audio data. DependenciesWhy are there so many dependencies ? Making a full-featured media framework is a huge undertaking in itself. By using the work done by others, we both reduce the amount of redundant work being done and leave ourselves free to work on the architecture itself instead of working on the low-level stuff. We would be stupid not to reuse the code others have written. However, do realize that in no way you are forced to have all dependencies installed. None of the core developers has all of them installed. GStreamer has only a few obligate dependencies : GLib 2.0, popt >= 1.6.0, and very common stuff like glibc, a C compiler, and so on. All of the other dependencies are optional. So, in closing, let's rephrase the question to Why are you giving me so many choices and such a rich environment ? Does GStreamer use GTK+ 1.2/GLib 1.2 or GLib 2.0 ? Since the 0.3.3 release of GStreamer, we use GLib 2.0 as the core library for GStreamer, which features a move of GObject from GTK+ 2.0 to GLib 2.0. If you want to compile using GTK+ 1.2/GLib 1.2, you need to get the 0.3.1 or earlier release. It is of course not supported. Does GStreamer offer support for DVD decoder cards like dxr2/3 ? We do have support for the dxr3, although dxr2 support is unknown. GStreamer can easily accomodate hardware acceleration by writing new device-specific elements. Is GStreamer X independent ? Yes, we have no X dependency in any of our core modules. There are GStreamer applications that run fine without any need for X. However, until our Linux Framebuffer or libsvga plugin is ready, you will not be able to play videos without X. In the future, there will probably be lots of different output plugins for video available. What is GStreamer's position on efforts such as LADSPA ? GStreamer actively supports such efforts, and in the case of LADPSA, we already have a wrapper plugin. This wrapper plug-in detects the LADSPA plugins present on your system at register time. Does GStreamer support MIDI ? Not yet. The GStreamer architecture should be able to support the needs of MIDI applications very well however. If you are a developer interested in adding MIDI support to GStreamer we are very interested in getting in touch with you. Does GStreamer depend on GNOME ? No. But many of the applications developed for GStreamer do, including our sample applications. There is nothing hindering people from developing applications using other toolkits however and we would happily help promote such efforts. A good example of an application using GStreamer, but which is not using GNOME is the Mozstreamer which uses Mozilla XUL. Getting GStreamerHow do I get GStreamer ? Generally speaking, you have three options, ranging from easy to hard : distribution-specific packages source tarballs CVS How can I install GStreamer from source ? We provide tarballs of our releases on our own site, at http://gstreamer.freedesktop.org/src/ When compiling from source, make sure you specify PKG_CONFIG_PATH correctly when building against GStreamer. For example, if you configured GStreamer with the default prefix (which is /usr/local), then you need to export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig before building gst-plugins. Are there premade binaries available ? Yes, we currently provide precompiled packages for Red Hat, Debian and Linux Mandrake. We provide RPMS for Red Hat and Fedora Core through our Apt for rpm page. We usually support the last 2-3 releases of Red Hat. (RH9 and FC1) GStreamer is already in Debian experimental, so if you are a debian user you should be able to get the Debian packages from there.GStreamer is also in Mandrake Cooker so if you are using a recent release of Linux Mandrake you should be able to get GStreamer from there. To learn howto get packages from Mandrake cooker the Mandrake cooker page has more info For other RPM based distributions we recommend getting the source tarball and doing 'rpm -ta gstreamer-0.X.X' to create rpms. We keep our SPEC file constantly up to date so you should always be able to build GStreamer rpms from a tarball. The SPEC file is aimed at Red Hat however, so there might be some need for you to edit the Requirements list if your distribution name these packages differently.Why don't you provide premade binaries for distribution XY ? GStreamer is run on a volunteer basis. The package that are provided are made by non-paid people who do this on their own time. The distributions we support with binaries are the distributions that we have people who have volunteered to make binaries for. If you are interested in maintaining GStreamer binaries for other distributions or Unices we would be happy to hear from you. Contact us through the GStreamer-devel mailing list. I am having trouble compiling GStreamer on my LFS installation, why ? If you are running LFS our basic opinion is that you should be knowledgeable enough to solve any build issues you get on your own. Being volunteered based we can't promise support to anyone of course, but are you using LFS consider yourself extra unsupported. We neither can or want to know enough, about how your unique system is configured, to be able to help you. That said, if you come to the #gstreamer channel on irc.openprojects.net we might of course be able to give you some general hints and pointers. How do I get GStreamer through CVS ? see this page : http://gstreamer.freedesktop.org/dev/ for CVS access. (anonymous and developer) Using GStreamerOk, I've installed GStreamer. What can I do next ? First of all, verify that you have a working registry and that you can inspect them by typing $ gst-inspect fakesrc This should print out a bunch of information about this particular element. If this tells you that there is "no such element or plugin", you haven't installed GStreamer correctly. Please check how to get GStreamer If this fails with any other message, we would appreciate a bug report. It's time to try out a few things. Start with gst-launch and two plug-ins that you really should have : fakesrc and fakesink. They do nothing except pass empty buffers. Type this at the command-line : $ gst-launch -v fakesrc num-buffers=3 ! fakesink This will print out output that looks similar to this : RUNNING pipeline ... fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 0) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 0) 0x8057510" fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 1) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 1) 0x8057510" fakesrc0: last-message = "get ******* (fakesrc0:src)gt; (0 bytes, 2) 0x8057510" fakesink0: last-message = "chain ******* (fakesink0:sink)lt; (0 bytes, 2) 0x8057510" execution ended after 5 iterations (sum 301479000 ns, average 60295800 ns, min 3000 ns, max 105482000 ns) (Some parts of output have been removed for clarity) If it looks similar, then GStreamer itself is running correctly. Can my system play sound through GStreamer ? You can test this by trying to play a sine tone. For this, you need to link the sinesrc plug-in to an output plug-in that matches your hardware. A (non-complete) list of output plug-ins for audio is osssink for OSS outputesdsink for ESound outputartsdsink for aRTs outputalsasink for ALSA outputjacksink for JACK output First of all, run gst-inspect on the output plug-in you want to use to make sure you have it installed. For example, if you use OSS, run $ gst-inspect osssink and see if that prints out a bunch of properties for the plug-in. Then try to play the sine tone by running $ gst-launch sinesrc ! osssink and see if you hear something. Make sure your volume is turned up, but also make sure it is not too loud and you are not wearing your headphones. In GNOME, you can configure audio output for most applications by running $ gstreamer-properties which can also be found in the start menu (Applications -> Preferences -> Multimedia Systems Selector). In KDE, there is not yet a shared way of setting audio output for all applications; however, applications such as Amarok allow you to specify an audio output in their preferences dialog. How can I see what GStreamer plugins I have on my system ? To do this you use the gst-inspect command-line tool, which comes standard with GStreamer. Invoked without any arguments, $ gst-inspect will print out a listing of installed plugins. To learn more about a particular plugin, pass its name on the command line. For example, $ gst-inspect volume will give you information about the volume plugin. Also, if you install the gst-editor package, you will have a graphical plugin browser available, gst-inspect-gui. Where should I report bugs ? Bug management is now hosted on GNOME's Bugzilla at http://bugzilla.gnome.org, under the product GStreamer. Using bugzilla you can view past bug history, report new bugs, etc. Bugzilla requires you to make an account here, which might seem cumbersome, but allows us to at least have a chance at contacting you for further information, as we will most likely have to. How should I report bugs ? When doing a bug report, you should at least describe your distribution how you installed GStreamer (from cvs, source, packages, which ?)if you installed GStreamer before It also is useful for us if you attach output of the gst-feedback command to your bug report. If you're having problem with a specific application (either one of ours, somebody else's, or your own), please also provide a log of gst-mask by running myapp --gst-mask=-1 > mask.log 2>&1 gzip mask.log (interrupting the program if it doesn't stop by itself) and attach mask.log.gz to your bug report. If the application you are having problems with is segfaulting, then provide us with the necessary gdb output. See How do I use the GStreamer command line interface ? You access the GStreamer command line interface using the command gst-launch. To decode an mp3 and play it through OSS, you could use gst-launch filesrc location=thesong.mp3 ! mad ! osssink . More examples can be found in the gst-launch man page. To automatically detect the right codec in a pipeline, try gst-launch filesrc location=my-random-media-file.mpeg ! spider ! osssink . Try replacing osssink with sdlvideosink and see what happens. We also have a simple tool called gst-launch-ext used for debugging, which has predefined pipelines for you. This means you can just write gst-launch-ext (filename) and it will play the file if the extension is supported. Note that no effort has been made for uninterrupted synchronized playback using this tool. Troubleshooting GStreamer My GStreamer-based application crashes on startup with errors about unfound schedulers on the command-line. I get undefined behaviour as soon as any GStreamer element is being initialized. Your registry is probably missing, or it is outdated (i.e. not updated after a recent upgrade). Fix this by running gst-register yourself: gst-register In the worst case, you might have to run it both as user and as root. Note that package managers are suggested to run this automatically during the post-installation. Our RPMs and Debian packages do just that. Some application is telling me that I am missing a plug-in. What do I do ? Well, start by checking if you really are missing the plug-in. gst-inspect (plug-in) and replace (plug-in) with the plug-in you think is missing. If this doesn't return any result, then you either don't have it or your registry cannot find it. If you're not sure either way, then chances are good that you don't have it. You should get the plug-in and run gst-register to register it. How to get the plug-in depends on your distribution. if you run GStreamer using packages for your distribution, you should check what packages are available for your distribution and see if any of the available packages contains the plug-in. if you run GStreamer from a source install, there's a good chance the plug-in didn't get built because you are missing an external library. When you ran configure, you should have gotten output of what plug-ins are going to be built. You can re-run configure to see if it's there. If it isn't, there is a good reason why it is not getting built. The most likely is that you're missing the library you need for it. Check the README file in gst-plugins to see what library you need. Make sure to remember to re-run configure after installing the supporting library ! if you run GStreamer from CVS, the same logic applies as for a source install. Go over the reasons why the plug-in didn't get configured for build. Check output of config.log for a clue as to why it doesn't get built if you're sure you have the library needed installed in a sane place. I get an error that says something like (process:26626): GLib-GObject-WARNING **: specified instance size for type `DVDReadSrc' is smaller than the parent type's `GstElement' instance size What's wrong ? If you run GStreamer CVS uninstalled, it means that something changed in the core that requires a recompilation in the plugins. Recompile the plugins by doing "make clean && make". If you run GStreamer installed, it probably means that you run the plugins against a different (incompatible) version than they were compiled against, which ususally means that you run multiple installations of GStreamer. Remove the old ones and - if needed - recompile again to ensure that it is using the right version. Note that we strongly recommend using Debian or RPM packages, since you will not get such issues if you use provided packages. The GStreamer application I used stops with a segmentation fault. What can I do ? There are two things you can do. If you compiled GStreamer with specific optimization compilation flags, you should try recompiling GStreamer, the application and the plug-ins without any optimization flags. This allows you to verify if the problem is due to optimization or due to bad code. Second, it will also allow you to provide a reasonable backtrace in case the segmentation fault still occurs. The second thing you can do is look at the backtrace to get an idea of where things are going wrong, or give us an idea of what is going wrong. To provide a backtrace, you should run the application in gdb by starting it with gdb (gst-application) (If the application is in a source tree instead of installed on the system, you might want to put "libtool" before "gdb") Pass on the command line arguments to the application by typing set args (the arguments to the application) at the (gdb) prompt Type "run" at the (gdb) prompt and wait for the application to segfault. The application will run a lot slower, however. After the segfault, type "bt" to get a backtrace. This is a stack of function calls detailing the path from main () to where the code is currently at. If the application you're trying to debug contains threads, it is also useful to do info threads and get backtraces of all of the threads involved, by switching to a different thread using "thread (number)" and then again requesting a backtrace using "bt". If you can't or don't want to work out the problem yourself, a copy and paste of all this information should be included in your bug report. Building GStreamer from CVS How do I check out GStreamer from CVS ? GStreamer is hosted on Freedesktop.org. GStreamer consists of various parts. In the beginning, you will be interested in the "gstreamer" module, containing the core, and "gst-plugins", containing the basic set of plugins. To check out the HEAD version of the core, use cvs -d:pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer co gstreamer This will create a directory "gstreamer" in your current directory. If you want to get another module, replace the last "gstreamer" with the name of the module. How do I get developer access to GStreamer CVS ? If you want to gain developer access to GStreamer CVS, you should ask for it on the development lists, or ask one of the maintainers directly. If you are not already a registered developer with a user account on Freedesktop.org, You will then have to provide them with: your desired unix usernameyour full nameyour e-mail addressa copy of your public sshv2 identity. If you do not have this yet, you can generate it by running "ssh-keygen -t dsa". The resulting public key will be in .ssh/id_dsa.pub(optionally) your GPG fingerprint. This would allow you to add and remove ssh keys to your account. I ran autogen.sh, but it fails with something like this: + running aclocal -I m4 -I common/m4 ... aclocal: configure.ac: 8: macro `AM_DISABLE_STATIC' not found in library aclocal: configure.ac: 17: macro `AM_PROG_LIBTOOL' not found in library aclocal failed What's wrong ? aclocal is unable to find two macros installed by libtool in a file called libtool.m4. Normally this would indicate that you don't have libtool, but that would mean autogen.sh would have failed on not finding libtool. It is more likely that you installed automake (which provides aclocal) in a different prefix than libtool. You can check this by examining in what prefix both aclocal and libtool are installed. You can do three things to fix this : install automake in the same prefix as libtoolforce use of the automake installed in the same prefix as libtool by using the --with-automake optionfigure out what prefix libtool has been installed to and point aclocal to the right location by running export ACLOCAL_FLAGS="-I $(prefix)/share/aclocal" where you replace prefix with the prefix where libtool was installed. Developing applications with GStreamerHow do I compile programs that use GStreamer ? GStreamer uses pkg-config to assist applications with compilationa and linking flags. pkg-config is already used by GTK+, GNOME, SDL, and others; so if you are familiar with using it for any of those, you're set. If you're not familiar with pkg-config to compile and link a small one-file program, pass the --cflags and --libs arguments to pkg-config. For example: $ libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.8` -o myprog myprog.c would be sufficient for a gstreamer-only program. If (for example) your app also used GTK+ 2.0, you could use $ libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.8 gtk+-2.0` -o myprog myprog.c Those are back-ticks (on the same key with the tilde on US keyboards), not single quotes. For bigger projects, you should integrate pkg-config use in your Makefile, or integrate with autoconf using the pkg.m4 macro. How do I develop against an uninstalled GStreamer copy ? It is possible to develop and compile against an uninstalled copy of gstreamer and gst-plugins (for example, against CVS copies). The easiest way to do this is to use a script like this (for bash): #!/bin/bash -i # # this script is in CVS as gstreamer/docs/faq/gst-uninstalled # # set up environment to use and develop gstreamer and friends uninstalled # # set up PATH, LD_LIBRARY_PATH, PKG_CONFIG_PATH, GST_PLUGIN_PATH, MANPATH, # PYTHONPATH # # prefer uninstalled versions, but also put installed ones on the path # # this script assumes that the relevant modules are checked out one by one # under a given tree specified below in MYGST # # symlink this script in a directory in your path (for example $HOME/bin) # to a name that reflects the version of your checkout # # e.g.: # - mkdir $HOME/gst/head # - ln -sf gst-uninstalled $HOME/bin/gst-head # - checkout copies of gstreamer modules in $HOME/gst/head # - gst-head # this script is run -i so that PS1 doesn't get cleared # change this variable to a different location depending on where you # store your cvs checkouts MYGST=$HOME/gst # extract version from $0 # if this script is called "gst-head" then version will be "head" VERSION=`echo $0 | sed s/.*gst-//g` # base path under which dirs are installed GST=$MYGST/$VERSION if test ! -e $GST; then echo "$GST does not exist !" exit fi # set up a bunch of paths PATH=$GST/gstreamer/tools:$GST/gst-plugins/tools:$GST/gst-player/src:$GST/gst-editor/src:$GST/prefix/bin:$PATH # /some/path: makes the dynamic linker look in . too, so avoid this export LD_LIBRARY_PATH=$GST/prefix/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} export PKG_CONFIG_PATH=$GST/prefix/lib/pkgconfig:$GST/gstreamer/pkgconfig:$GST/gst-plugins/pkgconfig:$GST/gst-python/pkgconfig:$PKG_CONFIG_PATH export GST_PLUGIN_PATH=$GST/gstreamer:$GST/gst-plugins:$GST/gst-ffmpeg:$GST/gst-monkeysaudio:$GST_PLUGIN_PATH export MANPATH=$GST/gstreamer/tools:$GST/prefix/share/man:$MANPATH pythonver=`python -c "import sys; print sys.version[:3]"` export PYTHONPATH=$GST/gst-python:$GST/prefix/lib/python$pythonver/site-packages:$PYTHONPATH # if we got a command, run it, else start a shell if test ! -z "$1"; then $@ exit $? fi # set up prompt to help us remember we're in a subshell, cd to # the gstreamer base dir and start $SHELL cd $GST PS1="[gst-$VERSION] $PS1" $SHELL If you put this script in your path, and symlink it to gst-cvs (if you want to develop against cvs HEAD) or to gst-0.6 (if you want to develop against the 0.6 branch), it will automatically use the uninstalled version from that directory. This requires you to have put your checkouts of gstreamer and gst-plugins under ~/gst/cvs (for the HEAD version). The program is easily modifiable if this isn't the case. After running this script, you'll be in an environment where you can use the uninstalled tools, and where gst-register registers the uninstalled plugins by default. Also, pkg-config wil detect the uninstalled copies before any installed copies. How can I use GConf to get the system-wide defaults ? It's a good idea to use GConf to use default ways of outputting audio and video. Since GStreamer's GConf keys can be more than just one element, but a whole pipeline, it would be a good idea to use the gstgconf library. It provides functions to parse the GConf key to a usable pipeline. To link against gstgconf, use pkg-config to query the gstreamer-libs-0.8.pc file for link flags, and add -lgstgconf to the link flags. This fragment of configure.ac shows how to use pkg-config to get the LIBS: dnl check for GStreamer helper libs PKG_CHECK_MODULES(GST_HELPLIBS, gstreamer-libs-0.8 >= $GSTREAMER_REQ,,exit) AC_SUBST(GST_HELPLIBS_LIBS) AC_SUBST(GST_HELPLIBS_CFLAGS) This fragment of a Makefile.am file shows how to make your application link to it: bin_PROGRAMS = application application_LDADD = $(GST_LIBS) $(GST_HELPLIBS_LIBS) -lgstgconf application_CFLAGS = $(GST_CFLAGS) $(GST_HELPLIBS_CFLAGS) How do I debug these funny shell scripts that libtool makes ? When you link a program against uninstalled GStreamer using libtool, funny shell scripts are made to modify your shared object search path and then run your program. For instance, to debug gst-launch, try libtool gdb /path/to/gstreamer-launch . If this does not work, you're probably using a broken version of libtool. Why is mail traffic so low on gstreamer-devel ? Our main arena for coordination and discussion is IRC, not email. Join us in #gstreamer on irc.freenode.net For larger picture questions or getting more input from more persons, a mail to gstreamer-devel is never a bad idea. However, we do archive our IRC discussions, which you may find in the gstreamer-daily mailing list archives. What kind of versioning scheme does GStreamer use ? For public releases, GStreamer uses a standard MAJOR.MINOR.MICRO version scheme. If the release consists of mostly bug fixes or incremental changes, the MICRO version is incremented. If the release contains big changes, the MINOR version is incremented. If we're particularly giddy, we might even increase the MAJOR number. Don't hold your breath for that though. During the development cycle, GStreamer also uses a fourth or NANO number. If this number is 1, then it's a CVS version. Any tarball or package that has a nano number of 1 is made from CVS and thus not supported. Additionally, if you didn't get this package or tarball from the GStreamer team, don't have high hopes on it doing whatever you want it to do. If the number is 2 or higher, it's an official pre-release in preparation of an actual complete release. Your help in testing these tarballs and packages is very much appreciated. What is the coding style for GStreamer core ? The core is basically coded in K&R with 2-space indenting. Just follow what's already there and you'll be fine. The core could use a code cleanup though at this point. Individual plugins in gst-plugins or plugins that you want considered for addition to the gst-plugins module should be coded in the same style. It's easier if everything is consistent. Consistency is, of course, the goal. If you use emacs, try these lines: (defun gstreamer-c-mode () "C mode with adjusted defaults for use with GStreamer." (interactive) (c-mode) (c-set-style "K&R") (setq c-basic-offset 2)) (setq auto-mode-alist (cons '("gst.*/.*\\.[ch]$" . gstreamer-c-mode) auto-mode-alist)) Or, run your code through indent -br -bad -cbi0 -cli2 -bls -l100 -ut -ce before submitting a patch (FIXME: check if these are indeed the proper options). As for the code itself, the GNOME coding guidelines is a good read. Where possible, we try to adhere to the spirit of GObject and use similar coding idioms. GStreamer Legal Issues This part of the FAQ is based on a series of questions we asked the FSF to understand how the GPL works and how patents affects the GPL. These questions were answered by the FSF lawyers, so we view them as the final interpretation on how the GPL and LGPL interact with patents in our opinion. This consultancy was paid for by Fluendo in order to obtain clear and quotable answers. These answers were certified by the FSF lawyer team and verified by FSF lawyer and law professor Eben Moglen. Can someone distribute the combination of GStreamer, the LGPL libraryTotem, a GPL playback applicationThe binary-only Sorenson decoder together in one distribution/operating system ? If not, what needs to be changed to make this possible ? This would be a problem, because the GStreamer and Totem licenses would forbid it. In order to link GStreamer to Totem, you need to use section 3 of the LGPL to convert GStreamer to GPL. The GPL version of GStreamer forbids linking to the Sorenson decoder. Anyway, the Totem GPL license forbids this. If the authors of Totem want to permit this, we have an exception for them: the controlled interface exception from the FAQ. The idea of this is that you can't get around the GPL just by including a LGPL bit in the middle. Suppose Apple wants to write a binary-only proprietary plugin for GStreamer to decode Sorenson video, which will be shipped stand-alone, not part of a package like in the question above. Can Apple distribute this binary-only plugin ? Yes, modulo certain reverse engineering requirements in section 6 of the LGPL. If a program released under the GPL uses a library that is LGPL, and this library can dlopen plug-ins at runtime, what are the requirements for the license of the plug-in ? You may not distribute the plug-in with the GPL application. Distributing the plug-in alone, with the knowledge that it will be used primarily by GPL software is a bit of an edge case. We will not advise you that it would be safe to do so, but we also will not advise you that it would be absolutely forbidden. Can someone in a country that does not have software patents distribute code covered by US patents under the GPL to people in, for example, Norway ? If he/she visits the US, can he/she be arrested ? Yes, he can. No, there are no criminal penalties for patent infringement in the US. Can someone from the US distribute software covered by US patents under the GPL to people in Norway ? To people in the US ? This might infringe some patents, but the GPL would not forbid it absent some actual restriction, such as a court judgement or agreement. The US government is empowered to refuse importation of patent infringing devices, including software. There are a lot of GPL- or LGPL-licensed libraries that handle media codecs which have patents. Take mad, an mp3 decoding library, as an example. It is licensed under the GPL. In countries where patents are valid, does this invalidate the GPL license for this project ? The mere existence of a patent which might read on the program does not change anything. However, if a court judgement or other agreement prevents you from distributing libmad under GPL terms, you can not distribute it at all. The GPL and LGPL say (sections 7 and 11): If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. So let's say there is a court judgement. Does this mean that the GPL license is invalid for the project everywhere, or only in the countries where it conflicts with the applicable patents ? The GPL operates on a per-action, not per-program basis. That is, if you are in a country which has software patents, and a court tells you that you cannot distribute (say) libmad in source code form, then you cannot distribute libmad at all. This doesn't affect anyone else. Patented decoding can be implemented in GStreamer either by having a binary-only plugin do the decoding, or by writing a plugin (with any applicable license) that links to a binary-only library. Does this affect the licensing issues involved in regards to GPL/LGPL? No. Is it correct that you cannot distribute the GPL mad library to decode mp3's, *even* in the case where you have obtained a valid license for decoding mp3 ? The only GPL-compatible patent licenses are those which are open to all parties posessing copies of GPL software which practices the teachings of the patent. If you take a license which doesn't allow others to distribute original or modified versions of libmad practicing the same patent claims as the version you distribute, then you may not distribute at all. Done. Copying .css files: base.css /bin/sh ../../mkinstalldirs /usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc mkdir /usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc cp -pr html /usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc test -z "/usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc" || mkdir -p -- "/usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc" make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/faq' Making install in manual make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' cd build && xmllint -noout -valid manual.xml make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual/build/manual.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" WimTaymans wim.taymans@chello.be SteveBaker stevebaker_org@yahoo.co.uk AndyWingo wingo@pobox.com RonaldS.Bultje rbultje@ronald.bitfreak.net This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/opl.shtml). GStreamer Application Development Manual (0.8.11)Overview GStreamer is an exremely powerful and versatile framework for creating streaming media applications. Many of the virtues of the GStreamer framework come from its modularity: GStreamer can seamlessly incorporate new plugin modules. But because modularity and power often come at a cost of greater complexity (consider, for example, CORBA), writing new applications is not always easy. This guide is intended to help you understand the GStreamer framework (version 0.8.11) so you can develop applications based on it. The first chapters will focus on development of a simple audio player, with much effort going into helping you understand GStreamer concepts. Later chapters will go into more advanced topics related to media playback, but also at other forms of media processing (capture, editing, etc.). Introduction This chapter gives you an overview of the technologies described in this book. What is GStreamer? GStreamer is a framework for creating streaming media applications. The fundamental design comes from the video pipeline at Oregon Graduate Institute, as well as some ideas from DirectShow. GStreamer's development framework makes it possible to write any type of streaming multimedia application. The GStreamer framework is designed to make it easy to write applications that handle audio or video or both. It isn't restricted to audio and video, and can process any kind of data flow. The pipeline design is made to have little overhead above what the applied filters induce. This makes GStreamer a good framework for designing even high-end audio applications which put high demands on latency. One of the the most obvious uses of GStreamer is using it to build a media player. GStreamer already includes components for building a media player that can support a very wide variety of formats, including MP3, Ogg/Vorbis, MPEG-1/2, AVI, Quicktime, mod, and more. GStreamer, however, is much more than just another media player. Its main advantages are that the pluggable components can be mixed and matched into arbitrary pipelines so that it's possible to write a full-fledged video or audio editing application. The framework is based on plugins that will provide the various codec and other functionality. The plugins can be linked and arranged in a pipeline. This pipeline defines the flow of the data. Pipelines can also be edited with a GUI editor and saved as XML so that pipeline libraries can be made with a minimum of effort. The GStreamer core function is to provide a framework for plugins, data flow and media type handling/negotiation. It also provides an API to write applications using the various plugins. Structure of this Manual This book is about GStreamer from a developer's point of view; it describes how to write a GStreamer application using the GStreamer libraries and tools. For an explanation about writing plugins, we suggest the Plugin Writers Guide. gives you an overview of GStreamer's motivation design goals. rapidly covers the basics of GStreamer application programming. At the end of that chapter, you should be able to build your own audio player using GStreamer In , we will move on to complicated subjects which make GStreamer stand out of its competitors. We will discuss application-pipeline interaction using dynamic parameters and interfaces, we will discuss threading and threaded pipelines, scheduling and clocks (and synchronization). Most of those topics are not just there to introduce you to their API, but primarily to give a deeper insight in solving application programming problems with GStreamer and understanding their concepts. Next, in , we will go into higher-level programming APIs for GStreamer. You don't exactly need to know all the details from the previous parts to understand this, but you will need to understand basic GStreamer concepts nevertheless. We will, amongst others, discuss XML, playbin and autopluggers. In , you will find some random information on integrating with GNOME, KDE, OS X or Windows, some debugging help and general tips to improve and simplify GStreamer programming. In order to understand this manual, you will need to have a basic understanding of the C language. Since GStreamer uses GLib 2.0, the reader is assumed to understand the basics of the GObject object model. It is recommended to have skimmed through the introduction of the GObject tutorial before reading this. You may also want to have a look at Eric Harlow's book Developing Linux Applications with GTK+ and GDK. Motivation & Goals Linux has historically lagged behind other operating systems in the multimedia arena. Microsoft's Windows and Apple's MacOS both have strong support for multimedia devices, multimedia content creation, playback, and realtime processing. Linux, on the other hand, has a poorly integrated collection of multimedia utilities and applications available, which can hardly compete with the professional level of software available for MS Windows and MacOS. GStreamer was designed to provide a solution to the current Linux media problems. Current problems We describe the typical problems in today's media handling on Linux. Multitude of duplicate code The Linux user who wishes to hear a sound file must hunt through their collection of sound file players in order to play the tens of sound file formats in wide use today. Most of these players basically reimplement the same code over and over again. The Linux developer who wishes to embed a video clip in their application must use crude hacks to run an external video player. There is no library available that a developer can use to create a custom media player. 'One goal' media players/libraries Your typical MPEG player was designed to play MPEG video and audio. Most of these players have implemented a complete infrastructure focused on achieving their only goal: playback. No provisions were made to add filters or special effects to the video or audio data. If you want to convert an MPEG-2 video stream into an AVI file, your best option would be to take all of the MPEG-2 decoding algorithms out of the player and duplicate them into your own AVI encoder. These algorithms cannot easily be shared across applications. Attempts have been made to create libraries for handling various media types. Because they focus on a very specific media type (avifile, libmpeg2, ...), significant work is needed to integrate them due to a lack of a common API. GStreamer allows you to wrap these libraries with a common API, which significantly simplifies integration and reuse. Non unified plugin mechanisms Your typical media player might have a plugin for different media types. Two media players will typically implement their own plugin mechanism so that the codecs cannot be easily exchanged. The plugin system of the typical media player is also very tailored to the specific needs of the application. The lack of a unified plugin mechanism also seriously hinders the creation of binary only codecs. No company is willing to port their code to all the different plugin mechanisms. While GStreamer also uses it own plugin system it offers a very rich framework for the plugin developer and ensures the plugin can be used in a wide range of applications, transparently interacting with other plugins. The framework that GStreamer provides for the plugins is flexible enough to host even the most demanding plugins. Poor user experience Because of the problems mentioned above, application authors have so far often been urged to spend a considerable amount of time in writing their own backends, plugin mechanisms and so on. The result has often been, unfortunately, that both the backend as well as the user interface were only half-finished. Demotivated, the application authors would start rewriting the whole thing and complete the circle. This leads to a poor end user experience. Provision for network transparency No infrastructure is present to allow network transparent media handling. A distributed MPEG encoder will typically duplicate the same encoder algorithms found in a non-distributed encoder. No provisions have been made for technologies such as the GNOME object embedding using Bonobo. The GStreamer core does not use network transparent technologies at the lowest level as it only adds overhead for the local case. That said, it shouldn't be hard to create a wrapper around the core components. There are tcp plugins now that implement a GStreamer Data Protocol that allows pipelines to be slit over TCP. These are located in the gst-plugins module directory gst/tcp. Catch up with the Windows world We need solid media handling if we want to see Linux succeed on the desktop. We must clear the road for commercially backed codecs and multimedia applications so that Linux can become an option for doing multimedia. The design goals We describe what we try to achieve with GStreamer. Clean and powerful GStreamer wants to provide a clean interface to: The application programmer who wants to build a media pipeline. The programmer can use an extensive set of powerful tools to create media pipelines without writing a single line of code. Performing complex media manipulations becomes very easy. The plugin programmer. Plugin programmers are provided a clean and simple API to create self-contained plugins. An extensive debugging and tracing mechanism has been integrated. GStreamer also comes with an extensive set of real-life plugins that serve as examples too. Object oriented GStreamer adheres to the GLib 2.0 object model. A programmer familiar with GLib 2.0 or older versions of GTK+ will be comfortable with GStreamer. GStreamer uses the mechanism of signals and object properties. All objects can be queried at runtime for their various properties and capabilities. GStreamer intends to be similar in programming methodology to GTK+. This applies to the object model, ownership of objects, reference counting, ... Extensible All GStreamer Objects can be extended using the GObject inheritance methods. All plugins are loaded dynamically and can be extended and upgraded independently. Allow binary only plugins Plugins are shared libraries that are loaded at runtime. Since all the properties of the plugin can be set using the GObject properties, there is no need (and in fact no way) to have any header files installed for the plugins. Special care has been taken to make plugins completely self-contained. All relevant aspects of plugins can be queried at run-time. High performance High performance is obtained by: using GLib's g_mem_chunk and fast non-blocking allocation algorithms where possible to minimize dynamic memory allocation. extremely light-weight links between plugins. Data can travel the pipeline with minimal overhead. Data passing between plugins only involves a pointer dereference in a typical pipeline. providing a mechanism to directly work on the target memory. A plugin can for example directly write to the X server's shared memory space. Buffers can also point to arbitrary memory, such as a sound card's internal hardware buffer. refcounting and copy on write minimize usage of memcpy. Sub-buffers efficiently split buffers into manageable pieces. the use of cothreads to minimize the threading overhead. Cothreads are a simple and fast user-space method for switching between subtasks. Cothreads were measured to consume as little as 600 cpu cycles. allowing hardware acceleration by using specialized plugins. using a plugin registry with the specifications of the plugins so that the plugin loading can be delayed until the plugin is actually used. all critical data passing is free of locks and mutexes. Clean core/plugins separation The core of GStreamer is essentially media-agnostic. It only knows about bytes and blocks, and only contains basic elements. The core of GStreamer is functional enough to even implement low-level system tools, like cp. All of the media handling functionality is provided by plugins external to the core. These tell the core how to handle specific types of media. Provide a framework for codec experimentation GStreamer also wants to be an easy framework where codec developers can experiment with different algorithms, speeding up the development of open and free multimedia codecs like Theora and Vorbis. Foundations This chapter of the guide introduces the basic concepts of GStreamer. Understanding these concepts will be important in reading any of the rest of this guide, all of them assume understanding of these basic concepts. Elements An element is the most important class of objects in GStreamer. You will usually create a chain of elements linked together and let data flow through this chain of elements. An element has one specific function, which can be the reading of data from a file, decoding of this data or outputting this data to your sound card (or anything else). By chaining together several such elements, you create a pipeline that can do a specific task, for example media playback or capture. GStreamer ships with a large collection of elements by default, making the development of a large variety of media applications possible. If needed, you can also write new elements. That topic is explained in great deal in the Plugin Writer's Guide. Bins and pipelines A bin is a container for a collection of elements. A pipeline is a special subtype of a bin that allows execution of all of its contained child elements. Since bins are subclasses of elements themselves, you can mostly control a bin as if it where an element, thereby abstracting away a lot of complexity for your application. You can, for example change state on all elements in a bin by changing the state of that bin itself. Bins also forward some signals from their contained childs (such as errors and tags). A pipeline is a bin that allows to run (technically referred to as iterating) its contained childs. By iterating a pipeline, data flow will start and media processing will take place. A pipeline requires iterating for anything to happen. you can also use threads, which automatically iterate the contained childs in a newly created threads. We will go into this in detail later on. Pads Pads are used to negotiate links and data flow between elements in GStreamer. A pad can be viewed as a plug or port on an element where links may be made with other elements, and through which data can flow to or from those elements. Pads have specific data handling capabilities: A pad can restrict the type of data that flows through it. Links are only allowed between two pads when the allowed data types of the two pads are compatible. Data types are negotiated between pads using a process called caps negotiation. Data types are described as a GstCaps. An analogy may be helpful here. A pad is similar to a plug or jack on a physical device. Consider, for example, a home theater system consisting of an amplifier, a DVD player, and a (silent) video projector. Linking the DVD player to the amplifier is allowed because both devices have audio jacks, and linking the projector to the DVD player is allowed because both devices have compatible video jacks. Links between the projector and the amplifier may not be made because the projector and amplifier have different types of jacks. Pads in GStreamer serve the same purpose as the jacks in the home theater system. For the most part, all data in GStreamer flows one way through a link between elements. Data flows out of one element through one or more source pads, and elements accept incoming data through one or more sink pads. Source and sink elements have only source and sink pads, respectively. Data is embodied in a GstData structure. Basic Concepts In these chapters, we will discuss the basic concepts of GStreamer and the most-used objects, such as elements, pads and buffers. We will use a visual representation of these objects so that we can visualize the more complex pipelines you will learn to build later on. You will get a first glance at the GStreamer API, which should be enough for building elementary applications. Later on in this part, you will also learn to build a basic command-line application. Note that this part will give a look into the low-level API and concepts of GStreamer. Once you're going to build applications, you might want to use higher-level APIs. Those will be discussed later on in this manual. Initializing GStreamer When writing a GStreamer application, you can simply include gst/gst.h to get access to the library functions. Besides that, you will also need to intialize the GStreamer library. Simple initialization Before the GStreamer libraries can be used, gst_init has to be called from the main application. This call will perform the necessary initialization of the library as well as parse the GStreamer-specific command line options. A typical program The code for this example is automatically extracted from the documentation and built under examples/manual in the GStreamer tarball. would have code to initialize GStreamer that looks like this: #include <gst/gst.h> int main (int argc, char *argv[]) { guint major, minor, micro; gst_init (&argc, &argv); gst_version (&major, &minor, &micro); printf ("This program is linked against GStreamer %d.%d.%d\n", major, minor, micro); return 0; } Use the GST_VERSION_MAJOR, GST_VERSION_MINOR and GST_VERSION_MICRO macros to get the GStreamer version you are building against, or use the function gst_version to get the version your application is linked against. GStreamer currently uses a scheme where versions with the same major and minor versions are API-/ and ABI-compatible. It is also possible to call the gst_init function with two NULL arguments, in which case no command line options will be parsed by GStreamer. The popt interface You can also use a popt table to initialize your own parameters as shown in the next example: #include <gst/gst.h> int main (int argc, char *argv[]) { gboolean silent = FALSE; gchar *savefile = NULL; struct poptOption options[] = { {"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0, "do not output status information", NULL}, {"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0, "save xml representation of pipeline to FILE and exit", "FILE"}, POPT_TABLEEND }; gst_init_with_popt_table (&argc, &argv, options); printf ("Run me with --help to see the Application options appended.\n"); return 0; } As shown in this fragment, you can use a popt table to define your application-specific command line options, and pass this table to the function gst_init_with_popt_table. Your application options will be parsed in addition to the standard GStreamer options. Elements The most important object in GStreamer for the application programmer is the GstElement object. An element is the basic building block for a media pipeline. All the different high-level components you will use are derived from GstElement. Every decoder, encoder, demuxer, video or audio output is in fact a GstElement What are elements? For the application programmer, elements are best visualized as black boxes. On the one end, you might put something in, the element does something with it and something else comes out at the other side. For a decoder element, ifor example, you'd put in encoded data, and the element would output decoded data. In the next chapter (see ), you will learn more about data input and output in elements, and how you can set that up in your application. Source elements Source elements generate data for use by a pipeline, for example reading from disk or from a sound card. shows how we will visualise a source element. We always draw a source pad to the right of the element. Visualisation of a source element Source elements do not accept data, they only generate data. You can see this in the figure because it only has a source pad (on the right). A source pad can only generate data. Filters, convertors, demuxers, muxers and codecs Filters and filter-like elements have both input and outputs pads. They operate on data that they receive on their input (sink) pads, and will provide data on their output (source) pads. Examples of such elements are a volume element (filter), a video scaler (convertor), an Ogg demuxer or a Vorbis decoder. Filter-like elements can have any number of source or sink pads. A video demuxer, for example, would have one sink pad and several (1-N) source pads, one for each elementary stream contained in the container format. Decoders, on the other hand, will only have one source and sink pads. Visualisation of a filter element shows how we will visualise a filter-like element. This specific element has one source and one sink element. Sink pads, receiving input data, are depicted at the left of the element; source pads are still on the right. Visualisation of a filter element with more than one output pad shows another filter-like element, this one having more than one output (source) pad. An example of one such element could, for example, be an Ogg demuxer for an Ogg stream containing both audio and video. One source pad will contain the elementary video stream, another will contain the elementary audio stream. Demuxers will generally fire signals when a new pad is created. The application programmer can then handle the new elementary stream in the signal handler. Sink elements Sink elements are end points in a media pipeline. They accept data but do not produce anything. Disk writing, soundcard playback, and video output would all be implemented by sink elements. shows a sink element. Visualisation of a sink elementCreating a GstElement The simplest way to create an element is to use gst_element_factory_make (). This function takes a factory name and an element name for the newly created element. The name of the element is something you can use later on to look up the element in a bin, for example. The name will also be used in debug output. You can pass NULL as the name argument to get a unique, default name. When you don't need the element anymore, you need to unref it using gst_object_unref (). This decreases the reference count for the element by 1. An element has a refcount of 1 when it gets created. An element gets destroyed completely when the refcount is decreased to 0. The following example The code for this example is automatically extracted from the documentation and built under examples/manual in the GStreamer tarball. shows how to create an element named source from the element factory named fakesrc. It checks if the creation succeeded. After checking, it unrefs the element. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *element; /* init GStreamer */ gst_init (&argc, &argv); /* create element */ element = gst_element_factory_make ("fakesrc", "source"); if (!element) { g_print ("Failed to create element of type 'fakesrc'\n"); return -1; } gst_object_unref (GST_OBJECT (element)); return 0; } gst_element_factory_make is actually a shorthand for a combination of two functions. A GstElement object is created from a factory. To create the element, you have to get access to a GstElementFactory object using a unique factory name. This is done with gst_element_factory_find (). The following code fragment is used to get a factory that can be used to create the fakesrc element, a fake data source. The function gst_element_factory_create () will use the element factory to create an element with the given name. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElementFactory *factory; GstElement * element; /* init GStreamer */ gst_init (&argc, &argv); /* create element, method #2 */ factory = gst_element_factory_find ("fakesrc"); if (!factory) { g_print ("Failed to find factory of type 'fakesrc'\n"); return -1; } element = gst_element_factory_create (factory, "source"); if (!element) { g_print ("Failed to create element, even though its factory exists!\n"); return -1; } gst_object_unref (GST_OBJECT (element)); return 0; } Using an element as a GObject A GstElement can have several properties which are implemented using standard GObject properties. The usual GObject methods to query, set and get property values and GParamSpecs are therefore supported. Every GstElement inherits at least one property from its parent GstObject: the "name" property. This is the name you provide to the functions gst_element_factory_make () or gst_element_factory_create (). You can get and set this property using the functions gst_object_set_name and gst_object_get_name or use the GObject property mechanism as shown below. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *element; const gchar *name; /* init GStreamer */ gst_init (&argc, &argv); /* create element */ element = gst_element_factory_make ("fakesrc", "source"); /* get name */ g_object_get (G_OBJECT (element), "name", &name, NULL); g_print ("The name of the element is '%s'.\n", name); gst_object_unref (GST_OBJECT (element)); return 0; } Most plugins provide additional properties to provide more information about their configuration or to configure the element. gst-inspect is a useful tool to query the properties of a particular element, it will also use property introspection to give a short explanation about the function of the property and about the parameter types and ranges it supports. See the appendix for details about gst-inspect. For more information about GObject properties we recommend you read the GObject manual and an introduction to The Glib Object system. A GstElement also provides various GObject signals that can be used as a flexible callback mechanism. Here, too, you can use gst-inspect to see which signals a specific elements supports. Together, signals and properties are the most basic way in which elements and applications interact. More about element factories In the previous section, we briefly introduced the GstElementFactory object already as a way to create instances of an element. Element factories, however, are much more than just that. Element factories are the basic types retrieved from the GStreamer registry, they describe all plugins and elements that GStreamer can create. This means that element factories are useful for automated element instancing, such as what autopluggers do, and for creating lists of available elements, such as what pipeline editing applications (e.g. GStreamer Editor) do. Getting information about an element using a factory Tools like gst-inspect will provide some generic information about an element, such as the person that wrote the plugin, a descriptive name (and a shortname), a rank and a category. The category can be used to get the type of the element that can be created using this element factory. Examples of categories include Codec/Decoder/Video (video decoder), Codec/Encoder/Video (video encoder), Source/Video (a video generator), Sink/Video (a video output), and all these exist for audio as well, of course. Then, there's also Codec/Demuxer and Codec/Muxer and a whole lot more. gst-inspect will give a list of all factories, and gst-inspect <factory-name> will list all of the above information, and a lot more. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElementFactory *factory; /* init GStreamer */ gst_init (&argc, &argv); /* get factory */ factory = gst_element_factory_find ("sinesrc"); if (!factory) { g_print ("You don't have the 'sinesrc' element installed, go get it!\n"); return -1; } /* display information */ g_print ("The '%s' element is a member of the category %s.\n" "Description: %s\n", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), gst_element_factory_get_klass (factory), gst_element_factory_get_description (factory)); return 0; } You can use gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY) to get a list of all the element factories that GStreamer knows about. Finding out what pads an element can contain Perhaps the most powerful feature of element factories is that they contain a full description of the pads that the element can generate, and the capabilities of those pads (in layman words: what types of media can stream over those pads), without actually having to load those plugins into memory. This can be used to provide a codec selection list for encoders, or it can be used for autoplugging purposes for media players. All current GStreamer-based media players and autopluggers work this way. We'll look closer at these features as we learn about GstPad and GstCaps in the next chapter: Linking elements By linking a source element with zero or more filter-like elements and finally a sink element, you set up a media pipeline. Data will flow through the elements. This is the basic concept of media handling in GStreamer. Visualisation of three linked elements By linking these three elements, we have created a very simple chain of elements. The effect of this will be that the output of the source element (element1) will be used as input for the filter-like element (element2). The filter-like element will do something with the data and send the result to the final sink element (element3). Imagine the above graph as a simple Ogg/Vorbis audio decoder. The source is a disk source which reads the file from disc. The second element is a Ogg/Vorbis audio decoder. The sink element is your soundcard, playing back the decoded audio data. We will use this simple graph to construct an Ogg/Vorbis player later in this manual. In code, the above graph is written like this: #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *source, *filter, *sink; /* init */ gst_init (&argc, &argv); /* create elements */ source = gst_element_factory_make ("fakesrc", "source"); filter = gst_element_factory_make ("identity", "filter"); sink = gst_element_factory_make ("fakesink", "sink"); /* link */ gst_element_link_many (source, filter, sink, NULL); [..] } For more specific behaviour, there are also the functions gst_element_link () and gst_element_link_pads (). You can also obtain references to individual pads and link those using various gst_pad_link_* () functions. See the API references for more details. Element States After being created, an element will not actually perform any actions yet. You need to change elements state to make it do something. GStreamer knows four element states, each with a very specific meaning. Those four states are: GST_STATE_NULL: this is the default state. This state will deallocate all resources held by the element. GST_STATE_READY: in the ready state, an element has allocated all of its global resources, that is, resources that can be kept within streams. You can think about opening devices, allocating buffers and so on. However, the stream is not opened in this state, so the stream positions is automatically zero. If a stream was previously opened, it should be closed in this state, and position, properties and such should be reset. GST_STATE_PAUSED: in this state, an element has opened the stream, but is not actively processing it. An element should not modify the stream's position, data or anything else in this state. When set back to PLAYING, it should continue processing at the point where it left off as soon as possible. GST_STATE_PLAYING: in the PLAYING state, an element does exactly the same as in the PAUSED state, except that it actually processes data. You can change the state of an element using the function gst_element_set_state (). If you set an element to another state, GStreamer will internally traverse all intermediate states. So if you set an element from NULL to PLAYING, GStreamer will internally set the element to READY and PAUSED in between. Even though an element in GST_STATE_PLAYING is ready for data processing, it will not necessarily do that. If the element is placed in a thread (see ), it will process data automatically. In other cases, however, you will need to iterate the element's container. Bins A bin is a container element. You can add elements to a bin. Since a bin is an element itself, a bin can be handled in the same way as any other element. Therefore, the whole previous chapter () applies to bins as well. What are bins Bins allow you to combine a group of linked elements into one logical element. You do not deal with the individual elements anymore but with just one element, the bin. We will see that this is extremely powerful when you are going to construct complex pipelines since it allows you to break up the pipeline in smaller chunks. The bin will also manage the elements contained in it. It will figure out how the data will flow in the bin and generate an optimal plan for that data flow. Plan generation is one of the most complicated procedures in GStreamer. You will learn more about this process, called scheduling, in . Visualisation of a bin with some elements in it There are two specialized types of bins available to the GStreamer programmer: A pipeline: a generic container that allows scheduling of the containing elements. The toplevel bin has to be a pipeline. Every application thus needs at least one of these. Applications can iterate pipelines using gst_bin_iterate () to make it process data while in the playing state. A thread: a bin that will be run in a separate execution thread. You will have to use this bin if you have to carefully synchronize audio and video, or for buffering. You will learn more about threads in . Creating a bin Bins are created in the same way that other elements are created, i.e. using an element factory. There are also convenience functions available (gst_bin_new (), gst_thread_new () and gst_pipeline_new ()). To add elements to a bin or remove elements from a bin, you can use gst_bin_add () and gst_bin_remove (). Note that the bin that you add an element to will take ownership of that element. If you destroy the bin, the element will be dereferenced with it. If you remove an element from a bin, it will be dereferenced automatically. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *bin, *pipeline, *source, *sink; /* init */ gst_init (&argc, &argv); /* create */ pipeline = gst_pipeline_new ("my_pipeline"); bin = gst_pipeline_new ("my_bin"); source = gst_element_factory_make ("fakesrc", "source"); sink = gst_element_factory_make ("fakesink", "sink"); /* set up pipeline */ gst_bin_add_many (GST_BIN (bin), source, sink, NULL); gst_bin_add (GST_BIN (pipeline), bin); gst_element_link (source, sink); [..] } There are various functions to lookup elements in a bin. You can also get a list of all elements that a bin contains using the function gst_bin_get_list (). See the API references of GstBin for details. Custom bins The application programmer can create custom bins packed with elements to perform a specific task. This allows you, for example, to write an Ogg/Vorbis decoder with just the following lines of code: int main (int argc char *argv[]) { GstElement *player; /* init */ gst_init (&argc, &argv); /* create player */ player = gst_element_factory_make ("oggvorbisplayer", "player"); /* set the source audio file */ g_object_set (G_OBJECT (player), "location", "helloworld.ogg", NULL); /* start playback */ gst_element_set_state (GST_ELEMENT (player), GST_STATE_PLAYING); [..] } Custom bins can be created with a plugin or an XML description. You will find more information about creating custom bin in the Plugin Writers Guide. Pads and capabilities As we have seen in , the pads are the element's interface to the outside world. Data streams from one element's source pad to another element's sink pad. The specific type of media that the element can handle will be exposed by the pad's capabilities. We will talk more on capabilities later in this chapter (see ). Pads A pad type is defined by two properties: its direction and its availability. As we've mentioned before, GStreamer defines two pad directions: source pads and sink pads. This terminology is defined from the view of within the element: elements receive data on their sink pads and generate data on their source pads. Schematically, sink pads are drawn on the left side of an element, whereas source pads are drawn on the right side of an element. In such graphs, data flows from left to right. In reality, there is no objection to data flowing from a source pad to the sink pad of an element upstream (to the left of this element in drawings). Data will, however, always flow from a source pad of one element to the sink pad of another. Pad directions are very simple compared to pad availability. A pad can have any of three availabilities: always, sometimes and on request. The meaning of those three types is exactly as it says: always pads always exist, sometimes pad exist only in certain cases (and can disappear randomly), and on-request pads appear only if explicitely requested by applications. Dynamic (or sometimes) pads Some elements might not have all of their pads when the element is created. This can happen, for example, with an Ogg demuxer element. The element will read the Ogg stream and create dynamic pads for each contained elementary stream (vorbis, theora) when it detects such a stream in the Ogg stream. Likewise, it will delete the pad when the stream ends. This principle is very useful for demuxer elements, for example. Running gst-inspect oggdemux will show that the element has only one pad: a sink pad called 'sink'. The other pads are dormant. You can see this in the pad template because there is an Exists: Sometimes property. Depending on the type of Ogg file you play, the pads will be created. We will see that this is very important when you are going to create dynamic pipelines. You can attach a signal handler to an element to inform you when the element has created a new pad from one of its sometimes pad templates. The following piece of code is an example of how to do this: #include <gst/gst.h> static void cb_new_pad (GstElement *element, GstPad *pad, gpointer data) { g_print ("A new pad %s was created\n", gst_pad_get_name (pad)); /* here, you would setup a new pad link for the newly created pad */ [..] } int main(int argc, char *argv[]) { GstElement *pipeline, *source, *demux; /* init */ gst_init (&argc, &argv); /* create elements */ pipeline = gst_pipeline_new ("my_pipeline"); source = gst_element_factory_make ("filesrc", "source"); g_object_set (source, "location", argv[1], NULL); demux = gst_element_factory_make ("oggdemux", "demuxer"); /* you would normally check that the elements were created properly */ /* put together a pipeline */ gst_bin_add_many (GST_BIN (pipeline), source, demux, NULL); gst_element_link (source, demux); /* listen for newly created pads */ g_signal_connect (demux, "new-pad", G_CALLBACK (cb_new_pad), NULL); /* start the pipeline */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); [..] } Request pads An element can also have request pads. These pads are not created automatically but are only created on demand. This is very useful for multiplexers, aggregators and tee elements. Aggregators are elements that merge the content of several input streams together into one output stream. Tee elements are the reverse: they are elements that have one input stream and copy this stream to each of their output pads, which are created on request. Whenever an application needs another copy of the stream, it can simply request a new output pad from the tee element. The following piece of code shows how you can request a new output pad from a tee element: static void some_function (GstElement *tee) { GstPad * pad; pad = gst_element_get_request_pad (tee, "src%d"); g_print ("A new pad %s was created\n", gst_pad_get_name (pad)); /* here, you would link the pad */ [..] } The gst_element_get_request_pad () method can be used to get a pad from the element based on the name of the pad template. It is also possible to request a pad that is compatible with another pad template. This is very useful if you want to link an element to a multiplexer element and you need to request a pad that is compatible. The method gst_element_get_compatible_pad () can be used to request a compatible pad, as shown in the next example. It will request a compatible pad from an Ogg multiplexer from any input. static void link_to_multiplexer (GstPad *tolink_pad, GstElement *mux) { GstPad *pad; pad = gst_element_get_compatible_pad (mux, tolink_pad); gst_pad_link (tolinkpad, pad); g_print ("A new pad %s was created and linked to %s\n", gst_pad_get_name (pad), gst_pad_get_name (tolink_pad)); } Capabilities of a pad Since the pads play a very important role in how the element is viewed by the outside world, a mechanism is implemented to describe the data that can flow or currently flows through the pad by using capabilities. Here,w e will briefly describe what capabilities are and how to use them, enough to get an understanding of the concept. For an in-depth look into capabilities and a list of all capabilities defined in GStreamer, see the Plugin Writers Guide. Capabilities are attached to pad templates and to pads. For pad templates, it will describe the types of media that may stream over a pad created from this template. For pads, it can either be a list of possible caps (usually a copy of the pad template's capabilities), in which case the pad is not yet negotiated, or it is the type of media that currently streams over this pad, in which case the pad has been negotiated already. Dissecting capabilities A pads capabilities are described in a GstCaps object. Internally, a GstCaps will contain one or more GstStructure that will describe one media type. A negotiated pad will have capabilities set that contain exactly one structure. Also, this structure will contain only fixed values. These constraints are not true for unnegotiated pads or pad templates. As an example, below is a dump of the capabilities of the vorbisdec element, which you will get by running gst-inspect vorbisdec. You will see two pads: a source and a sink pad. Both of these pads are always available, and both have capabilities attached to them. The sink pad will accept vorbis-encoded audio data, with the mime-type audio/x-vorbis. The source pad will be used to send raw (decoded) audio samples to the next element, with a raw audio mime-type (either audio/x-raw-int or audio/x-raw-float). The source pad will also contain properties for the audio samplerate and the amount of channels, plus some more that you don't need to worry about for now. Pad Templates: SRC template: 'src' Availability: Always Capabilities: audio/x-raw-float rate: [ 8000, 50000 ] channels: [ 1, 2 ] endianness: 1234 width: 32 buffer-frames: 0 SINK template: 'sink' Availability: Always Capabilities: audio/x-vorbis Properties and values Properties are used to describe extra information for capabilities. A property consists of a key (a string) and a value. There are different possible value types that can be used: Basic types, this can be pretty much any GType registered with Glib. Those properties indicate a specific, non-dynamic value for this property. Examples include: An integer value (G_TYPE_INT): the property has this exact value. A boolean value (G_TYPE_BOOLEAN): the property is either TRUE or FALSE. A float value (G_TYPE_FLOAT): the property has this exact floating point value. A string value (G_TYPE_STRING): the property contains a UTF-8 string. Range types are GTypes registered by GStreamer to indicate a range of possible values. They are used for indicating allowed audio samplerate values or supported video sizes. The two types defined in GStreamer are: An integer range value (GST_TYPE_INT_RANGE): the property denotes a range of possible integers, with a lower and an upper boundary. The vorbisdec element, for example, has a rate property that can be between 8000 and 50000. A float range value (GST_TYPE_FLOAT_RANGE): the property denotes a range of possible floating point values, with a lower and an upper boundary. A list value (GST_TYPE_LIST): the property can take any value from a list of basic values given in this list. What capabilities are used for Capabilities describe the type of data that is streamed between two pads, or that one pad (template) supports. This makes them very useful for various purposes: Autoplugging: automatically finding elements to link to a pad based on its capabilities. All autopluggers use this method. Compatibility detection: when two pads are linked, GStreamer can verify if the two pads are talking about the same media type. The process of linking two pads and checking if they are compatible is called caps negotiation. Metadata: by reading the capabilities from a pad, applications can provide information about the type of media that is being streamed over the pad, which is information about the stream thatis currently being played back. Filtering: an application can use capabilities to limit the possible media types that can stream between two pads to a specific subset of their supported stream types. An application can, for example, use filtered caps to set a specific (non-fixed) video size that will stream between two pads. Using capabilities for metadata A pad can have a set (i.e. one or more) of capabilities attached to it. You can get values of properties in a set of capabilities by querying individual properties of one structure. You can get a structure from a caps using gst_caps_get_structure (): static void read_video_props (GstCaps *caps) { gint width, height; const GstStructure *str; str = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (str, "width", &width) || !gst_structure_get_int (str, "height", &height)) { g_print ("No width/height available\n"); return; } g_print ("The video size of this set of capabilities is %dx%d\n", width, height); } Creating capabilities for filtering While capabilities are mainly used inside a plugin to describe the media type of the pads, the application programmer also has to have basic understanding of capabilities in order to interface with the plugins, especially when using filtered caps. When you're using filtered caps or fixation, you're limiting the allowed types of media that can stream between two pads to a subset of their supported media types. You do this by filtering using your own set of capabilities. In order to do this, you need to create your own GstCaps. The simplest way to do this is by using the convenience function gst_caps_new_simple (): static void link_pads_with_filter (GstPad *one, GstPad *other) { GstCaps *caps; caps = gst_caps_new_simple ("video/x-raw-yuv", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL); gst_pad_link_filtered (one, other, caps); } In some cases, you will want to create a more elaborate set of capabilities to filter a link between two pads. Then, this function is too simplistic and you'll want to use the method gst_caps_new_full (): static void link_pads_with_filter (GstPad *one, GstPad *other) { GstCaps *caps; caps = gst_caps_new_full ( gst_structure_new ("video/x-raw-yuv", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL), gst_structure_new ("video/x-raw-rgb", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL), NULL); gst_pad_link_filtered (one, other, caps); } See the API references for the full API of GstStructure and GstCaps. Ghost pads You can see from how a bin has no pads of its own. This is where "ghost pads" come into play. Visualisation of a GstBin element without ghost pads A ghost pad is a pad from some element in the bin that can be accessed directly from the bin as well. Compare it to a symbolic link in UNIX filesystems. Using ghost pads on bins, the bin also has a pad and can transparently be used as an element in other parts of your code. Visualisation of a GstBin element with a ghost pad is a representation of a ghost pad. The sink pad of element one is now also a pad of the bin. Obviously, ghost pads can be added to any type of elements, not just to a GstBin. A ghostpad is created using the function gst_element_add_ghost_pad (): #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *bin, *sink; /* init */ gst_init (&argc, &argv); /* create element, add to bin, add ghostpad */ sink = gst_element_factory_make ("fakesink", "sink"); bin = gst_bin_new ("mybin"); gst_bin_add (GST_BIN (bin), sink); gst_element_add_ghost_pad (bin, gst_element_get_pad (sink, "sink"), "sink"); [..] } In the above example, the bin now also has a pad: the pad called sink of the given element. The bin can, from here on, be used as a substitute for the sink element. You could, for example, link another element to the bin. Buffers and Events The data flowing through a pipeline consists of a combination of buffers and events. Buffers contain the actual pipeline data. Events contain control information, such as seeking information and end-of-stream notifiers. All this will flow through the pipeline automatically when it's running. This chapter is mostly meant to explain the concept to you; you don't need to do anything for this. Buffers Buffers contain the data that will flow through the pipeline you have created. A source element will typically create a new buffer and pass it through a pad to the next element in the chain. When using the GStreamer infrastructure to create a media pipeline you will not have to deal with buffers yourself; the elements will do that for you. A buffer consists, amongst others, of: A pointer to a piece of memory. The size of the memory. A timestamp for the buffer. A refcount that indicates how many elements are using this buffer. This refcount will be used to destroy the buffer when no element has a reference to it. The simple case is that a buffer is created, memory allocated, data put in it, and passed to the next element. That element reads the data, does something (like creating a new buffer and decoding into it), and unreferences the buffer. This causes the data to be free'ed and the buffer to be destroyed. A typical video or audio decoder works like this. There are more complex scenarios, though. Elements can modify buffers in-place, i.e. without allocating a new one. Elements can also write to hardware memory (such as from video-capture sources) or memory allocated from the X-server using XShm). Buffers can be read-only, and so on. Events Events are control particles that are sent both up- and downstream in a pipeline along with buffers. Downstream events notify fellow elements of stream states. Possible events include discontinuities, flushes, end-of-stream notifications and so on. Upstream events are used both in application-element interaction as well as event-event interaction to request changes in stream state, such as seeks. For applications, only upstream events are important. Downstream events are just explained to get a more complete picture of the data concept. Since most applications seek in time units, our example below does so too: static void seek_to_time (GstElement *element, guint64 time_ns) { GstEvent *event; event = gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME, time_ns); gst_element_send_event (element, event); } The function gst_element_seek () is a shortcut for this. This is mostly just to show how it all works. Your first application This chapter will summarize everything you've learned in the previous chapters. It describes all aspects of a simple GStreamer application, including initializing libraries, creating elements, packing elements together in a pipeline and playing this pipeline. By doing all this, you will be able to build a simple Ogg/Vorbis audio player. Hello world We're going to create a simple first application, a simple Ogg/Vorbis command-line audio player. For this, we will use only standard GStreamer components. The player will read a file specified on the command-line. Let's get started! We've learned, in , that the first thing to do in your application is to initialize GStreamer by calling gst_init (). Also, make sure that the application includes gst/gst.h so all function names and objects are properly defined. Use #include <gst/gst.h> to do that. Next, you'll want to create the different elements using gst_element_factory_make (). For an Ogg/Vorbis audio player, we'll need a source element that reads files from a disk. GStreamer includes this element under the name filesrc. Next, we'll need something to parse the file and decoder it into raw audio. GStreamer has two elements for this: the first parses Ogg streams into elementary streams (video, audio) and is called oggdemux. The second is a Vorbis audio decoder, it's conveniently called vorbisdec. Since oggdemux creates dynamic pads for each elementary stream, you'll need to set a new-pad event handler on the oggdemux element, like you've learned in , to link the Ogg parser and the Vorbis decoder elements together. At last, we'll also need an audio output element, we will use alsasink, which outputs sound to an ALSA audio device. The last thing left to do is to add all elements into a container element, a GstPipeline, and iterate this pipeline until we've played the whole song. We've previously learned how to add elements to a container bin in , and we've learned about element states in . We will use the function gst_bin_sync_children_state () to synchronize the state of a bin on all of its contained children. Let's now add all the code together to get our very first audio player: #include <gst/gst.h> /* * Global objects are usually a bad thing. For the purpose of this * example, we will use them, however. */ GstElement *pipeline, *source, *parser, *decoder, *conv, *scale, *sink; static void new_pad (GstElement *element, GstPad *pad, gpointer data) { /* We can now link this pad with the audio decoder and * add both decoder and audio output to the pipeline. */ gst_pad_link (pad, gst_element_get_pad (decoder, "sink")); gst_bin_add_many (GST_BIN (pipeline), decoder, conv, scale, sink, NULL); /* This function synchronizes a bins state on all of its * contained children. */ gst_bin_sync_children_state (GST_BIN (pipeline)); } int main (int argc, char *argv[]) { /* initialize GStreamer */ gst_init (&argc, &argv); /* check input arguments */ if (argc != 2) { g_print ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]); return -1; } /* create elements */ pipeline = gst_pipeline_new ("audio-player"); source = gst_element_factory_make ("filesrc", "file-source"); parser = gst_element_factory_make ("oggdemux", "ogg-parser"); decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder"); conv = gst_element_factory_make ("audioconvert", "conv"); scale = gst_element_factory_make ("audioscale", "scale"); sink = gst_element_factory_make ("alsasink", "alsa-output"); /* set filename property on the file source */ g_object_set (G_OBJECT (source), "location", argv[1], NULL); /* link together - note that we cannot link the parser and * decoder yet, becuse the parser uses dynamic pads. For that, * we set a new-pad signal handler. */ gst_element_link (source, parser); gst_element_link_many (decoder, conv, scale, sink, NULL); g_signal_connect (parser, "new-pad", G_CALLBACK (new_pad), NULL); /* put all elements in a bin - or at least the ones we will use * instantly. */ gst_bin_add_many (GST_BIN (pipeline), source, parser, NULL); /* Now set to playing and iterate. We will set the decoder and * audio output to ready so they initialize their memory already. * This will decrease the amount of time spent on linking these * elements when the Ogg parser emits the new-pad signal. */ gst_element_set_state (decoder, GST_STATE_READY); gst_element_set_state (conv, GST_STATE_READY); gst_element_set_state (scale, GST_STATE_READY); gst_element_set_state (sink, GST_STATE_READY); gst_element_set_state (pipeline, GST_STATE_PLAYING); /* and now iterate - the rest will be automatic from here on. * When the file is finished, gst_bin_iterate () will return * FALSE, thereby terminating this loop. */ while (gst_bin_iterate (GST_BIN (pipeline))) ; /* clean up nicely */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } We now have created a complete pipeline. We can visualise the pipeline as follows: The "hello world" pipelineCompiling and Running helloworld.c To compile the helloworld example, use: gcc -Wall $(pkg-config --cflags --libs gstreamer-0.8) helloworld.c -o helloworld. GStreamer makes use of pkg-config to get compiler and linker flags needed to compile this application. If you're running a non-standard installation, make sure the PKG_CONFIG_PATH environment variable is set to the correct location ($libdir/pkgconfig). application against the uninstalled location. You can run this example application with ./helloworld file.ogg. Substitute file.ogg with your favourite Ogg/Vorbis file. Conclusion This concludes our first example. As you see, setting up a pipeline is very low-level but powerful. You will see later in this manual how you can create a more powerful media player with even less effort using higher-level interfaces. We will discuss all that in . We will first, however, go more in-depth into more advanced GStreamer internals. It should be clear from the example that we can very easily replace the filesrc element with some other element that reads data from a network, or some other data source element that is better integrated with your desktop environment. Also, you can use other decoders and parsers to support other media types. You can use another audio sink if you're not running Linux, but Mac OS X, Windows or FreeBSD, or you can instead use a filesink to write audio files to disk instead of playing them back. By using an audio card source, you can even do audio capture instead of playback. All this shows the reusability of GStreamer elements, which is its greatest advantage. Advanced GStreamer concepts In this part we will cover the more advanced features of GStreamer. With the basics you learned in the previous part you should be able to create a simple application. However, GStreamer provides much more candy than just the basics of playing back audio files. In this chapter, you will learn more of the low-level features and internals of GStreamer, such as threads, scheduling, synchronization, metadata, interfaces and dynamic parameters. Position tracking and seeking So far, we've looked at how to create a pipeline to do media processing and how to make it run ("iterate"). Most application developers will be interested in providing feedback to the user on media progress. Media players, for example, will want to show a slider showing the progress in the song, and usually also a label indicating stream length. Transcoding applications will want to show a progress bar on how much % of the task is done. GStreamer has built-in support for doing all this using a concept known as querying. Since seeking is very similar, it will be discussed here as well. Seeking is done using the concept of events. Querying: getting the position or length of a stream Querying is defined as requesting a specific stream-property related to progress tracking. This includes getting the length of a stream (if available) or getting the current position. Those stream properties can be retrieved in various formats such as time, audio samples, video frames or bytes. The functions used are gst_element_query () and gst_pad_query (). Obviously, using either of the above-mentioned functions requires the application to know which element or pad to run the query on. This is tricky, but there are some good sides to the story. The good thing is that elements (or, rather, pads - since gst_element_query () internally calls gst_pad_query ()) forward (dispatch) events and queries to peer pads (or elements) if they don't handle it themselves. The bad side is that some elements (or pads) will handle events, but not the specific formats that you want, and therefore it still won't work. Most queries will, fortunately, work fine. Queries are always dispatched backwards. This means, effectively, that it's easiest to run the query on your video or audio output element, and it will take care of dispatching the query to the element that knows the answer (such as the current position or the media length; usually the demuxer or decoder). #include <gst/gst.h> gint main (gint argc, gchar *argv[]) { GstElement *sink, *pipeline; [..] /* run pipeline */ do { gint64 len, pos; GstFormat fmt = GST_FORMAT_TIME; if (gst_element_query (sink, GST_QUERY_POSITION, &fmt, &pos) && gst_element_query (sink, GST_QUERY_TOTAL, &fmt, &len)) { g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", GST_TIME_ARGS (pos), GST_TIME_ARGS (len)); } } while (gst_bin_iterate (GST_BIN (pipeline))); [..] } If you are having problems with the dispatching behaviour, your best bet is to manually decide which element to start running the query on. You can get a list of supported formats and query-types with gst_element_get_query_types () and gst_element_get_formats (). Events: seeking (and more) Events work in a very similar way as queries. Dispatching, for example, works exactly the same for events (and also has the same limitations). Although there are more ways in which applications and elements can interact using events, we will only focus on seeking here. This is done using the seek-event. A seek-event contains a seeking offset, a seek method (which indicates relative to what the offset was given), a seek format (which is the unit of the offset, e.g. time, audio samples, video frames or bytes) and optionally a set of seeking-related flags (e.g. whether internal buffers should be flushed). The behaviour of a seek is also wrapped in the function gst_element_seek (). static void seek_to_time (GstElement *audiosink, gint64 time_nanonseconds) { gst_element_seek (audiosink, GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_FLUSH, time_nanoseconds); } Metadata GStreamer makes a clear distinction between two types of metadata, and has support for both types. The first is stream tags, which describe the content of a stream in a non-technical way. Examples include the author of a song, the title of that very same song or the album it is a part of. The other type of metadata is stream-info, which is a somewhat technical description of the properties of a stream. This can include video size, audio samplerate, codecs used and so on. Tags are handled using the GStreamer tagging system. Stream-info can be retrieved from a GstPad. Stream information Stream information can most easily be read by reading them from a GstPad. This has already been discussed before in . Therefore, we will skip it here. Tag reading Tag reading is remarkably simple in GStreamer Every element supports the found-tag signal, which will be fired each the time the element reads tags from the stream. A GstBin will conveniently forward tags found by its childs. Therefore, in most applications, you will only need to connect to the found-tag signal on the top-most bin in your pipeline, and you will automatically retrieve all tags from the stream. Note, however, that the found-tag might be fired multiple times and by multiple elements in the pipeline. It is the application's responsibility to put all those tags together and display them to the user in a nice, coherent way. Tag writing WRITEME Interfaces In , you have learned how to use GObject properties as a simple way to do interaction between applications and elements. This method suffices for the simple'n'straight settings, but fails for anything more complicated than a getter and setter. For the more complicated use cases, GStreamer uses interfaces based on the Glib GInterface type. Most of the interfaces handled here will not contain any example code. See the API references for details. Here, we will just describe the scope and purpose of each interface. The Mixer interface The mixer interface provides a uniform way to control the volume on a hardware (or software) mixer. The interface is primarily intended to be implemented by elements for audio inputs and outputs that talk directly to the hardware (e.g. OSS or ALSA plugins). Using this interface, it is possible to control a list of tracks (such as Line-in, Microphone, etc.) from a mixer element. They can be muted, their volume can be changed and, for input tracks, their record flag can be set as well. Example plugins implementing this interface include the OSS elements (osssrc, osssink, ossmixer) and the ALSA plugins (alsasrc, alsasink and alsamixer). The Tuner interface The tuner interface is a uniform way to control inputs and outputs on a multi-input selection device. This is primarily used for input selection on elements for TV- and capture-cards. Using this interface, it is possible to select one track from a list of tracks supported by that tuner-element. The tuner will than select that track for media-processing internally. This can, for example, be used to switch inputs on a TV-card (e.g. from Composite to S-video). This interface is currently only implemented by the Video4linux and Video4linux2 elements. The Color Balance interface The colorbalance interface is a way to control video-related properties on an element, such as brightness, contrast and so on. It's sole reason for existance is that, as far as its authors know, there's no way to dynamically register properties using GObject. The colorbalance interface is implemented by several plugins, including xvimagesink and the Video4linux and Video4linux2 elements. The Property Probe interface The property probe is a way to autodetect allowed values for a GObject property. It's primary use (and the only thing that we currently use it for) is to autodetect devices in several elements. For example, the OSS elements use this interface to detect all OSS devices on a system. Applications can then probe this property and get a list of detected devices. Given the overlap between HAL and the practical implementations of this interface, this might in time be deprecated in favour of HAL. This interface is currently implemented by many elements, including the ALSA, OSS, Video4linux and Video4linux2 elements. The X Overlay interface The X Overlay interface was created to solve the problem of embedding video streams in an application window. The application provides an X-window to the element implementing this interface to draw on, and the element will then use this X-window to draw on rather than creating a new toplevel window. This is useful to embed video in video players. This interface is implemented by, amongst others, the Video4linux and Video4linux2 elements and by ximagesink, xvimagesink and sdlvideosink. Clocks in GStreamer WRITEME Dynamic ParametersGetting Started The Dynamic Parameters subsystem is contained within the gstcontrol library. You need to include the header in your application's source file: ... #include <gst/gst.h> #include <gst/control/control.h> ... Your application should link to the shared library gstcontrol. The gstcontrol library needs to be initialized when your application is run. This can be done after the the GStreamer library has been initialized. ... gst_init(&argc,&argv); gst_control_init(&argc,&argv); ... Creating and Attaching Dynamic Parameters Once you have created your elements you can create and attach dparams to them. First you need to get the element's dparams manager. If you know exactly what kind of element you have, you may be able to get the dparams manager directly. However if this is not possible, you can get the dparams manager by calling gst_dpman_get_manager. Once you have the dparams manager, you must set the mode that the manager will run in. There is currently only one mode implemented called "synchronous" - this is used for real-time applications where the dparam value cannot be known ahead of time (such as a slider in a GUI). The mode is called "synchronous" because the dparams are polled by the element for changes before each buffer is processed. Another yet-to-be-implemented mode is "asynchronous". This is used when parameter changes are known ahead of time - such as with a timelined editor. The mode is called "asynchronous" because parameter changes may happen in the middle of a buffer being processed. GstElement *sinesrc; GstDParamManager *dpman; ... sinesrc = gst_element_factory_make("sinesrc","sine-source"); ... dpman = gst_dpman_get_manager (sinesrc); gst_dpman_set_mode(dpman, "synchronous"); If you don't know the names of the required dparams for your element you can call gst_dpman_list_dparam_specs(dpman) to get a NULL terminated array of param specs. This array should be freed after use. You can find the name of the required dparam by calling g_param_spec_get_name on each param spec in the array. In our example, "volume" will be the name of our required dparam. Each type of dparam currently has its own new function. This may eventually be replaced by a factory method for creating new instances. A default dparam instance can be created with the gst_dparam_new function. Once it is created it can be attached to a required dparam in the element. GstDParam *volume; ... volume = gst_dparam_new(G_TYPE_DOUBLE); if (gst_dpman_attach_dparam (dpman, "volume", volume)){ /* the dparam was successfully attached */ ... } Changing Dynamic Parameter Values All interaction with dparams to actually set the dparam value is done through simple GObject properties. There is a property value for each type that dparams supports - these currently being "value_double", "value_float", "value_int" and "value_int64". To set the value of a dparam, simply set the property which matches the type of your dparam instance. #define ZERO(mem) memset(&mem, 0, sizeof(mem)) ... gdouble set_to_value; GstDParam *volume; GValue set_val; ZERO(set_val); g_value_init(&set_val, G_TYPE_DOUBLE); ... g_value_set_double(&set_val, set_to_value); g_object_set_property(G_OBJECT(volume), "value_double", &set_val); Or if you create an actual GValue instance: gdouble set_to_value; GstDParam *volume; GValue *set_val; set_val = g_new0(GValue,1); g_value_init(set_val, G_TYPE_DOUBLE); ... g_value_set_double(set_val, set_to_value); g_object_set_property(G_OBJECT(volume), "value_double", set_val); Different Types of Dynamic Parameter There are currently only two implementations of dparams so far. They are both for real-time use so should be run in the "synchronous" mode. GstDParam - the base dparam type All dparam implementations will subclass from this type. It provides a basic implementation which simply propagates any value changes as soon as it can. A new instance can be created with the function GstDParam* gst_dparam_new (GType type). It has the following object properties: "value_double" - the property to set and get if it is a double dparam "value_float" - the property to set and get if it is a float dparam "value_int" - the property to set and get if it is an integer dparam "value_int64" - the property to set and get if it is a 64 bit integer dparam "is_log" - readonly boolean which is TRUE if the param should be displayed on a log scale "is_rate" - readonly boolean which is TRUE if the value is a proportion of the sample rate. For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz. GstDParamSmooth - smoothing real-time dparam Some parameter changes can create audible artifacts if they change too rapidly. The GstDParamSmooth implementation can greatly reduce these artifacts by limiting the rate at which the value can change. This is currently only supported for double and float dparams - the other types fall back to the default implementation. A new instance can be created with the function GstDParam* gst_dpsmooth_new (GType type). It has the following object properties: "update_period" - an int64 value specifying the number nanoseconds between updates. This will be ignored in "synchronous" mode since the buffer size dictates the update period. "slope_time" - an int64 value specifying the time period to use in the maximum slope calculation "slope_delta_double" - a double specifying the amount a double value can change in the given slope_time. "slope_delta_float" - a float specifying the amount a float value can change in the given slope_time. Audible artifacts may not be completely eliminated by using this dparam. The only way to eliminate artifacts such as "zipper noise" would be for the element to implement its required dparams using the array method. This would allow dparams to change parameters at the sample rate which should eliminate any artifacts. Timelined dparams A yet-to-be-implemented subclass of GstDParam will add an API which allows the creation and manipulation of points on a timeline. This subclass will also provide a dparam implementation which uses linear interpolation between these points to find the dparam value at any given time. Further subclasses can extend this functionality to implement more exotic interpolation algorithms such as splines. Threads GStreamer has support for multithreading through the use of the GstThread object. This object is in fact a special GstBin that will start a new thread (using Glib's GThread system) when started. To create a new thread, you can simply use gst_thread_new (). From then on, you can use it similar to how you would use a GstBin. You can add elements to it, change state and so on. The largest difference between a thread and other bins is that the thread does not require iteration. Once set to the GST_STATE_PLAYING state, it will iterate its contained children elements automatically. shows how a thread can be visualised. A threadWhen would you want to use a thread? There are several reasons to use threads. However, there's also some reasons to limit the use of threads as much as possible. We will go into the drawbacks of threading in GStreamer in the next section. Let's first list some situations where threads can be useful: Data buffering, for example when dealing with network streams or when recording data from a live stream such as a video or audio card. Short hickups elsewhere in the pipeline will not cause data loss. See for a visualization of this idea. Synchronizing output devices, e.g. when playing a stream containing both video and audio data. By using threads for both outputs, they will run independently and their synchronization will be better. Data pre-rolls. You can use threads and queues (thread boundaries) to cache a few seconds of data before playing. By using this approach, the whole pipeline will already be setup and data will already be decoded. When activating the rest of the pipeline, the switch from PAUSED to PLAYING will be instant. a two-threaded decoder with a queue Above, we've mentioned the queue element several times now. A queue is a thread boundary element. It does so by using a classic provider/receiver model as learned in threading classes at universities all around the world. By doing this, it acts both as a means to make data throughput between threads threadsafe, and it can also act as a buffer. Queues have several GObject properties to be configured for specific uses. For example, you can set lower and upper tresholds for the element. If there's less data than the lower treshold (default: disabled), it will block output. If there's more data than the upper treshold, it will block input or (if configured to do so) drop data. Constraints placed on the pipeline by the GstThread Within the pipeline, everything is the same as in any other bin. The difference lies at the thread boundary, at the link between the thread and the outside world (containing bin). Since GStreamer is fundamentally buffer-oriented rather than byte-oriented, the natural solution to this problem is an element that can "buffer" the buffers between the threads, in a thread-safe fashion. This element is the queue element. A queue should be placed in between any two elements whose pads are linked together while the elements live in different threads. It doesn't matter if the queue is placed in the containing bin or in the thread itself, but it needs to be present on one side or the other to enable inter-thread communication. If you are writing a GUI application, making the top-level bin a thread will make your GUI more responsive. If it were a pipeline instead, it would have to be iterated by your application's event loop, which increases the latency between events (say, keyboard presses) and responses from the GUI. In addition, any slight hang in the GUI would delay iteration of the pipeline, which (for example) could cause pops in the output of the sound card, if it is an audio pipeline. A problem with using threads is, however, thread contexts. If you connect to a signal that is emitted inside a thread, then the signal handler for this thread will be executed in that same thread! This is very important to remember, because many graphical toolkits can not run multi-threaded. Gtk+, for example, only allows threaded access to UI objects if you explicitely use mutexes. Not doing so will result in random crashes and X errors. A solution many people use is to place an idle handler in the signal handler, and have the actual signal emission code be executed in the idle handler, which will be executed from the mainloop. Generally, if you use threads, you will encounter some problems. Don't hesistate to ask us for help in case of problems. A threaded example application As an example we show the helloworld program that we coded in using a thread. Note that the whole application lives in a thread (as opposed to half of the application living in a thread and the other half being another thread or a pipeline). Therefore, it does not need a queue element in this specific case. #include <gst/gst.h> GstElement *thread, *source, *decodebin, *audiosink; static gboolean idle_eos (gpointer data) { g_print ("Have idle-func in thread %p\n", g_thread_self ()); gst_main_quit (); /* do this function only once */ return FALSE; } /* * EOS will be called when the src element has an end of stream. * Note that this function will be called in the thread context. * We will place an idle handler to the function that really * quits the application. */ static void cb_eos (GstElement *thread, gpointer data) { g_print ("Have eos in thread %p\n", g_thread_self ()); g_idle_add ((GSourceFunc) idle_eos, NULL); } /* * On error, too, you'll want to forward signals to the main * thread, especially when using GUI applications. */ static void cb_error (GstElement *thread, GstElement *source, GError *error, gchar *debug, gpointer data) { g_print ("Error in thread %p: %s\n", g_thread_self (), error->message); g_idle_add ((GSourceFunc) idle_eos, NULL); } /* * Link new pad from decodebin to audiosink. * Contains no further error checking. */ static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) { gst_pad_link (pad, gst_element_get_pad (audiosink, "sink")); gst_bin_add (GST_BIN (thread), audiosink); gst_bin_sync_children_state (GST_BIN (thread)); } gint main (gint argc, gchar *argv[]) { /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have a filename argument */ if (argc != 2) { g_print ("usage: %s <Ogg/Vorbis filename>\n", argv[0]); return -1; } /* create a new thread to hold the elements */ thread = gst_thread_new ("thread"); g_signal_connect (thread, "eos", G_CALLBACK (cb_eos), NULL); g_signal_connect (thread, "error", G_CALLBACK (cb_error), NULL); /* create elements */ source = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (source), "location", argv[1], NULL); decodebin = gst_element_factory_make ("decodebin", "decoder"); g_signal_connect (decodebin, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); audiosink = gst_element_factory_make ("alsasink", "audiosink"); /* setup */ gst_bin_add_many (GST_BIN (thread), source, decodebin, NULL); gst_element_link (source, decodebin); gst_element_set_state (audiosink, GST_STATE_PAUSED); gst_element_set_state (thread, GST_STATE_PLAYING); /* no need to iterate. We can now use a mainloop */ gst_main (); /* unset */ gst_element_set_state (thread, GST_STATE_NULL); gst_object_unref (GST_OBJECT (thread)); return 0; } Scheduling By now, you've seen several example applications. All of them would set up a pipeline and call gst_bin_iterate () to start media processing. You might have started wondering what happens during pipeline iteration. This whole process of media processing is called scheduling. Scheduling is considered one of the most complex parts of GStreamer. Here, we will do no more than give a global overview of scheduling, most of which will be purely informative. It might help in understanding the underlying parts of GStreamer. The scheduler is responsible for managing the plugins at runtime. Its main responsibilities are: Managing data throughput between pads and elements in a pipeline. This might sometimes imply temporary data storage between elements. Calling functions in elements that do the actual data processing. Monitoring state changes and enabling/disabling elements in the chain. Selecting and distributing the global clock. The scheduler is a pluggable component; this means that alternative schedulers can be written and plugged into GStreamer. There is usually no need for interaction in the process of choosing the scheduler, though. The default scheduler in GStreamer is called opt. Some of the concepts discussed here are specific to opt. Managing elements and data throughput To understand some specifics of scheduling, it is important to know how elements work internally. Largely, there are four types of elements: _chain ()-based elements, _loop ()-based elements, _get ()-based elements and decoupled elements. Each of those have a set of features and limitations that are important for how they are scheduled. _chain ()-based elements are elements that have a _chain ()-function defined for each of their sinkpads. Those functions will receive data whenever input data is available. In those functions, the element can push data over its source pad(s) to peer elements. _chain ()-based elements cannot pull additional data from their sinkpad(s). Most elements in GStreamer are _chain ()-based. _loop ()-based elements are elements that have a _loop ()-function defined for the whole element. Inside this function, the element can pull buffers from its sink pad(s) and push data over its source pad(s) as it sees fit. Such elements usually require specific control over their input. Muxers and demuxers are usually _loop ()-based. _get ()-based elements are elements with only source pads. For each source pad, a _get ()-function is defined, which is called whenever the peer element needs additional input data. Most source elements are, in fact, _get ()-based. Such an element cannot actively push data. Decoupled elements are elements whose source pads are _get ()-based and whose sink pads are _chain ()-based. The _chain ()-function cannot push data over its source pad(s), however. One such element is the queue element, which is a thread boundary element. Since only one side of such elements are interesting for one particular scheduler, we can safely handle those elements as if they were either _get ()- or _chain ()-based. Therefore, we will further omit this type of elements in the discussion. Obviously, the type of elements that are linked together have implications for how the elements will be scheduled. If a get-based element is linked to a loop-based element and the loop-based element requests data from its sinkpad, we can just call the get-function and be done with it. However, if two loop-based elements are linked to each other, it's a lot more complicated. Similarly, a loop-based element linked to a chain-based element is a lot easier than two loop-based elements linked to each other. The default GStreamer scheduler, opt, uses a concept of chains and groups. A group is a series of elements that do not require any context switches or intermediate data stores to be executed. In practice, this implies zero or one loop-based elements, one get-based element (at the beginning) and an infinite amount of chain-based elements. If there is a loop-based element, then the scheduler will simply call this elements loop-function to iterate. If there is no loop-based element, then data will be pulled from the get-based element and will be pushed over the chain-based elements. A chain is a series of groups that depend on each other for data. For example, two linked loop-based elements would end up in different groups, but in the same chain. Whenever the first loop-based element pushes data over its source pad, the data will be temporarily stored inside the scheduler until the loop-function returns. When it's done, the loop-function of the second element will be called to process this data. If it pulls data from its sinkpad while no data is available, the scheduler will emulate a get-function and, in this function, iterate the first group until data is available. The above is roughly how scheduling works in GStreamer. This has some implications for ideal pipeline design. An pipeline would ideally contain at most one loop-based element, so that all data processing is immediate and no data is stored inside the scheduler during group switches. You would think that this decreases overhead significantly. In practice, this is not so bad, however. It's something to keep in the back of your mind, nothing more. Autoplugging In , you've learned to build a simple media player for Ogg/Vorbis files. By using alternative elements, you are able to build media players for other media types, such as Ogg/Speex, MP3 or even video formats. However, you would rather want to build an application that can automatically detect the media type of a stream and automatically generate the best possible pipeline by looking at all available elements in a system. This process is called autoplugging, and GStreamer contains high-quality autopluggers. If you're looking for an autoplugger, don't read any further and go to . This chapter will explain the concept of autoplugging and typefinding. It will explain what systems GStreamer includes to dynamically detect the type of a media stream, and how to generate a pipeline of decoder elements to playback this media. The same principles can also be used for transcoding. Because of the full dynamicity of this concept, GStreamer can be automatically extended to support new media types without needing any adaptations to its autopluggers. We will first introduce the concept of MIME types as a dynamic and extendible way of identifying media streams. After that, we will introduce the concept of typefinding to find the type of a media stream. Lastly, we will explain how autoplugging and the GStreamer registry can be used to setup a pipeline that will convert media from one mimetype to another, for example for media decoding. MIME-types as a way to identity streams We have previously introduced the concept of capabilities as a way for elements (or, rather, pads) to agree on a media type when streaming data from one element to the next (see ). We have explained that a capability is a combination of a mimetype and a set of properties. For most container formats (those are the files that you will find on your hard disk; Ogg, for example, is a container format), no properties are needed to describe the stream. Only a MIME-type is needed. A full list of MIME-types and accompanying properties can be found in the Plugin Writer's Guide. An element must associate a MIME-type to its source and sink pads when it is loaded into the system. GStreamer knows about the different elements and what type of data they expect and emit through the GStreamer registry. This allows for very dynamic and extensible element creation as we will see. In , we've learned to build a music player for Ogg/Vorbis files. Let's look at the MIME-types associated with each pad in this pipeline. shows what MIME-type belongs to each pad in this pipeline. The Hello world pipeline with MIME types Now that we have an idea how GStreamer identifies known media streams, we can look at methods GStreamer uses to setup pipelines for media handling and for media type detection. Media stream type detection Usually, when loading a media stream, the type of the stream is not known. This means that before we can choose a pipeline to decode the stream, we first need to detect the stream type. GStreamer uses the concept of typefinding for this. Typefinding is a normal part of a pipeline, it will read data for as long as the type of a stream is unknown. During this period, it will provide data to all plugins that implement a typefinder. when one of the typefinders recognizes the stream, the typefind element will emit a signal and act as a passthrough module from that point on. If no type was found, it will emit an error and further media processing will stop. Once the typefind element has found a type, the application can use this to plug together a pipeline to decode the media stream. This will be discussed in the next section. Plugins in GStreamer can, as mentioned before, implement typefinder functionality. A plugin implementing this functionality will submit a mimetype, optionally a set of file extensions commonly used for this media type, and a typefind function. Once this typefind function inside the plugin is called, the plugin will see if the data in this media stream matches a specific pattern that marks the media type identified by that mimetype. If it does, it will notify the typefind element of this fact, telling which mediatype was recognized and how certain we are that this stream is indeed that mediatype. Once this run has been completed for all plugins implementing a typefind functionality, the typefind element will tell the application what kind of media stream it thinks to have recognized. The following code should explain how to use the typefind element. It will print the detected media type, or tell that the media type was not found. The next section will introduce more useful behaviours, such as plugging together a decoding pipeline. #include <gst/gst.h> static void cb_typefound (GstElement *typefind, guint probability, GstCaps *caps, gpointer data) { gchar *type; type = gst_caps_to_string (caps); g_print ("Media type %s found, probability %d%%\n", type, probability); g_free (type); /* done */ (* (gboolean *) data) = TRUE; } static void cb_error (GstElement *pipeline, GstElement *source, GError *error, gchar *debug, gpointer data) { g_print ("Error: %s\n", error->message); /* done */ (* (gboolean *) data) = TRUE; } gint main (gint argc, gchar *argv[]) { GstElement *pipeline, *filesrc, *typefind; gboolean done = FALSE; /* init GStreamer */ gst_init (&argc, &argv); /* check args */ if (argc != 2) { g_print ("Usage: %s <filename>\n", argv[0]); return -1; } /* create a new pipeline to hold the elements */ pipeline = gst_pipeline_new ("pipe"); g_signal_connect (pipeline, "error", G_CALLBACK (cb_error), &done); /* create file source and typefind element */ filesrc = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); typefind = gst_element_factory_make ("typefind", "typefinder"); g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), &done); /* setup */ gst_bin_add_many (GST_BIN (pipeline), filesrc, typefind, NULL); gst_element_link (filesrc, typefind); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); /* now iterate until the type is found */ do { if (!gst_bin_iterate (GST_BIN (pipeline))) break; } while (!done); /* unset */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Once a media type has been detected, you can plug an element (e.g. a demuxer or decoder) to the source pad of the typefind element, and decoding of the media stream will start right after. Plugging together dynamic pipelines In this chapter we will see how you can create a dynamic pipeline. A dynamic pipeline is a pipeline that is updated or created while data is flowing through it. We will create a partial pipeline first and add more elements while the pipeline is playing. The basis of this player will be the application that we wrote in the previous section () to identify unknown media streams. Once the type of the media has been found, we will find elements in the registry that can decode this streamtype. For this, we will get all element factories (which we've seen before in ) and find the ones with the given MIME-type and capabilities on their sinkpad. Note that we will only use parsers, demuxers and decoders. We will not use factories for any other element types, or we might get into a loop of encoders and decoders. For this, we will want to build a list of allowed factories right after initializing GStreamer. static GList *factories; /* * This function is called by the registry loader. Its return value * (TRUE or FALSE) decides whether the given feature will be included * in the list that we're generating further down. */ static gboolean cb_feature_filter (GstPluginFeature *feature, gpointer data) { const gchar *klass; guint rank; /* we only care about element factories */ if (!GST_IS_ELEMENT_FACTORY (feature)) return FALSE; /* only parsers, demuxers and decoders */ klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); if (g_strrstr (klass, "Demux") == NULL && g_strrstr (klass, "Decoder") == NULL && g_strrstr (klass, "Parse") == NULL) return FALSE; /* only select elements with autoplugging rank */ rank = gst_plugin_feature_get_rank (feature); if (rank < GST_RANK_MARGINAL) return FALSE; return TRUE; } /* * This function is called to sort features by rank. */ static gint cb_compare_ranks (GstPluginFeature *f1, GstPluginFeature *f2) { return gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); } static void init_factories (void) { /* first filter out the interesting element factories */ factories = gst_registry_pool_feature_filter ( (GstPluginFeatureFilter) cb_feature_filter, FALSE, NULL); /* sort them according to their ranks */ factories = g_list_sort (factories, (GCompareFunc) cb_compare_ranks); } From this list of element factories, we will select the one that most likely will help us decoding a media stream to a given output type. For each newly created element, we will again try to autoplug new elements to its source pad(s). Also, if the element has dynamic pads (which we've seen before in ), we will listen for newly created source pads and handle those, too. The following code replaces the cb_type_found from the previous section with a function to initiate autoplugging, which will continue with the above approach. static void try_to_plug (GstPad *pad, const GstCaps *caps); static GstElement *audiosink; static void cb_newpad (GstElement *element, GstPad *pad, gpointer data) { GstCaps *caps; caps = gst_pad_get_caps (pad); try_to_plug (pad, caps); gst_caps_free (caps); } static void close_link (GstPad *srcpad, GstElement *sinkelement, const gchar *padname, const GList *templlist) { gboolean has_dynamic_pads = FALSE; g_print ("Plugging pad %s:%s to newly created %s:%s\n", gst_object_get_name (GST_OBJECT (gst_pad_get_parent (srcpad))), gst_pad_get_name (srcpad), gst_object_get_name (GST_OBJECT (sinkelement)), padname); /* add the element to the pipeline and set correct state */ gst_element_set_state (sinkelement, GST_STATE_PAUSED); gst_bin_add (GST_BIN (pipeline), sinkelement); gst_pad_link (srcpad, gst_element_get_pad (sinkelement, padname)); gst_bin_sync_children_state (GST_BIN (pipeline)); /* if we have static source pads, link those. If we have dynamic * source pads, listen for new-pad signals on the element */ for ( ; templlist != NULL; templlist = templlist->next) { GstPadTemplate *templ = GST_PAD_TEMPLATE (templlist->data); /* only sourcepads, no request pads */ if (templ->direction != GST_PAD_SRC || templ->presence == GST_PAD_REQUEST) { continue; } switch (templ->presence) { case GST_PAD_ALWAYS: { GstPad *pad = gst_element_get_pad (sinkelement, templ->name_template); GstCaps *caps = gst_pad_get_caps (pad); /* link */ try_to_plug (pad, caps); gst_caps_free (caps); break; } case GST_PAD_SOMETIMES: has_dynamic_pads = TRUE; break; default: break; } } /* listen for newly created pads if this element supports that */ if (has_dynamic_pads) { g_signal_connect (sinkelement, "new-pad", G_CALLBACK (cb_newpad), NULL); } } static void try_to_plug (GstPad *pad, const GstCaps *caps) { GstObject *parent = GST_OBJECT (gst_pad_get_parent (pad)); const gchar *mime; const GList *item; GstCaps *res, *audiocaps; /* don't plug if we're already plugged */ if (GST_PAD_IS_LINKED (gst_element_get_pad (audiosink, "sink"))) { g_print ("Omitting link for pad %s:%s because we're already linked\n", gst_object_get_name (parent), gst_pad_get_name (pad)); return; } /* as said above, we only try to plug audio... Omit video */ mime = gst_structure_get_name (gst_caps_get_structure (caps, 0)); if (g_strrstr (mime, "video")) { g_print ("Omitting link for pad %s:%s because mimetype %s is non-audio\n", gst_object_get_name (parent), gst_pad_get_name (pad), mime); return; } /* can it link to the audiopad? */ audiocaps = gst_pad_get_caps (gst_element_get_pad (audiosink, "sink")); res = gst_caps_intersect (caps, audiocaps); if (res && !gst_caps_is_empty (res)) { g_print ("Found pad to link to audiosink - plugging is now done\n"); close_link (pad, audiosink, "sink", NULL); gst_caps_free (audiocaps); gst_caps_free (res); return; } gst_caps_free (audiocaps); gst_caps_free (res); /* try to plug from our list */ for (item = factories; item != NULL; item = item->next) { GstElementFactory *factory = GST_ELEMENT_FACTORY (item->data); const GList *pads; for (pads = gst_element_factory_get_pad_templates (factory); pads != NULL; pads = pads->next) { GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data); /* find the sink template - need an always pad*/ if (templ->direction != GST_PAD_SINK || templ->presence != GST_PAD_ALWAYS) { continue; } /* can it link? */ res = gst_caps_intersect (caps, templ->caps); if (res && !gst_caps_is_empty (res)) { GstElement *element; gchar *name_template = g_strdup (templ->name_template); /* close link and return */ gst_caps_free (res); element = gst_element_factory_create (factory, NULL); close_link (pad, element, name_template, gst_element_factory_get_pad_templates (factory)); g_free (name_template); return; } gst_caps_free (res); /* we only check one sink template per factory, so move on to the * next factory now */ break; } } /* if we get here, no item was found */ g_print ("No compatible pad found to decode %s on %s:%s\n", mime, gst_object_get_name (parent), gst_pad_get_name (pad)); } static void cb_typefound (GstElement *typefind, guint probability, GstCaps *caps, gpointer data) { gchar *s; s = gst_caps_to_string (caps); g_print ("Detected media type %s\n", s); g_free (s); /* actually plug now */ try_to_plug (gst_element_get_pad (typefind, "src"), caps); } By doing all this, we will be able to make a simple autoplugger that can automatically setup a pipeline for any media type. In the example below, we will do this for audio only. However, we can also do this for video to create a player that plays both audio and video. The example above is a good first try for an autoplugger. Next steps would be to listen for pad-removed signals, so we can dynamically change the plugged pipeline if the stream changes (this happens for DVB or Ogg radio). Also, you might want special-case code for input with known content (such as a DVD or an audio-CD), and much, much more. Moreover, you'll want many checks to prevent infinite loops during autoplugging, maybe you'll want to implement shortest-path-finding to make sure the most optimal pipeline is chosen, and so on. Basically, the features that you implement in an autoplugger depend on what you want to use it for. For full-blown implementations, see the playbin, decodebin and spider elements. Pipeline manipulation This chapter will discuss how you can manipulate your pipeline in several ways from your application on. Parts of this chapter are downright hackish, so be assured that you'll need some programming knowledge before you start reading this. Topics that will be discussed here include how you can insert data into a pipeline from your application, how to read data from a pipeline, how to manipulate the pipeline's speed, length, starting point and how to listen to a pipeline's data processing. Data probes Probes are best envisioned as pad listeners. They are attached to a pad in a pipeline, and you can add callback functions to this probe. Those callback functions will be called whenever data is being sent over this pad. The callback can then decide whether the data should be discarded or it can replace the piece of data with another piece of data. In this callback, it can also trigger actions in the application itself. For pipeline manipulation, probes are rather limited, but for pipeline tracking, they can be very useful. Manually adding or removing data from/to a pipeline Many people have expressed the wish to use their own sources to inject data into a pipeline. Some people have also expressed the wish to grab the output in a pipeline and take care of the actual output inside their application. While either of these methods are stongly discouraged, GStreamer offers hacks to do this. However, there is no support for those methods. If it doesn't work, you're on your own. Also, synchronization, thread-safety and other things that you've been able to take for granted so far are no longer guanranteed if you use any of those methods. It's always better to simply write a plugin and have the pipeline schedule and manage it. See the Plugin Writer's Guide for more information on this topic. Also see the next section, which will explain how to embed plugins statically in your application. After all those disclaimers, let's start. There's three possible elements that you can use for the above-mentioned purposes. Those are called fakesrc (an imaginary source), fakesink (an imaginary sink) and identity (an imaginary filter). The same method applies to each of those elements. Here, we will discuss how to use those elements to insert (using fakesrc) or grab (using fakesink or identity) data from a pipeline, and how to set negotiation. Inserting or grabbing data The three before-mentioned elements (fakesrc, fakesink and identity) each have a handoff signal that will be called in the _get ()- (fakesrc) or _chain ()-function (identity, fakesink). In the signal handler, you can set (fakesrc) or get (identity, fakesink) data to/from the provided buffer. Note that in the case of fakesrc, you have to set the size of the provided buffer using the sizemax property. For both fakesrc and fakesink, you also have to set the signal-handoffs property for this method to work. Note that your handoff function should not block, since this will block pipeline iteration. Also, do not try to use all sort of weird hacks in such functions to accomplish something that looks like synchronization or so; it's not the right way and will lead to issues elsewhere. If you're doing any of this, you're basically misunderstanding the GStreamer design. Forcing a format Sometimes, when using fakesrc as a source in your pipeline, you'll want to set a specific format, for example a video size and format or an audio bitsize and number of channels. You can do this by forcing a specific GstCaps on the pipeline, which is possible by using filtered caps. You can set a filtered caps on a link by using gst_pad_link_filtered (), where the third argument is the format to force on the link. Example application This example application will generate black/white (it switches every second) video to an X-window output by using fakesrc as a source and using filtered caps to force a format. Since the depth of the image depends on your X-server settings, we use a colorspace conversion element to make sure that the output to your X server will have the correct bitdepth. You can also set timestamps on the provided buffers to override the fixed framerate. #include <string.h> /* for memset () */ #include <gst/gst.h> static void cb_handoff (GstElement *fakesrc, GstBuffer *buffer, GstPad *pad, gpointer user_data) { static gboolean white = FALSE; /* this makes the image black/white */ memset (GST_BUFFER_DATA (buffer), white ? 0xff : 0x0, GST_BUFFER_SIZE (buffer)); white = !white; } gint main (gint argc, gchar *argv[]) { GstElement *pipeline, *fakesrc, *conv, *videosink; GstCaps *filter; /* init GStreamer */ gst_init (&argc, &argv); /* setup pipeline */ pipeline = gst_pipeline_new ("pipeline"); fakesrc = gst_element_factory_make ("fakesrc", "source"); conv = gst_element_factory_make ("ffmpegcolorspace", "conv"); videosink = gst_element_factory_make ("ximagesink", "videosink"); /* setup */ filter = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, (gdouble) 1.0, "bpp", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL); gst_element_link_filtered (fakesrc, conv, filter); gst_element_link (conv, videosink); gst_bin_add_many (GST_BIN (pipeline), fakesrc, conv, videosink, NULL); /* setup fake source */ g_object_set (G_OBJECT (fakesrc), "signal-handoffs", TRUE, "sizemax", 384 * 288 * 2, "sizetype", 2, NULL); g_signal_connect (fakesrc, "handoff", G_CALLBACK (cb_handoff), NULL); /* play */ gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))) ; /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Embedding static elements in your application The Plugin Writer's Guide describes in great detail how to write elements for the GStreamer framework. In this section, we will solely discuss how to embed such elements statically in your application. This can be useful for application-specific elements that have no use elsewhere in GStreamer. Dynamically loaded plugins contain a structure that's defined using GST_PLUGIN_DEFINE (). This structure is loaded when the plugin is loaded by the GStreamer core. The structure contains an initialization function (usually called plugin_init) that will be called right after that. It's purpose is to register the elements provided by the plugin with the GStreamer framework. If you want to embed elements directly in your application, the only thing you need to do is to manually run this structure using _gst_plugin_register_static (). The initialization will then be called, and the elements will from then on be available like any other element, without them having to be dynamically loadable libraries. In the example below, you would be able to call gst_element_factory_make ("my-element-name", "some-name") to create an instance of the element. /* * Here, you would write the actual plugin code. */ [..] static gboolean register_elements (GstPlugin *plugin) { return gst_element_register (plugin, "my-element-name", GST_RANK_NONE, MY_PLUGIN_TYPE); } static GstPluginDesc plugin_desc = { GST_VERSION_MAJOR, GST_VERSION_MINOR, "my-private-plugins", "Private elements of my application", register_elements, NULL, "0.0.1", "LGPL", "my-application", "http://www.my-application.net/", GST_PADDING_INIT }; /* * Call this function right after calling gst_init (). */ void my_elements_init (void) { _gst_plugin_register_static (&plugin_desc); } Higher-level interfaces for GStreamer applications In the previous two parts, you have learned many of the internals and their corresponding low-level interfaces into GStreamer application programming. Many people will, however, not need so much control (and as much code), but will prefer to use a standard playback interface that does most of the difficult internals for them. In this chapter, we will introduce you into the concept of autopluggers, playback managing elements, XML-based pipelines and other such things. Those higher-level interfaces are intended to simplify GStreamer-based application programming. They do, however, also reduce the flexibility. It is up to the application developer to choose which interface he will want to use. Components GStreamer includes several higher-level components to simplify your applications life. All of the components discussed here (for now) are targetted at media playback. The idea of each of these components is to integrate as closely as possible with a GStreamer pipeline, but to hide the complexity of media type detection and several other rather complex topics that have been discussed in . We currently recommend people to use either playbin (see ) or decodebin (see ), depending on their needs. The other components discussed here are either outdated or deprecated. The documentation is provided for legacy purposes. Use of those other components is not recommended. Playbin Playbin is an element that can be created using the standard GStreamer API (e.g. gst_element_factory_make ()). The factory is conveniently called playbin. By being a GstElement, playbin automatically supports all of the features of this class, including error handling, tag support, state handling, getting stream positions, seeking, and so on. Setting up a playbin pipeline is as simple as creating an instance of the playbin element, setting a file location (this has to be a valid URI, so <protocol>://<location>, e.g. file:///tmp/my.ogg or http://www.example.org/stream.ogg) using the uri property on playbin, and then setting the element to the GST_STATE_PLAYING state. Internally, playbin uses threads, so there's no need to iterate the element or anything. However, one thing to keep in mind is that signals fired by playbin might come from another than the main thread, so be sure to keep this in mind in your signal handles. Most application programmers will want to use a function such as g_idle_add () to make sure that the signal is handled in the main thread. #include <gst/gst.h> static void cb_eos (GstElement *play, gpointer data) { gst_main_quit (); } static void cb_error (GstElement *play, GstElement *src, GError *err, gchar *debug, gpointer data) { g_print ("Error: %s\n", err->message); } gint main (gint argc, gchar *argv[]) { GstElement *play; /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have a URI */ if (argc != 2) { g_print ("Usage: %s <URI>\n", argv[0]); return -1; } /* set up */ play = gst_element_factory_make ("playbin", "play"); g_object_set (G_OBJECT (play), "uri", argv[1], NULL); g_signal_connect (play, "eos", G_CALLBACK (cb_eos), NULL); g_signal_connect (play, "error", G_CALLBACK (cb_error), NULL); if (gst_element_set_state (play, GST_STATE_PLAYING) != GST_STATE_SUCCESS) { g_print ("Failed to play\n"); return -1; } /* now run */ gst_main (); /* also clean up */ gst_element_set_state (play, GST_STATE_NULL); gst_object_unref (GST_OBJECT (play)); return 0; } Playbin has several features that have been discussed previously: Settable video and audio output (using the video-sink and audio-sink properties). Mostly controllable and trackable as a GstElement, including error handling, eos handling, tag handling, state handling, media position handling and seeking. Buffers network-sources. Supports visualizations for audio-only media. Supports subtitles, both in the media as well as from separate files. Supports stream selection and disabling. If your media has multiple audio or subtitle tracks, you can dynamically choose which one to play back, or decide to turn it off alltogther (which is especially useful to turn off subtitles). Decodebin Decodebin is the actual autoplugger backend of playbin, which was discussed in the previous section. Decodebin will, in short, accept input from a source that is linked to its sinkpad and will try to detect the media type contained in the stream, and set up decoder routines for each of those. It will automatically select decoders. For each decoded stream, it will emit the new-decoded-pad signal, to let the client know about the newly found decoded stream. For unknown streams (which might be the whole stream), it will emit the unknown-type signal. The application is then responsible for reporting the error to the user. The example code below will play back an audio stream of an input file. For readability, it does not include any error handling of any sort. #include <gst/gst.h> GstElement *pipeline, *audio; GstPad *audiopad; static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) { GstCaps *caps; GstStructure *str; /* only link audio; only link once */ if (GST_PAD_IS_LINKED (audiopad)) return; caps = gst_pad_get_caps (pad); str = gst_caps_get_structure (caps, 0); if (!g_strrstr (gst_structure_get_name (str), "audio")) return; /* link'n'play */ gst_pad_link (pad, audiopad); gst_bin_add (GST_BIN (pipeline), audio); gst_bin_sync_children_state (GST_BIN (pipeline)); } gint main (gint argc, gchar *argv[]) { GstElement *src, *dec, *conv, *scale, *sink; /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have input */ if (argc != 2) { g_print ("Usage: %s <filename>\n", argv[0]); return -1; } /* setup */ pipeline = gst_pipeline_new ("pipeline"); src = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (src), "location", argv[1], NULL); dec = gst_element_factory_make ("decodebin", "decoder"); g_signal_connect (dec, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); audio = gst_bin_new ("audiobin"); conv = gst_element_factory_make ("audioconvert", "aconv"); audiopad = gst_element_get_pad (conv, "sink"); scale = gst_element_factory_make ("audioscale", "scale"); sink = gst_element_factory_make ("alsasink", "sink"); gst_bin_add_many (GST_BIN (audio), conv, scale, sink, NULL); gst_element_link_many (conv, scale, sink, NULL); gst_bin_add_many (GST_BIN (pipeline), src, dec, NULL); gst_element_link (src, dec); /* run */ gst_element_set_state (audio, GST_STATE_PAUSED); gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))) ; /* cleanup */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Decodebin, similar to playbin, supports the following features: Can decode an unlimited number of contained streams to decoded output pads. Is handled as a GstElement in all ways, including tag or error forwarding and state handling. Although decodebin is a good autoplugger, there's a whole lot of things that it does not do and is not intended to do: Taking care of input streams with a known media type (e.g. a DVD, an audio-CD or such). Selection of streams (e.g. which audio track to play in case of multi-language media streams). Overlaying subtitles over a decoded video stream. Decodebin can be easily tested on the commandline, e.g. by using the command gst-launch-0.8 filesrc location=file.ogg ! decodebin ! audioconvert ! audioscale ! alsasink. Spider Spider is an autoplugger that looks and feels very much like decodebin. On the commandline, you can literally switch between spider and decodebin and it'll mostly just work. Try, for example, gst-launch-0.8 filesrc location=file.ogg ! spider ! audioconvert ! audioscale ! alsasink. Although the two may seem very much alike from the outside, they are very different from the inside. Those internal differences are the main reason why spider is currently considered deprecated (along with the fact that it was hard to maintain). As opposed to decodebin, spider does not decode pads and emit signals for each detected stream. Instead, you have to add output sinks to spider by create source request pads and connecting those to sink elements. This means that streams decoded by spider cannot be dynamic. Also, spider uses many loop-based elements internally, which is rather heavy scheduler-wise. Code for using spider would look almost identical to the code of decodebin, and is therefore omitted. Also, featureset and limitations are very much alike, except for the above-mentioned extra limitations for spider with respect to decodebin. GstPlay GstPlay is a GtkWidget with a simple API to play, pause and stop a media file. GstEditor GstEditor is a set of widgets to display a graphical representation of a pipeline. XML in GStreamer GStreamer uses XML to store and load its pipeline definitions. XML is also used internally to manage the plugin registry. The plugin registry is a file that contains the definition of all the plugins GStreamer knows about to have quick access to the specifics of the plugins. We will show you how you can save a pipeline to XML and how you can reload that XML file again for later use. Turning GstElements into XML We create a simple pipeline and write it to stdout with gst_xml_write_file (). The following code constructs an MP3 player pipeline with two threads and then writes out the XML both to stdout and to a file. Use this program with one argument: the MP3 file on disk. #include <stdlib.h> #include <gst/gst.h> gboolean playing; int main (int argc, char *argv[]) { GstElement *filesrc, *osssink, *queue, *queue2, *decode; GstElement *bin; GstElement *thread, *thread2; gst_init (&argc,&argv); if (argc != 2) { g_print ("usage: %s <mp3 filename>\n", argv[0]); exit (-1); } /* create a new thread to hold the elements */ thread = gst_element_factory_make ("thread", "thread"); g_assert (thread != NULL); thread2 = gst_element_factory_make ("thread", "thread2"); g_assert (thread2 != NULL); /* create a new bin to hold the elements */ bin = gst_bin_new ("bin"); g_assert (bin != NULL); /* create a disk reader */ filesrc = gst_element_factory_make ("filesrc", "disk_source"); g_assert (filesrc != NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); queue = gst_element_factory_make ("queue", "queue"); queue2 = gst_element_factory_make ("queue", "queue2"); /* and an audio sink */ osssink = gst_element_factory_make ("osssink", "play_audio"); g_assert (osssink != NULL); decode = gst_element_factory_make ("mad", "decode"); g_assert (decode != NULL); /* add objects to the main bin */ gst_bin_add_many (GST_BIN (bin), filesrc, queue, NULL); gst_bin_add_many (GST_BIN (thread), decode, queue2, NULL); gst_bin_add (GST_BIN (thread2), osssink); gst_element_link_many (filesrc, queue, decode, queue2, osssink, NULL); gst_bin_add_many (GST_BIN (bin), thread, thread2, NULL); /* write the bin to stdout */ gst_xml_write_file (GST_ELEMENT (bin), stdout); /* write the bin to a file */ gst_xml_write_file (GST_ELEMENT (bin), fopen ("xmlTest.gst", "w")); exit (0); } The most important line is: gst_xml_write_file (GST_ELEMENT (bin), stdout); gst_xml_write_file () will turn the given element into an xmlDocPtr that is then formatted and saved to a file. To save to disk, pass the result of a fopen(2) as the second argument. The complete element hierarchy will be saved along with the inter element pad links and the element parameters. Future GStreamer versions will also allow you to store the signals in the XML file. Loading a GstElement from an XML file Before an XML file can be loaded, you must create a GstXML object. A saved XML file can then be loaded with the gst_xml_parse_file (xml, filename, rootelement) method. The root element can optionally left NULL. The following code example loads the previously created XML file and runs it. #include <stdlib.h> #include <gst/gst.h> int main(int argc, char *argv[]) { GstXML *xml; GstElement *bin; gboolean ret; gst_init (&argc, &argv); xml = gst_xml_new (); ret = gst_xml_parse_file(xml, "xmlTest.gst", NULL); g_assert (ret == TRUE); bin = gst_xml_get_element (xml, "bin"); g_assert (bin != NULL); gst_element_set_state (bin, GST_STATE_PLAYING); while (gst_bin_iterate(GST_BIN(bin))); gst_element_set_state (bin, GST_STATE_NULL); exit (0); } gst_xml_get_element (xml, "name") can be used to get a specific element from the XML file. gst_xml_get_topelements (xml) can be used to get a list of all toplevel elements in the XML file. In addition to loading a file, you can also load a from a xmlDocPtr and an in memory buffer using gst_xml_parse_doc and gst_xml_parse_memory respectively. Both of these methods return a gboolean indicating success or failure of the requested action. Adding custom XML tags into the core XML data It is possible to add custom XML tags to the core XML created with gst_xml_write. This feature can be used by an application to add more information to the save plugins. The editor will for example insert the position of the elements on the screen using the custom XML tags. It is strongly suggested to save and load the custom XML tags using a namespace. This will solve the problem of having your XML tags interfere with the core XML tags. To insert a hook into the element saving procedure you can link a signal to the GstElement using the following piece of code: xmlNsPtr ns; ... ns = xmlNewNs (NULL, "http://gstreamer.net/gst-test/1.0/", "test"); ... thread = gst_element_factory_make ("thread", "thread"); g_signal_connect (G_OBJECT (thread), "object_saved", G_CALLBACK (object_saved), g_strdup ("decoder thread")); ... When the thread is saved, the object_save method will be called. Our example will insert a comment tag: static void object_saved (GstObject *object, xmlNodePtr parent, gpointer data) { xmlNodePtr child; child = xmlNewChild (parent, ns, "comment", NULL); xmlNewChild (child, ns, "text", (gchar *)data); } Adding the custom tag code to the above example you will get an XML file with the custom tags in it. Here's an excerpt: ... <gst:element> <gst:name>thread</gst:name> <gst:type>thread</gst:type> <gst:version>0.1.0</gst:version> ... </gst:children> <test:comment> <test:text>decoder thread</test:text> </test:comment> </gst:element> ... To retrieve the custom XML again, you need to attach a signal to the GstXML object used to load the XML data. You can then parse your custom XML from the XML tree whenever an object is loaded. We can extend our previous example with the following piece of code. xml = gst_xml_new (); g_signal_connect (G_OBJECT (xml), "object_loaded", G_CALLBACK (xml_loaded), xml); ret = gst_xml_parse_file (xml, "xmlTest.gst", NULL); g_assert (ret == TRUE); Whenever a new object has been loaded, the xml_loaded function will be called. This function looks like: static void xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data) { xmlNodePtr children = self->xmlChildrenNode; while (children) { if (!strcmp (children->name, "comment")) { xmlNodePtr nodes = children->xmlChildrenNode; while (nodes) { if (!strcmp (nodes->name, "text")) { gchar *name = g_strdup (xmlNodeGetContent (nodes)); g_print ("object %s loaded with comment '%s'\n", gst_object_get_name (object), name); } nodes = nodes->next; } } children = children->next; } } As you can see, you'll get a handle to the GstXML object, the newly loaded GstObject and the xmlNodePtr that was used to create this object. In the above example we look for our special tag inside the XML tree that was used to load the object and we print our comment to the console. Appendices By now, you've learned all about the internals of GStreamer and application programming using the GStreamer framework. This part will go into some random bits that are useful to know if you're going to use GStreamer for serious application programming. It will touch upon things related to integration with popular desktop environments that we run on (GNOME, KDE, OS X, Windows), it will shortly explain how applications included with GStreamer can help making your life easier, and some information on debugging. Things to check when writing an application This chapter contains a fairly random selection of things that can be useful to keep in mind when writing GStreamer-based applications. It's up to you how much you're going to use the information provided here. We will shortly discuss how to debug pipeline problems using GStreamer applications. Also, we will touch upon how to acquire knowledge about plugins and elements and how to test simple pipelines before building applications around them. Good programming habits Always connect to the error signal of your topmost pipeline to be notified of errors in your pipeline. Always check return values of GStreamer functions. Especially, check return values of gst_element_link () and gst_element_set_state (). Always use your pipeline object to keep track of the current state of your pipeline. Don't keep private variables in your application. Also, don't update your user interface if a user presses the play button. Instead, connect to the state-changed signal of your topmost pipeline and update the user interface whenever this signal is triggered. Debugging Applications can make use of the extensive GStreamer debugging system to debug pipeline problems. Elements will write output to this system to log what they're doing. It's not used for error reporting, but it is very useful for tracking what an element is doing exactly, which can come in handy when debugging application issues (such as failing seeks, out-of-sync media, etc.). Most GStreamer-based applications accept the commandline option --gst-debug=LIST and related family members. The list consists of a comma-separated list of category/level pairs, which can set the debugging level for a specific debugging category. For example, --gst-debug=oggdemux:5 would turn on debugging for the Ogg demuxer element. You can use wildcards as well. A debugging level of 0 will turn off all debugging, and a level of 5 will turn on all debugging. Intermediate values only turn on some debugging (based on message severity; 2, for example, will only display errors and warnings). Here's a list of all available options: --gst-debug-help will print available debug categories and exit. --gst-debug-level=LEVEL will set the default debug level (which can range from 0 (no output) to 5 (everything)). --gst-debug=LIST takes a comma-separated list of category_name:level pairs to set specific levels for the individual categories. Example: GST_AUTOPLUG:5,avidemux:3. --gst-debug-no-color will disable color debugging. --gst-debug-disable disables debugging alltogether. --gst-plugin-spew enables printout of errors while loading GStreamer plugins. Conversion plugins GStreamer contains a bunch of conversion plugins that most applications will find useful. Specifically, those are videoscalers (videoscale), colorspace convertors (ffmpegcolorspace), audio format convertors and channel resamplers (audioconvert) and audio samplerate convertors (audioscale). Those convertors don't do anything when not required, they will act in passthrough mode. They will activate when the hardware doesn't support a specific request, though. All applications are recommended to use those elements. Utility applications provided with GStreamer GStreamer comes with a default set of command-line utilities that can help in application development. We will discuss only gst-launch and gst-inspect here. gst-launch gst-launch is a simple script-like commandline application that can be used to test pipelines. For example, the command gst-launch sinesrc ! alsasink will run a pipeline which generates a sine-wave audio stream and plays it to your ALSA audio card. gst-launch also allows the use of threads (using curly brackets, so { and }) and bins (using brackets, so ( and )). You can use dots to imply padnames on elements, or even omit the padname to automatically select a pad. Using all this, the pipeline gst-launch filesrc location=file.ogg ! oggdemux name=d { d. ! theoradec ! ffmpegcolorspace ! xvimagesink } { d. ! vorbisdec ! alsasink } will play an Ogg file containing a Theora video-stream and a Vorbis audio-stream. You can also use autopluggers such as decodebin on the commandline. See the manual page of gst-launch for more information. gst-inspect gst-inspect can be used to inspect all properties, signals, dynamic parameters and the object hierarchy of an element. This can be very useful to see which GObject properties or which signals (and using what arguments) an element supports. Run gst-inspect fakesrc to get an idea of what it does. See the manual page of gst-inspect for more information. Integration GStreamer tries to integrate closely with operating systems (such as Linux and UNIX-like operating systems, OS X or Windows) and desktop environments (such as GNOME or KDE). In this chapter, we'll mention some specific techniques to integrate your application with your operating system or desktop environment of choice. Linux and UNIX-like operating systems GStreamer provides a basic set of elements that are useful when integrating with Linux or a UNIX-like operating system. For audio input and output, GStreamer provides input and output elements for several audio subsystems. Amongst others, GStreamer includes elements for ALSA (alsasrc, alsamixer, alsasink), OSS (osssrc, ossmixer, osssink) and Sun audio (sunaudiosrc, sunaudiomixer, sunaudiosink). For video input, GStreamer contains source elements for Video4linux (v4lsrc, v4lmjpegsrc, v4lelement and v4lmjpegisnk) and Video4linux2 (v4l2src, v4l2element). For video output, GStreamer provides elements for output to X-windows (ximagesink), Xv-windows (xvimagesink; for hardware-accelerated video), direct-framebuffer (dfbimagesink) and openGL image contexts (glsink). GNOME desktop GStreamer has been the media backend of the GNOME desktop since GNOME-2.2 onwards. Nowadays, a whole bunch of GNOME applications make use of GStreamer for media-processing, including (but not limited to) Rhythmbox, Totem and Sound Juicer. Most of these GNOME applications make use of some specific techniques to integrate as closely as possible with the GNOME desktop: GNOME applications call gnome_program_init () to parse command-line options and initialize the necessary gnome modules. GStreamer applications would normally call gst_init () to do the same for GStreamer. This would mean that only one of the two can parse command-line options. To work around this issue, GStreamer can provide a poptOption array which can be passed to gnome_program_init (). #include <gnome.h> #include <gst/gst.h> gint main (gint argc, gchar *argv[]) { struct poptOption options[] = { {NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL}, POPT_TABLEEND }; /* init GStreamer and GNOME using the GStreamer popt tables */ options[0].arg = (void *) gst_init_get_popt_table (); gnome_program_init ("my-application", "0.0.1", LIBGNOMEUI_MODULE, argc, argv, GNOME_PARAM_POPT_TABLE, options, NULL); [..] } GNOME stores the default video and audio sources and sinks in GConf. GStreamer provides a small utility library that can be used to get the elements from the registry using functions such as gst_gconf_get_default_video_sink (). See the header file (gst/gconf/gconf.h) for details. All GNOME applications are recommended to use those variables. GStreamer provides data input/output elements for use with the GNOME-VFS system. These elements are called gnomevfssrc and gnomevfssink. KDE desktop GStreamer has been proposed for inclusion in KDE-4.0. Currently, GStreamer is included as an optional component, and it's used by several KDE applications, including AmaroK and JuK. A backend for KMPlayer is currently under development. Although not yet as complete as the GNOME integration bits, there are already some KDE integration specifics available. This list will probably grow as GStreamer starts to be used in KDE-4.0: AmaroK contains a kiosrc element, which is a source element that integrates with the KDE VFS subsystem KIO. OS X GStreamer provides native video and audio output elements for OS X. It builds using the standard development tools for OS X. Windows GStreamer builds using Microsoft Visual C .NET 2003 and using Cygwin. Licensing advisoryHow to license the applications you build with GStreamer The licensing of GStreamer is no different from a lot of other libraries out there like GTK+ or glibc: we use the LGPL. What complicates things with regards to GStreamer is its plugin-based design and the heavily patented and proprietary nature of many multimedia codecs. While patents on software are currently only allowed in a small minority of world countries (the US and Australia being the most important of those), the problem is that due to the central place the US hold in the world economy and the computing industry, software patents are hard to ignore wherever you are. Due to this situation, many companies, including major GNU/Linux distributions, get trapped in a situation where they either get bad reviews due to lacking out-of-the-box media playback capabilities (and attempts to educate the reviewers have met with little success so far), or go against their own - and the free software movement's - wish to avoid proprietary software. Due to competitive pressure, most choose to add some support. Doing that through pure free software solutions would have them risk heavy litigation and punishment from patent owners. So when the decision is made to include support for patented codecs, it leaves them the choice of either using special proprietary applications, or try to integrate the support for these codecs through proprietary plugins into the multimedia infrastructure provided by GStreamer. Faced with one of these two evils the GStreamer community of course prefer the second option. The problem which arises is that most free software and open source applications developed use the GPL as their license. While this is generally a good thing, it creates a dilemma for people who want to put together a distribution. The dilemma they face is that if they include proprietary plugins in GStreamer to support patented formats in a way that is legal for them, they do risk running afoul of the GPL license of the applications. We have gotten some conflicting reports from lawyers on whether this is actually a problem, but the official stance of the FSF is that it is a problem. We view the FSF as an authority on this matter, so we are inclined to follow their interpretation of the GPL license. So what does this mean for you as an application developer? Well, it means you have to make an active decision on whether you want your application to be used together with proprietary plugins or not. What you decide here will also influence the chances of commercial distributions and Unix vendors shipping your application. The GStreamer community suggest you license your software using a license that will allow proprietary plugins to be bundled with GStreamer and your applications, in order to make sure that as many vendors as possible go with GStreamer instead of less free solutions. This in turn we hope and think will let GStreamer be a vehicle for wider use of free formats like the Xiph.org formats. If you do decide that you want to allow for non-free plugins to be used with your application you have a variety of choices. One of the simplest is using licenses like LGPL, MPL or BSD for your application instead of the GPL. Or you can add a exceptions clause to your GPL license stating that you except GStreamer plugins from the obligations of the GPL. A good example of such a GPL exception clause would be, using the Muine music player project as an example: The Muine project hereby grants permission for non-GPL-compatible GStreamer plugins to be used and distributed together with GStreamer and Muine. This permission goes above and beyond the permissions granted by the GPL license Muine is covered by. Our suggestion among these choices is to use the LGPL license, as it is what resembles the GPL most and it makes it a good licensing fit with the major GNU/Linux desktop projects like GNOME and KDE. It also allows you to share code more openly with projects that have compatible licenses. Obviously, pure GPL code without the above-mentioned clause is not usable in your application as such. By choosing the LGPL, there is no need for an exception clause and thus code can be shared more freely. I have above outlined the practical reasons for why the GStreamer community suggest you allow non-free plugins to be used with your applications. We feel that in the multimedia arena, the free software community is still not strong enough to set the agenda and that blocking non-free plugins to be used in our infrastructure hurts us more than it hurts the patent owners and their ilk. This view is not shared by everyone. The Free Software Foundation urges you to use an unmodified GPL for your applications, so as to push back against the temptation to use non-free plug-ins. They say that since not everyone else has the strength to reject them because they are unethical, they ask your help to give them a legal reason to do so. This advisory is part of a bigger advisory with a FAQ which you can find on the GStreamer website Windows supportBuilding GStreamer under Win32There are different makefiles that can be used to build GStreamer with the usual Microsoft compiling tools.The Makefile is meant to be used with the GNU make program and the free version of the Microsoft compiler (http://msdn.microsoft.com/visualc/vctoolkit2003/). You also have to modify your system environment variables to use it from the command-line. You will also need a working Platform SDK for Windows that is available for free from Microsoft.The projects/makefiles will generate automatically some source files needed to compile GStreamer. That requires that you have installed on your system some GNU tools and that they are available in your system PATH.The GStreamer project depends on other libraries, namely :GLibpoptlibxml2libintllibiconvThere is now an existing package that has all these dependencies built with MSVC7.1. It exists either as precompiled librairies and headers in both Release and Debug mode, or as the source package to build it yourself. You can find it on http://mukoli.free.fr/gstreamer/deps/.NotesGNU tools needed that you can find on http://gnuwin32.sourceforge.net/GNU flex (tested with 2.5.4)GNU bison (tested with 1.35)and http://www.mingw.org/GNU make (tested with 3.80)the generated files from the -auto makefiles will be available soon separately on the net for convenience (people who don't want to install GNU tools).Installation on the systemBy default, GSTreamer needs a registry. You have to generate it using "gst-register.exe". It will create the file in c:\gstreamer\registry.xml that will hold all the plugins you can use.You should install the GSTreamer core in c:\gstreamer\bin and the plugins in c:\gstreamer\plugins. Both directories should be added to your system PATH. The library dependencies should be installed in c:\usrFor example, my current setup is :c:\gstreamer\registry.xmlc:\gstreamer\bin\gst-inspect.exec:\gstreamer\bin\gst-launch.exec:\gstreamer\bin\gst-register.exec:\gstreamer\bin\gstbytestream.dllc:\gstreamer\bin\gstelements.dllc:\gstreamer\bin\gstoptimalscheduler.dllc:\gstreamer\bin\gstspider.dllc:\gstreamer\bin\libgtreamer-0.8.dllc:\gstreamer\plugins\gst-libs.dllc:\gstreamer\plugins\gstmatroska.dllc:\usr\bin\iconv.dllc:\usr\bin\intl.dllc:\usr\bin\libglib-2.0-0.dllc:\usr\bin\libgmodule-2.0-0.dllc:\usr\bin\libgobject-2.0-0.dllc:\usr\bin\libgthread-2.0-0.dllc:\usr\bin\libxml2.dllc:\usr\bin\popt.dllQuotes from the Developers As well as being a cool piece of software, GStreamer is a lively project, with developers from around the globe very actively contributing. We often hang out on the #gstreamer IRC channel on irc.freenode.net: the following are a selection of amusingNo guarantee of sense of humour compatibility is given. quotes from our conversations. 14 Oct 2004 * zaheerm wonders how he can break gstreamer today :) ensonic: zaheerm, spider is always a good starting point 14 Jun 2004 teuf: ok, things work much better when I don't write incredibly stupid and buggy code thaytan: I find that too 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 --- wingo-party is now known as wingo * wingo holds head 16 Feb 2001 wtay: I shipped a few commerical products to >40000 people now but GStreamer is way more exciting... 16 Feb 2001 * tool-man is a gstreamer groupie 14 Jan 2001 Omega: did you run ldconfig? maybe it talks to init? wtay: not sure, don't think so... I did run gstreamer-register though :-) Omega: ah, that did it then ;-) wtay: right Omega: probably not, but in case GStreamer starts turning into an OS, someone please let me know? 9 Jan 2001 wtay: me tar, you rpm? wtay: hehe, forgot "zan" Omega: ? wtay: me tar"zan", you ... 7 Jan 2001 Omega: that means probably building an agreggating, cache-massaging queue to shove N buffers across all at once, forcing cache transfer. wtay: never done that before... Omega: nope, but it's easy to do in gstreamer <g> wtay: sure, I need to rewrite cp with gstreamer too, someday :-) 7 Jan 2001 wtay: GStreamer; always at least one developer is awake... 5/6 Jan 2001 wtay: we need to cut down the time to create an mp3 player down to seconds... richardb: :) Omega: I'm wanting to something more interesting soon, I did the "draw an mp3 player in 15sec" back in October '99. wtay: by the time Omega gets his hands on the editor, you'll see a complete audio mixer in the editor :-) richardb: Well, it clearly has the potential... Omega: Working on it... ;-) 28 Dec 2000 MPAA: We will sue you now, you have violated our IP rights! wtay: hehehe MPAA: How dare you laugh at us? We have lawyers! We have Congressmen! We have LARS! wtay: I'm so sorry your honor MPAA: Hrumph. * wtay bows before thy 4 Jun 2001taaz: you witchdoctors and your voodoo mpeg2 black magic... omega_: um. I count three, no four different cults there <g> ajmitch: hehe omega_: witchdoctors, voodoo, black magic, omega_: and mpeg Done. Copying .css files: base.css Copying .png images: build/images/bin-element-ghost.png build/images/bin-element-noghost.png build/images/bin-element.png build/images/filter-element-multi.png build/images/filter-element.png build/images/hello-world.png build/images/linked-elements.png build/images/mime-world.png build/images/queue.png build/images/sink-element.png build/images/src-element.png build/images/state-diagram.png build/images/thread.png make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' make[3]: Nothing to be done for `install-exec-am'. make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' cd build && xmllint -noout -valid manual.xml make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual/build/manual.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" WimTaymans wim.taymans@chello.be SteveBaker stevebaker_org@yahoo.co.uk AndyWingo wingo@pobox.com RonaldS.Bultje rbultje@ronald.bitfreak.net This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/opl.shtml). GStreamer Application Development Manual (0.8.11)Overview GStreamer is an exremely powerful and versatile framework for creating streaming media applications. Many of the virtues of the GStreamer framework come from its modularity: GStreamer can seamlessly incorporate new plugin modules. But because modularity and power often come at a cost of greater complexity (consider, for example, CORBA), writing new applications is not always easy. This guide is intended to help you understand the GStreamer framework (version 0.8.11) so you can develop applications based on it. The first chapters will focus on development of a simple audio player, with much effort going into helping you understand GStreamer concepts. Later chapters will go into more advanced topics related to media playback, but also at other forms of media processing (capture, editing, etc.). Introduction This chapter gives you an overview of the technologies described in this book. What is GStreamer? GStreamer is a framework for creating streaming media applications. The fundamental design comes from the video pipeline at Oregon Graduate Institute, as well as some ideas from DirectShow. GStreamer's development framework makes it possible to write any type of streaming multimedia application. The GStreamer framework is designed to make it easy to write applications that handle audio or video or both. It isn't restricted to audio and video, and can process any kind of data flow. The pipeline design is made to have little overhead above what the applied filters induce. This makes GStreamer a good framework for designing even high-end audio applications which put high demands on latency. One of the the most obvious uses of GStreamer is using it to build a media player. GStreamer already includes components for building a media player that can support a very wide variety of formats, including MP3, Ogg/Vorbis, MPEG-1/2, AVI, Quicktime, mod, and more. GStreamer, however, is much more than just another media player. Its main advantages are that the pluggable components can be mixed and matched into arbitrary pipelines so that it's possible to write a full-fledged video or audio editing application. The framework is based on plugins that will provide the various codec and other functionality. The plugins can be linked and arranged in a pipeline. This pipeline defines the flow of the data. Pipelines can also be edited with a GUI editor and saved as XML so that pipeline libraries can be made with a minimum of effort. The GStreamer core function is to provide a framework for plugins, data flow and media type handling/negotiation. It also provides an API to write applications using the various plugins. Structure of this Manual This book is about GStreamer from a developer's point of view; it describes how to write a GStreamer application using the GStreamer libraries and tools. For an explanation about writing plugins, we suggest the Plugin Writers Guide. gives you an overview of GStreamer's motivation design goals. rapidly covers the basics of GStreamer application programming. At the end of that chapter, you should be able to build your own audio player using GStreamer In , we will move on to complicated subjects which make GStreamer stand out of its competitors. We will discuss application-pipeline interaction using dynamic parameters and interfaces, we will discuss threading and threaded pipelines, scheduling and clocks (and synchronization). Most of those topics are not just there to introduce you to their API, but primarily to give a deeper insight in solving application programming problems with GStreamer and understanding their concepts. Next, in , we will go into higher-level programming APIs for GStreamer. You don't exactly need to know all the details from the previous parts to understand this, but you will need to understand basic GStreamer concepts nevertheless. We will, amongst others, discuss XML, playbin and autopluggers. In , you will find some random information on integrating with GNOME, KDE, OS X or Windows, some debugging help and general tips to improve and simplify GStreamer programming. In order to understand this manual, you will need to have a basic understanding of the C language. Since GStreamer uses GLib 2.0, the reader is assumed to understand the basics of the GObject object model. It is recommended to have skimmed through the introduction of the GObject tutorial before reading this. You may also want to have a look at Eric Harlow's book Developing Linux Applications with GTK+ and GDK. Motivation & Goals Linux has historically lagged behind other operating systems in the multimedia arena. Microsoft's Windows and Apple's MacOS both have strong support for multimedia devices, multimedia content creation, playback, and realtime processing. Linux, on the other hand, has a poorly integrated collection of multimedia utilities and applications available, which can hardly compete with the professional level of software available for MS Windows and MacOS. GStreamer was designed to provide a solution to the current Linux media problems. Current problems We describe the typical problems in today's media handling on Linux. Multitude of duplicate code The Linux user who wishes to hear a sound file must hunt through their collection of sound file players in order to play the tens of sound file formats in wide use today. Most of these players basically reimplement the same code over and over again. The Linux developer who wishes to embed a video clip in their application must use crude hacks to run an external video player. There is no library available that a developer can use to create a custom media player. 'One goal' media players/libraries Your typical MPEG player was designed to play MPEG video and audio. Most of these players have implemented a complete infrastructure focused on achieving their only goal: playback. No provisions were made to add filters or special effects to the video or audio data. If you want to convert an MPEG-2 video stream into an AVI file, your best option would be to take all of the MPEG-2 decoding algorithms out of the player and duplicate them into your own AVI encoder. These algorithms cannot easily be shared across applications. Attempts have been made to create libraries for handling various media types. Because they focus on a very specific media type (avifile, libmpeg2, ...), significant work is needed to integrate them due to a lack of a common API. GStreamer allows you to wrap these libraries with a common API, which significantly simplifies integration and reuse. Non unified plugin mechanisms Your typical media player might have a plugin for different media types. Two media players will typically implement their own plugin mechanism so that the codecs cannot be easily exchanged. The plugin system of the typical media player is also very tailored to the specific needs of the application. The lack of a unified plugin mechanism also seriously hinders the creation of binary only codecs. No company is willing to port their code to all the different plugin mechanisms. While GStreamer also uses it own plugin system it offers a very rich framework for the plugin developer and ensures the plugin can be used in a wide range of applications, transparently interacting with other plugins. The framework that GStreamer provides for the plugins is flexible enough to host even the most demanding plugins. Poor user experience Because of the problems mentioned above, application authors have so far often been urged to spend a considerable amount of time in writing their own backends, plugin mechanisms and so on. The result has often been, unfortunately, that both the backend as well as the user interface were only half-finished. Demotivated, the application authors would start rewriting the whole thing and complete the circle. This leads to a poor end user experience. Provision for network transparency No infrastructure is present to allow network transparent media handling. A distributed MPEG encoder will typically duplicate the same encoder algorithms found in a non-distributed encoder. No provisions have been made for technologies such as the GNOME object embedding using Bonobo. The GStreamer core does not use network transparent technologies at the lowest level as it only adds overhead for the local case. That said, it shouldn't be hard to create a wrapper around the core components. There are tcp plugins now that implement a GStreamer Data Protocol that allows pipelines to be slit over TCP. These are located in the gst-plugins module directory gst/tcp. Catch up with the Windows world We need solid media handling if we want to see Linux succeed on the desktop. We must clear the road for commercially backed codecs and multimedia applications so that Linux can become an option for doing multimedia. The design goals We describe what we try to achieve with GStreamer. Clean and powerful GStreamer wants to provide a clean interface to: The application programmer who wants to build a media pipeline. The programmer can use an extensive set of powerful tools to create media pipelines without writing a single line of code. Performing complex media manipulations becomes very easy. The plugin programmer. Plugin programmers are provided a clean and simple API to create self-contained plugins. An extensive debugging and tracing mechanism has been integrated. GStreamer also comes with an extensive set of real-life plugins that serve as examples too. Object oriented GStreamer adheres to the GLib 2.0 object model. A programmer familiar with GLib 2.0 or older versions of GTK+ will be comfortable with GStreamer. GStreamer uses the mechanism of signals and object properties. All objects can be queried at runtime for their various properties and capabilities. GStreamer intends to be similar in programming methodology to GTK+. This applies to the object model, ownership of objects, reference counting, ... Extensible All GStreamer Objects can be extended using the GObject inheritance methods. All plugins are loaded dynamically and can be extended and upgraded independently. Allow binary only plugins Plugins are shared libraries that are loaded at runtime. Since all the properties of the plugin can be set using the GObject properties, there is no need (and in fact no way) to have any header files installed for the plugins. Special care has been taken to make plugins completely self-contained. All relevant aspects of plugins can be queried at run-time. High performance High performance is obtained by: using GLib's g_mem_chunk and fast non-blocking allocation algorithms where possible to minimize dynamic memory allocation. extremely light-weight links between plugins. Data can travel the pipeline with minimal overhead. Data passing between plugins only involves a pointer dereference in a typical pipeline. providing a mechanism to directly work on the target memory. A plugin can for example directly write to the X server's shared memory space. Buffers can also point to arbitrary memory, such as a sound card's internal hardware buffer. refcounting and copy on write minimize usage of memcpy. Sub-buffers efficiently split buffers into manageable pieces. the use of cothreads to minimize the threading overhead. Cothreads are a simple and fast user-space method for switching between subtasks. Cothreads were measured to consume as little as 600 cpu cycles. allowing hardware acceleration by using specialized plugins. using a plugin registry with the specifications of the plugins so that the plugin loading can be delayed until the plugin is actually used. all critical data passing is free of locks and mutexes. Clean core/plugins separation The core of GStreamer is essentially media-agnostic. It only knows about bytes and blocks, and only contains basic elements. The core of GStreamer is functional enough to even implement low-level system tools, like cp. All of the media handling functionality is provided by plugins external to the core. These tell the core how to handle specific types of media. Provide a framework for codec experimentation GStreamer also wants to be an easy framework where codec developers can experiment with different algorithms, speeding up the development of open and free multimedia codecs like Theora and Vorbis. Foundations This chapter of the guide introduces the basic concepts of GStreamer. Understanding these concepts will be important in reading any of the rest of this guide, all of them assume understanding of these basic concepts. Elements An element is the most important class of objects in GStreamer. You will usually create a chain of elements linked together and let data flow through this chain of elements. An element has one specific function, which can be the reading of data from a file, decoding of this data or outputting this data to your sound card (or anything else). By chaining together several such elements, you create a pipeline that can do a specific task, for example media playback or capture. GStreamer ships with a large collection of elements by default, making the development of a large variety of media applications possible. If needed, you can also write new elements. That topic is explained in great deal in the Plugin Writer's Guide. Bins and pipelines A bin is a container for a collection of elements. A pipeline is a special subtype of a bin that allows execution of all of its contained child elements. Since bins are subclasses of elements themselves, you can mostly control a bin as if it where an element, thereby abstracting away a lot of complexity for your application. You can, for example change state on all elements in a bin by changing the state of that bin itself. Bins also forward some signals from their contained childs (such as errors and tags). A pipeline is a bin that allows to run (technically referred to as iterating) its contained childs. By iterating a pipeline, data flow will start and media processing will take place. A pipeline requires iterating for anything to happen. you can also use threads, which automatically iterate the contained childs in a newly created threads. We will go into this in detail later on. Pads Pads are used to negotiate links and data flow between elements in GStreamer. A pad can be viewed as a plug or port on an element where links may be made with other elements, and through which data can flow to or from those elements. Pads have specific data handling capabilities: A pad can restrict the type of data that flows through it. Links are only allowed between two pads when the allowed data types of the two pads are compatible. Data types are negotiated between pads using a process called caps negotiation. Data types are described as a GstCaps. An analogy may be helpful here. A pad is similar to a plug or jack on a physical device. Consider, for example, a home theater system consisting of an amplifier, a DVD player, and a (silent) video projector. Linking the DVD player to the amplifier is allowed because both devices have audio jacks, and linking the projector to the DVD player is allowed because both devices have compatible video jacks. Links between the projector and the amplifier may not be made because the projector and amplifier have different types of jacks. Pads in GStreamer serve the same purpose as the jacks in the home theater system. For the most part, all data in GStreamer flows one way through a link between elements. Data flows out of one element through one or more source pads, and elements accept incoming data through one or more sink pads. Source and sink elements have only source and sink pads, respectively. Data is embodied in a GstData structure. Basic Concepts In these chapters, we will discuss the basic concepts of GStreamer and the most-used objects, such as elements, pads and buffers. We will use a visual representation of these objects so that we can visualize the more complex pipelines you will learn to build later on. You will get a first glance at the GStreamer API, which should be enough for building elementary applications. Later on in this part, you will also learn to build a basic command-line application. Note that this part will give a look into the low-level API and concepts of GStreamer. Once you're going to build applications, you might want to use higher-level APIs. Those will be discussed later on in this manual. Initializing GStreamer When writing a GStreamer application, you can simply include gst/gst.h to get access to the library functions. Besides that, you will also need to intialize the GStreamer library. Simple initialization Before the GStreamer libraries can be used, gst_init has to be called from the main application. This call will perform the necessary initialization of the library as well as parse the GStreamer-specific command line options. A typical program The code for this example is automatically extracted from the documentation and built under examples/manual in the GStreamer tarball. would have code to initialize GStreamer that looks like this: #include <gst/gst.h> int main (int argc, char *argv[]) { guint major, minor, micro; gst_init (&argc, &argv); gst_version (&major, &minor, &micro); printf ("This program is linked against GStreamer %d.%d.%d\n", major, minor, micro); return 0; } Use the GST_VERSION_MAJOR, GST_VERSION_MINOR and GST_VERSION_MICRO macros to get the GStreamer version you are building against, or use the function gst_version to get the version your application is linked against. GStreamer currently uses a scheme where versions with the same major and minor versions are API-/ and ABI-compatible. It is also possible to call the gst_init function with two NULL arguments, in which case no command line options will be parsed by GStreamer. The popt interface You can also use a popt table to initialize your own parameters as shown in the next example: #include <gst/gst.h> int main (int argc, char *argv[]) { gboolean silent = FALSE; gchar *savefile = NULL; struct poptOption options[] = { {"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0, "do not output status information", NULL}, {"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0, "save xml representation of pipeline to FILE and exit", "FILE"}, POPT_TABLEEND }; gst_init_with_popt_table (&argc, &argv, options); printf ("Run me with --help to see the Application options appended.\n"); return 0; } As shown in this fragment, you can use a popt table to define your application-specific command line options, and pass this table to the function gst_init_with_popt_table. Your application options will be parsed in addition to the standard GStreamer options. Elements The most important object in GStreamer for the application programmer is the GstElement object. An element is the basic building block for a media pipeline. All the different high-level components you will use are derived from GstElement. Every decoder, encoder, demuxer, video or audio output is in fact a GstElement What are elements? For the application programmer, elements are best visualized as black boxes. On the one end, you might put something in, the element does something with it and something else comes out at the other side. For a decoder element, ifor example, you'd put in encoded data, and the element would output decoded data. In the next chapter (see ), you will learn more about data input and output in elements, and how you can set that up in your application. Source elements Source elements generate data for use by a pipeline, for example reading from disk or from a sound card. shows how we will visualise a source element. We always draw a source pad to the right of the element. Visualisation of a source element Source elements do not accept data, they only generate data. You can see this in the figure because it only has a source pad (on the right). A source pad can only generate data. Filters, convertors, demuxers, muxers and codecs Filters and filter-like elements have both input and outputs pads. They operate on data that they receive on their input (sink) pads, and will provide data on their output (source) pads. Examples of such elements are a volume element (filter), a video scaler (convertor), an Ogg demuxer or a Vorbis decoder. Filter-like elements can have any number of source or sink pads. A video demuxer, for example, would have one sink pad and several (1-N) source pads, one for each elementary stream contained in the container format. Decoders, on the other hand, will only have one source and sink pads. Visualisation of a filter element shows how we will visualise a filter-like element. This specific element has one source and one sink element. Sink pads, receiving input data, are depicted at the left of the element; source pads are still on the right. Visualisation of a filter element with more than one output pad shows another filter-like element, this one having more than one output (source) pad. An example of one such element could, for example, be an Ogg demuxer for an Ogg stream containing both audio and video. One source pad will contain the elementary video stream, another will contain the elementary audio stream. Demuxers will generally fire signals when a new pad is created. The application programmer can then handle the new elementary stream in the signal handler. Sink elements Sink elements are end points in a media pipeline. They accept data but do not produce anything. Disk writing, soundcard playback, and video output would all be implemented by sink elements. shows a sink element. Visualisation of a sink elementCreating a GstElement The simplest way to create an element is to use gst_element_factory_make (). This function takes a factory name and an element name for the newly created element. The name of the element is something you can use later on to look up the element in a bin, for example. The name will also be used in debug output. You can pass NULL as the name argument to get a unique, default name. When you don't need the element anymore, you need to unref it using gst_object_unref (). This decreases the reference count for the element by 1. An element has a refcount of 1 when it gets created. An element gets destroyed completely when the refcount is decreased to 0. The following example The code for this example is automatically extracted from the documentation and built under examples/manual in the GStreamer tarball. shows how to create an element named source from the element factory named fakesrc. It checks if the creation succeeded. After checking, it unrefs the element. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *element; /* init GStreamer */ gst_init (&argc, &argv); /* create element */ element = gst_element_factory_make ("fakesrc", "source"); if (!element) { g_print ("Failed to create element of type 'fakesrc'\n"); return -1; } gst_object_unref (GST_OBJECT (element)); return 0; } gst_element_factory_make is actually a shorthand for a combination of two functions. A GstElement object is created from a factory. To create the element, you have to get access to a GstElementFactory object using a unique factory name. This is done with gst_element_factory_find (). The following code fragment is used to get a factory that can be used to create the fakesrc element, a fake data source. The function gst_element_factory_create () will use the element factory to create an element with the given name. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElementFactory *factory; GstElement * element; /* init GStreamer */ gst_init (&argc, &argv); /* create element, method #2 */ factory = gst_element_factory_find ("fakesrc"); if (!factory) { g_print ("Failed to find factory of type 'fakesrc'\n"); return -1; } element = gst_element_factory_create (factory, "source"); if (!element) { g_print ("Failed to create element, even though its factory exists!\n"); return -1; } gst_object_unref (GST_OBJECT (element)); return 0; } Using an element as a GObject A GstElement can have several properties which are implemented using standard GObject properties. The usual GObject methods to query, set and get property values and GParamSpecs are therefore supported. Every GstElement inherits at least one property from its parent GstObject: the "name" property. This is the name you provide to the functions gst_element_factory_make () or gst_element_factory_create (). You can get and set this property using the functions gst_object_set_name and gst_object_get_name or use the GObject property mechanism as shown below. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *element; const gchar *name; /* init GStreamer */ gst_init (&argc, &argv); /* create element */ element = gst_element_factory_make ("fakesrc", "source"); /* get name */ g_object_get (G_OBJECT (element), "name", &name, NULL); g_print ("The name of the element is '%s'.\n", name); gst_object_unref (GST_OBJECT (element)); return 0; } Most plugins provide additional properties to provide more information about their configuration or to configure the element. gst-inspect is a useful tool to query the properties of a particular element, it will also use property introspection to give a short explanation about the function of the property and about the parameter types and ranges it supports. See the appendix for details about gst-inspect. For more information about GObject properties we recommend you read the GObject manual and an introduction to The Glib Object system. A GstElement also provides various GObject signals that can be used as a flexible callback mechanism. Here, too, you can use gst-inspect to see which signals a specific elements supports. Together, signals and properties are the most basic way in which elements and applications interact. More about element factories In the previous section, we briefly introduced the GstElementFactory object already as a way to create instances of an element. Element factories, however, are much more than just that. Element factories are the basic types retrieved from the GStreamer registry, they describe all plugins and elements that GStreamer can create. This means that element factories are useful for automated element instancing, such as what autopluggers do, and for creating lists of available elements, such as what pipeline editing applications (e.g. GStreamer Editor) do. Getting information about an element using a factory Tools like gst-inspect will provide some generic information about an element, such as the person that wrote the plugin, a descriptive name (and a shortname), a rank and a category. The category can be used to get the type of the element that can be created using this element factory. Examples of categories include Codec/Decoder/Video (video decoder), Codec/Encoder/Video (video encoder), Source/Video (a video generator), Sink/Video (a video output), and all these exist for audio as well, of course. Then, there's also Codec/Demuxer and Codec/Muxer and a whole lot more. gst-inspect will give a list of all factories, and gst-inspect <factory-name> will list all of the above information, and a lot more. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElementFactory *factory; /* init GStreamer */ gst_init (&argc, &argv); /* get factory */ factory = gst_element_factory_find ("sinesrc"); if (!factory) { g_print ("You don't have the 'sinesrc' element installed, go get it!\n"); return -1; } /* display information */ g_print ("The '%s' element is a member of the category %s.\n" "Description: %s\n", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), gst_element_factory_get_klass (factory), gst_element_factory_get_description (factory)); return 0; } You can use gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY) to get a list of all the element factories that GStreamer knows about. Finding out what pads an element can contain Perhaps the most powerful feature of element factories is that they contain a full description of the pads that the element can generate, and the capabilities of those pads (in layman words: what types of media can stream over those pads), without actually having to load those plugins into memory. This can be used to provide a codec selection list for encoders, or it can be used for autoplugging purposes for media players. All current GStreamer-based media players and autopluggers work this way. We'll look closer at these features as we learn about GstPad and GstCaps in the next chapter: Linking elements By linking a source element with zero or more filter-like elements and finally a sink element, you set up a media pipeline. Data will flow through the elements. This is the basic concept of media handling in GStreamer. Visualisation of three linked elements By linking these three elements, we have created a very simple chain of elements. The effect of this will be that the output of the source element (element1) will be used as input for the filter-like element (element2). The filter-like element will do something with the data and send the result to the final sink element (element3). Imagine the above graph as a simple Ogg/Vorbis audio decoder. The source is a disk source which reads the file from disc. The second element is a Ogg/Vorbis audio decoder. The sink element is your soundcard, playing back the decoded audio data. We will use this simple graph to construct an Ogg/Vorbis player later in this manual. In code, the above graph is written like this: #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *source, *filter, *sink; /* init */ gst_init (&argc, &argv); /* create elements */ source = gst_element_factory_make ("fakesrc", "source"); filter = gst_element_factory_make ("identity", "filter"); sink = gst_element_factory_make ("fakesink", "sink"); /* link */ gst_element_link_many (source, filter, sink, NULL); [..] } For more specific behaviour, there are also the functions gst_element_link () and gst_element_link_pads (). You can also obtain references to individual pads and link those using various gst_pad_link_* () functions. See the API references for more details. Element States After being created, an element will not actually perform any actions yet. You need to change elements state to make it do something. GStreamer knows four element states, each with a very specific meaning. Those four states are: GST_STATE_NULL: this is the default state. This state will deallocate all resources held by the element. GST_STATE_READY: in the ready state, an element has allocated all of its global resources, that is, resources that can be kept within streams. You can think about opening devices, allocating buffers and so on. However, the stream is not opened in this state, so the stream positions is automatically zero. If a stream was previously opened, it should be closed in this state, and position, properties and such should be reset. GST_STATE_PAUSED: in this state, an element has opened the stream, but is not actively processing it. An element should not modify the stream's position, data or anything else in this state. When set back to PLAYING, it should continue processing at the point where it left off as soon as possible. GST_STATE_PLAYING: in the PLAYING state, an element does exactly the same as in the PAUSED state, except that it actually processes data. You can change the state of an element using the function gst_element_set_state (). If you set an element to another state, GStreamer will internally traverse all intermediate states. So if you set an element from NULL to PLAYING, GStreamer will internally set the element to READY and PAUSED in between. Even though an element in GST_STATE_PLAYING is ready for data processing, it will not necessarily do that. If the element is placed in a thread (see ), it will process data automatically. In other cases, however, you will need to iterate the element's container. Bins A bin is a container element. You can add elements to a bin. Since a bin is an element itself, a bin can be handled in the same way as any other element. Therefore, the whole previous chapter () applies to bins as well. What are bins Bins allow you to combine a group of linked elements into one logical element. You do not deal with the individual elements anymore but with just one element, the bin. We will see that this is extremely powerful when you are going to construct complex pipelines since it allows you to break up the pipeline in smaller chunks. The bin will also manage the elements contained in it. It will figure out how the data will flow in the bin and generate an optimal plan for that data flow. Plan generation is one of the most complicated procedures in GStreamer. You will learn more about this process, called scheduling, in . Visualisation of a bin with some elements in it There are two specialized types of bins available to the GStreamer programmer: A pipeline: a generic container that allows scheduling of the containing elements. The toplevel bin has to be a pipeline. Every application thus needs at least one of these. Applications can iterate pipelines using gst_bin_iterate () to make it process data while in the playing state. A thread: a bin that will be run in a separate execution thread. You will have to use this bin if you have to carefully synchronize audio and video, or for buffering. You will learn more about threads in . Creating a bin Bins are created in the same way that other elements are created, i.e. using an element factory. There are also convenience functions available (gst_bin_new (), gst_thread_new () and gst_pipeline_new ()). To add elements to a bin or remove elements from a bin, you can use gst_bin_add () and gst_bin_remove (). Note that the bin that you add an element to will take ownership of that element. If you destroy the bin, the element will be dereferenced with it. If you remove an element from a bin, it will be dereferenced automatically. #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *bin, *pipeline, *source, *sink; /* init */ gst_init (&argc, &argv); /* create */ pipeline = gst_pipeline_new ("my_pipeline"); bin = gst_pipeline_new ("my_bin"); source = gst_element_factory_make ("fakesrc", "source"); sink = gst_element_factory_make ("fakesink", "sink"); /* set up pipeline */ gst_bin_add_many (GST_BIN (bin), source, sink, NULL); gst_bin_add (GST_BIN (pipeline), bin); gst_element_link (source, sink); [..] } There are various functions to lookup elements in a bin. You can also get a list of all elements that a bin contains using the function gst_bin_get_list (). See the API references of GstBin for details. Custom bins The application programmer can create custom bins packed with elements to perform a specific task. This allows you, for example, to write an Ogg/Vorbis decoder with just the following lines of code: int main (int argc char *argv[]) { GstElement *player; /* init */ gst_init (&argc, &argv); /* create player */ player = gst_element_factory_make ("oggvorbisplayer", "player"); /* set the source audio file */ g_object_set (G_OBJECT (player), "location", "helloworld.ogg", NULL); /* start playback */ gst_element_set_state (GST_ELEMENT (player), GST_STATE_PLAYING); [..] } Custom bins can be created with a plugin or an XML description. You will find more information about creating custom bin in the Plugin Writers Guide. Pads and capabilities As we have seen in , the pads are the element's interface to the outside world. Data streams from one element's source pad to another element's sink pad. The specific type of media that the element can handle will be exposed by the pad's capabilities. We will talk more on capabilities later in this chapter (see ). Pads A pad type is defined by two properties: its direction and its availability. As we've mentioned before, GStreamer defines two pad directions: source pads and sink pads. This terminology is defined from the view of within the element: elements receive data on their sink pads and generate data on their source pads. Schematically, sink pads are drawn on the left side of an element, whereas source pads are drawn on the right side of an element. In such graphs, data flows from left to right. In reality, there is no objection to data flowing from a source pad to the sink pad of an element upstream (to the left of this element in drawings). Data will, however, always flow from a source pad of one element to the sink pad of another. Pad directions are very simple compared to pad availability. A pad can have any of three availabilities: always, sometimes and on request. The meaning of those three types is exactly as it says: always pads always exist, sometimes pad exist only in certain cases (and can disappear randomly), and on-request pads appear only if explicitely requested by applications. Dynamic (or sometimes) pads Some elements might not have all of their pads when the element is created. This can happen, for example, with an Ogg demuxer element. The element will read the Ogg stream and create dynamic pads for each contained elementary stream (vorbis, theora) when it detects such a stream in the Ogg stream. Likewise, it will delete the pad when the stream ends. This principle is very useful for demuxer elements, for example. Running gst-inspect oggdemux will show that the element has only one pad: a sink pad called 'sink'. The other pads are dormant. You can see this in the pad template because there is an Exists: Sometimes property. Depending on the type of Ogg file you play, the pads will be created. We will see that this is very important when you are going to create dynamic pipelines. You can attach a signal handler to an element to inform you when the element has created a new pad from one of its sometimes pad templates. The following piece of code is an example of how to do this: #include <gst/gst.h> static void cb_new_pad (GstElement *element, GstPad *pad, gpointer data) { g_print ("A new pad %s was created\n", gst_pad_get_name (pad)); /* here, you would setup a new pad link for the newly created pad */ [..] } int main(int argc, char *argv[]) { GstElement *pipeline, *source, *demux; /* init */ gst_init (&argc, &argv); /* create elements */ pipeline = gst_pipeline_new ("my_pipeline"); source = gst_element_factory_make ("filesrc", "source"); g_object_set (source, "location", argv[1], NULL); demux = gst_element_factory_make ("oggdemux", "demuxer"); /* you would normally check that the elements were created properly */ /* put together a pipeline */ gst_bin_add_many (GST_BIN (pipeline), source, demux, NULL); gst_element_link (source, demux); /* listen for newly created pads */ g_signal_connect (demux, "new-pad", G_CALLBACK (cb_new_pad), NULL); /* start the pipeline */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); [..] } Request pads An element can also have request pads. These pads are not created automatically but are only created on demand. This is very useful for multiplexers, aggregators and tee elements. Aggregators are elements that merge the content of several input streams together into one output stream. Tee elements are the reverse: they are elements that have one input stream and copy this stream to each of their output pads, which are created on request. Whenever an application needs another copy of the stream, it can simply request a new output pad from the tee element. The following piece of code shows how you can request a new output pad from a tee element: static void some_function (GstElement *tee) { GstPad * pad; pad = gst_element_get_request_pad (tee, "src%d"); g_print ("A new pad %s was created\n", gst_pad_get_name (pad)); /* here, you would link the pad */ [..] } The gst_element_get_request_pad () method can be used to get a pad from the element based on the name of the pad template. It is also possible to request a pad that is compatible with another pad template. This is very useful if you want to link an element to a multiplexer element and you need to request a pad that is compatible. The method gst_element_get_compatible_pad () can be used to request a compatible pad, as shown in the next example. It will request a compatible pad from an Ogg multiplexer from any input. static void link_to_multiplexer (GstPad *tolink_pad, GstElement *mux) { GstPad *pad; pad = gst_element_get_compatible_pad (mux, tolink_pad); gst_pad_link (tolinkpad, pad); g_print ("A new pad %s was created and linked to %s\n", gst_pad_get_name (pad), gst_pad_get_name (tolink_pad)); } Capabilities of a pad Since the pads play a very important role in how the element is viewed by the outside world, a mechanism is implemented to describe the data that can flow or currently flows through the pad by using capabilities. Here,w e will briefly describe what capabilities are and how to use them, enough to get an understanding of the concept. For an in-depth look into capabilities and a list of all capabilities defined in GStreamer, see the Plugin Writers Guide. Capabilities are attached to pad templates and to pads. For pad templates, it will describe the types of media that may stream over a pad created from this template. For pads, it can either be a list of possible caps (usually a copy of the pad template's capabilities), in which case the pad is not yet negotiated, or it is the type of media that currently streams over this pad, in which case the pad has been negotiated already. Dissecting capabilities A pads capabilities are described in a GstCaps object. Internally, a GstCaps will contain one or more GstStructure that will describe one media type. A negotiated pad will have capabilities set that contain exactly one structure. Also, this structure will contain only fixed values. These constraints are not true for unnegotiated pads or pad templates. As an example, below is a dump of the capabilities of the vorbisdec element, which you will get by running gst-inspect vorbisdec. You will see two pads: a source and a sink pad. Both of these pads are always available, and both have capabilities attached to them. The sink pad will accept vorbis-encoded audio data, with the mime-type audio/x-vorbis. The source pad will be used to send raw (decoded) audio samples to the next element, with a raw audio mime-type (either audio/x-raw-int or audio/x-raw-float). The source pad will also contain properties for the audio samplerate and the amount of channels, plus some more that you don't need to worry about for now. Pad Templates: SRC template: 'src' Availability: Always Capabilities: audio/x-raw-float rate: [ 8000, 50000 ] channels: [ 1, 2 ] endianness: 1234 width: 32 buffer-frames: 0 SINK template: 'sink' Availability: Always Capabilities: audio/x-vorbis Properties and values Properties are used to describe extra information for capabilities. A property consists of a key (a string) and a value. There are different possible value types that can be used: Basic types, this can be pretty much any GType registered with Glib. Those properties indicate a specific, non-dynamic value for this property. Examples include: An integer value (G_TYPE_INT): the property has this exact value. A boolean value (G_TYPE_BOOLEAN): the property is either TRUE or FALSE. A float value (G_TYPE_FLOAT): the property has this exact floating point value. A string value (G_TYPE_STRING): the property contains a UTF-8 string. Range types are GTypes registered by GStreamer to indicate a range of possible values. They are used for indicating allowed audio samplerate values or supported video sizes. The two types defined in GStreamer are: An integer range value (GST_TYPE_INT_RANGE): the property denotes a range of possible integers, with a lower and an upper boundary. The vorbisdec element, for example, has a rate property that can be between 8000 and 50000. A float range value (GST_TYPE_FLOAT_RANGE): the property denotes a range of possible floating point values, with a lower and an upper boundary. A list value (GST_TYPE_LIST): the property can take any value from a list of basic values given in this list. What capabilities are used for Capabilities describe the type of data that is streamed between two pads, or that one pad (template) supports. This makes them very useful for various purposes: Autoplugging: automatically finding elements to link to a pad based on its capabilities. All autopluggers use this method. Compatibility detection: when two pads are linked, GStreamer can verify if the two pads are talking about the same media type. The process of linking two pads and checking if they are compatible is called caps negotiation. Metadata: by reading the capabilities from a pad, applications can provide information about the type of media that is being streamed over the pad, which is information about the stream thatis currently being played back. Filtering: an application can use capabilities to limit the possible media types that can stream between two pads to a specific subset of their supported stream types. An application can, for example, use filtered caps to set a specific (non-fixed) video size that will stream between two pads. Using capabilities for metadata A pad can have a set (i.e. one or more) of capabilities attached to it. You can get values of properties in a set of capabilities by querying individual properties of one structure. You can get a structure from a caps using gst_caps_get_structure (): static void read_video_props (GstCaps *caps) { gint width, height; const GstStructure *str; str = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (str, "width", &width) || !gst_structure_get_int (str, "height", &height)) { g_print ("No width/height available\n"); return; } g_print ("The video size of this set of capabilities is %dx%d\n", width, height); } Creating capabilities for filtering While capabilities are mainly used inside a plugin to describe the media type of the pads, the application programmer also has to have basic understanding of capabilities in order to interface with the plugins, especially when using filtered caps. When you're using filtered caps or fixation, you're limiting the allowed types of media that can stream between two pads to a subset of their supported media types. You do this by filtering using your own set of capabilities. In order to do this, you need to create your own GstCaps. The simplest way to do this is by using the convenience function gst_caps_new_simple (): static void link_pads_with_filter (GstPad *one, GstPad *other) { GstCaps *caps; caps = gst_caps_new_simple ("video/x-raw-yuv", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL); gst_pad_link_filtered (one, other, caps); } In some cases, you will want to create a more elaborate set of capabilities to filter a link between two pads. Then, this function is too simplistic and you'll want to use the method gst_caps_new_full (): static void link_pads_with_filter (GstPad *one, GstPad *other) { GstCaps *caps; caps = gst_caps_new_full ( gst_structure_new ("video/x-raw-yuv", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL), gst_structure_new ("video/x-raw-rgb", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, 25., NULL), NULL); gst_pad_link_filtered (one, other, caps); } See the API references for the full API of GstStructure and GstCaps. Ghost pads You can see from how a bin has no pads of its own. This is where "ghost pads" come into play. Visualisation of a GstBin element without ghost pads A ghost pad is a pad from some element in the bin that can be accessed directly from the bin as well. Compare it to a symbolic link in UNIX filesystems. Using ghost pads on bins, the bin also has a pad and can transparently be used as an element in other parts of your code. Visualisation of a GstBin element with a ghost pad is a representation of a ghost pad. The sink pad of element one is now also a pad of the bin. Obviously, ghost pads can be added to any type of elements, not just to a GstBin. A ghostpad is created using the function gst_element_add_ghost_pad (): #include <gst/gst.h> int main (int argc, char *argv[]) { GstElement *bin, *sink; /* init */ gst_init (&argc, &argv); /* create element, add to bin, add ghostpad */ sink = gst_element_factory_make ("fakesink", "sink"); bin = gst_bin_new ("mybin"); gst_bin_add (GST_BIN (bin), sink); gst_element_add_ghost_pad (bin, gst_element_get_pad (sink, "sink"), "sink"); [..] } In the above example, the bin now also has a pad: the pad called sink of the given element. The bin can, from here on, be used as a substitute for the sink element. You could, for example, link another element to the bin. Buffers and Events The data flowing through a pipeline consists of a combination of buffers and events. Buffers contain the actual pipeline data. Events contain control information, such as seeking information and end-of-stream notifiers. All this will flow through the pipeline automatically when it's running. This chapter is mostly meant to explain the concept to you; you don't need to do anything for this. Buffers Buffers contain the data that will flow through the pipeline you have created. A source element will typically create a new buffer and pass it through a pad to the next element in the chain. When using the GStreamer infrastructure to create a media pipeline you will not have to deal with buffers yourself; the elements will do that for you. A buffer consists, amongst others, of: A pointer to a piece of memory. The size of the memory. A timestamp for the buffer. A refcount that indicates how many elements are using this buffer. This refcount will be used to destroy the buffer when no element has a reference to it. The simple case is that a buffer is created, memory allocated, data put in it, and passed to the next element. That element reads the data, does something (like creating a new buffer and decoding into it), and unreferences the buffer. This causes the data to be free'ed and the buffer to be destroyed. A typical video or audio decoder works like this. There are more complex scenarios, though. Elements can modify buffers in-place, i.e. without allocating a new one. Elements can also write to hardware memory (such as from video-capture sources) or memory allocated from the X-server using XShm). Buffers can be read-only, and so on. Events Events are control particles that are sent both up- and downstream in a pipeline along with buffers. Downstream events notify fellow elements of stream states. Possible events include discontinuities, flushes, end-of-stream notifications and so on. Upstream events are used both in application-element interaction as well as event-event interaction to request changes in stream state, such as seeks. For applications, only upstream events are important. Downstream events are just explained to get a more complete picture of the data concept. Since most applications seek in time units, our example below does so too: static void seek_to_time (GstElement *element, guint64 time_ns) { GstEvent *event; event = gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME, time_ns); gst_element_send_event (element, event); } The function gst_element_seek () is a shortcut for this. This is mostly just to show how it all works. Your first application This chapter will summarize everything you've learned in the previous chapters. It describes all aspects of a simple GStreamer application, including initializing libraries, creating elements, packing elements together in a pipeline and playing this pipeline. By doing all this, you will be able to build a simple Ogg/Vorbis audio player. Hello world We're going to create a simple first application, a simple Ogg/Vorbis command-line audio player. For this, we will use only standard GStreamer components. The player will read a file specified on the command-line. Let's get started! We've learned, in , that the first thing to do in your application is to initialize GStreamer by calling gst_init (). Also, make sure that the application includes gst/gst.h so all function names and objects are properly defined. Use #include <gst/gst.h> to do that. Next, you'll want to create the different elements using gst_element_factory_make (). For an Ogg/Vorbis audio player, we'll need a source element that reads files from a disk. GStreamer includes this element under the name filesrc. Next, we'll need something to parse the file and decoder it into raw audio. GStreamer has two elements for this: the first parses Ogg streams into elementary streams (video, audio) and is called oggdemux. The second is a Vorbis audio decoder, it's conveniently called vorbisdec. Since oggdemux creates dynamic pads for each elementary stream, you'll need to set a new-pad event handler on the oggdemux element, like you've learned in , to link the Ogg parser and the Vorbis decoder elements together. At last, we'll also need an audio output element, we will use alsasink, which outputs sound to an ALSA audio device. The last thing left to do is to add all elements into a container element, a GstPipeline, and iterate this pipeline until we've played the whole song. We've previously learned how to add elements to a container bin in , and we've learned about element states in . We will use the function gst_bin_sync_children_state () to synchronize the state of a bin on all of its contained children. Let's now add all the code together to get our very first audio player: #include <gst/gst.h> /* * Global objects are usually a bad thing. For the purpose of this * example, we will use them, however. */ GstElement *pipeline, *source, *parser, *decoder, *conv, *scale, *sink; static void new_pad (GstElement *element, GstPad *pad, gpointer data) { /* We can now link this pad with the audio decoder and * add both decoder and audio output to the pipeline. */ gst_pad_link (pad, gst_element_get_pad (decoder, "sink")); gst_bin_add_many (GST_BIN (pipeline), decoder, conv, scale, sink, NULL); /* This function synchronizes a bins state on all of its * contained children. */ gst_bin_sync_children_state (GST_BIN (pipeline)); } int main (int argc, char *argv[]) { /* initialize GStreamer */ gst_init (&argc, &argv); /* check input arguments */ if (argc != 2) { g_print ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]); return -1; } /* create elements */ pipeline = gst_pipeline_new ("audio-player"); source = gst_element_factory_make ("filesrc", "file-source"); parser = gst_element_factory_make ("oggdemux", "ogg-parser"); decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder"); conv = gst_element_factory_make ("audioconvert", "conv"); scale = gst_element_factory_make ("audioscale", "scale"); sink = gst_element_factory_make ("alsasink", "alsa-output"); /* set filename property on the file source */ g_object_set (G_OBJECT (source), "location", argv[1], NULL); /* link together - note that we cannot link the parser and * decoder yet, becuse the parser uses dynamic pads. For that, * we set a new-pad signal handler. */ gst_element_link (source, parser); gst_element_link_many (decoder, conv, scale, sink, NULL); g_signal_connect (parser, "new-pad", G_CALLBACK (new_pad), NULL); /* put all elements in a bin - or at least the ones we will use * instantly. */ gst_bin_add_many (GST_BIN (pipeline), source, parser, NULL); /* Now set to playing and iterate. We will set the decoder and * audio output to ready so they initialize their memory already. * This will decrease the amount of time spent on linking these * elements when the Ogg parser emits the new-pad signal. */ gst_element_set_state (decoder, GST_STATE_READY); gst_element_set_state (conv, GST_STATE_READY); gst_element_set_state (scale, GST_STATE_READY); gst_element_set_state (sink, GST_STATE_READY); gst_element_set_state (pipeline, GST_STATE_PLAYING); /* and now iterate - the rest will be automatic from here on. * When the file is finished, gst_bin_iterate () will return * FALSE, thereby terminating this loop. */ while (gst_bin_iterate (GST_BIN (pipeline))) ; /* clean up nicely */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } We now have created a complete pipeline. We can visualise the pipeline as follows: The "hello world" pipelineCompiling and Running helloworld.c To compile the helloworld example, use: gcc -Wall $(pkg-config --cflags --libs gstreamer-0.8) helloworld.c -o helloworld. GStreamer makes use of pkg-config to get compiler and linker flags needed to compile this application. If you're running a non-standard installation, make sure the PKG_CONFIG_PATH environment variable is set to the correct location ($libdir/pkgconfig). application against the uninstalled location. You can run this example application with ./helloworld file.ogg. Substitute file.ogg with your favourite Ogg/Vorbis file. Conclusion This concludes our first example. As you see, setting up a pipeline is very low-level but powerful. You will see later in this manual how you can create a more powerful media player with even less effort using higher-level interfaces. We will discuss all that in . We will first, however, go more in-depth into more advanced GStreamer internals. It should be clear from the example that we can very easily replace the filesrc element with some other element that reads data from a network, or some other data source element that is better integrated with your desktop environment. Also, you can use other decoders and parsers to support other media types. You can use another audio sink if you're not running Linux, but Mac OS X, Windows or FreeBSD, or you can instead use a filesink to write audio files to disk instead of playing them back. By using an audio card source, you can even do audio capture instead of playback. All this shows the reusability of GStreamer elements, which is its greatest advantage. Advanced GStreamer concepts In this part we will cover the more advanced features of GStreamer. With the basics you learned in the previous part you should be able to create a simple application. However, GStreamer provides much more candy than just the basics of playing back audio files. In this chapter, you will learn more of the low-level features and internals of GStreamer, such as threads, scheduling, synchronization, metadata, interfaces and dynamic parameters. Position tracking and seeking So far, we've looked at how to create a pipeline to do media processing and how to make it run ("iterate"). Most application developers will be interested in providing feedback to the user on media progress. Media players, for example, will want to show a slider showing the progress in the song, and usually also a label indicating stream length. Transcoding applications will want to show a progress bar on how much % of the task is done. GStreamer has built-in support for doing all this using a concept known as querying. Since seeking is very similar, it will be discussed here as well. Seeking is done using the concept of events. Querying: getting the position or length of a stream Querying is defined as requesting a specific stream-property related to progress tracking. This includes getting the length of a stream (if available) or getting the current position. Those stream properties can be retrieved in various formats such as time, audio samples, video frames or bytes. The functions used are gst_element_query () and gst_pad_query (). Obviously, using either of the above-mentioned functions requires the application to know which element or pad to run the query on. This is tricky, but there are some good sides to the story. The good thing is that elements (or, rather, pads - since gst_element_query () internally calls gst_pad_query ()) forward (dispatch) events and queries to peer pads (or elements) if they don't handle it themselves. The bad side is that some elements (or pads) will handle events, but not the specific formats that you want, and therefore it still won't work. Most queries will, fortunately, work fine. Queries are always dispatched backwards. This means, effectively, that it's easiest to run the query on your video or audio output element, and it will take care of dispatching the query to the element that knows the answer (such as the current position or the media length; usually the demuxer or decoder). #include <gst/gst.h> gint main (gint argc, gchar *argv[]) { GstElement *sink, *pipeline; [..] /* run pipeline */ do { gint64 len, pos; GstFormat fmt = GST_FORMAT_TIME; if (gst_element_query (sink, GST_QUERY_POSITION, &fmt, &pos) && gst_element_query (sink, GST_QUERY_TOTAL, &fmt, &len)) { g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", GST_TIME_ARGS (pos), GST_TIME_ARGS (len)); } } while (gst_bin_iterate (GST_BIN (pipeline))); [..] } If you are having problems with the dispatching behaviour, your best bet is to manually decide which element to start running the query on. You can get a list of supported formats and query-types with gst_element_get_query_types () and gst_element_get_formats (). Events: seeking (and more) Events work in a very similar way as queries. Dispatching, for example, works exactly the same for events (and also has the same limitations). Although there are more ways in which applications and elements can interact using events, we will only focus on seeking here. This is done using the seek-event. A seek-event contains a seeking offset, a seek method (which indicates relative to what the offset was given), a seek format (which is the unit of the offset, e.g. time, audio samples, video frames or bytes) and optionally a set of seeking-related flags (e.g. whether internal buffers should be flushed). The behaviour of a seek is also wrapped in the function gst_element_seek (). static void seek_to_time (GstElement *audiosink, gint64 time_nanonseconds) { gst_element_seek (audiosink, GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_FLUSH, time_nanoseconds); } Metadata GStreamer makes a clear distinction between two types of metadata, and has support for both types. The first is stream tags, which describe the content of a stream in a non-technical way. Examples include the author of a song, the title of that very same song or the album it is a part of. The other type of metadata is stream-info, which is a somewhat technical description of the properties of a stream. This can include video size, audio samplerate, codecs used and so on. Tags are handled using the GStreamer tagging system. Stream-info can be retrieved from a GstPad. Stream information Stream information can most easily be read by reading them from a GstPad. This has already been discussed before in . Therefore, we will skip it here. Tag reading Tag reading is remarkably simple in GStreamer Every element supports the found-tag signal, which will be fired each the time the element reads tags from the stream. A GstBin will conveniently forward tags found by its childs. Therefore, in most applications, you will only need to connect to the found-tag signal on the top-most bin in your pipeline, and you will automatically retrieve all tags from the stream. Note, however, that the found-tag might be fired multiple times and by multiple elements in the pipeline. It is the application's responsibility to put all those tags together and display them to the user in a nice, coherent way. Tag writing WRITEME Interfaces In , you have learned how to use GObject properties as a simple way to do interaction between applications and elements. This method suffices for the simple'n'straight settings, but fails for anything more complicated than a getter and setter. For the more complicated use cases, GStreamer uses interfaces based on the Glib GInterface type. Most of the interfaces handled here will not contain any example code. See the API references for details. Here, we will just describe the scope and purpose of each interface. The Mixer interface The mixer interface provides a uniform way to control the volume on a hardware (or software) mixer. The interface is primarily intended to be implemented by elements for audio inputs and outputs that talk directly to the hardware (e.g. OSS or ALSA plugins). Using this interface, it is possible to control a list of tracks (such as Line-in, Microphone, etc.) from a mixer element. They can be muted, their volume can be changed and, for input tracks, their record flag can be set as well. Example plugins implementing this interface include the OSS elements (osssrc, osssink, ossmixer) and the ALSA plugins (alsasrc, alsasink and alsamixer). The Tuner interface The tuner interface is a uniform way to control inputs and outputs on a multi-input selection device. This is primarily used for input selection on elements for TV- and capture-cards. Using this interface, it is possible to select one track from a list of tracks supported by that tuner-element. The tuner will than select that track for media-processing internally. This can, for example, be used to switch inputs on a TV-card (e.g. from Composite to S-video). This interface is currently only implemented by the Video4linux and Video4linux2 elements. The Color Balance interface The colorbalance interface is a way to control video-related properties on an element, such as brightness, contrast and so on. It's sole reason for existance is that, as far as its authors know, there's no way to dynamically register properties using GObject. The colorbalance interface is implemented by several plugins, including xvimagesink and the Video4linux and Video4linux2 elements. The Property Probe interface The property probe is a way to autodetect allowed values for a GObject property. It's primary use (and the only thing that we currently use it for) is to autodetect devices in several elements. For example, the OSS elements use this interface to detect all OSS devices on a system. Applications can then probe this property and get a list of detected devices. Given the overlap between HAL and the practical implementations of this interface, this might in time be deprecated in favour of HAL. This interface is currently implemented by many elements, including the ALSA, OSS, Video4linux and Video4linux2 elements. The X Overlay interface The X Overlay interface was created to solve the problem of embedding video streams in an application window. The application provides an X-window to the element implementing this interface to draw on, and the element will then use this X-window to draw on rather than creating a new toplevel window. This is useful to embed video in video players. This interface is implemented by, amongst others, the Video4linux and Video4linux2 elements and by ximagesink, xvimagesink and sdlvideosink. Clocks in GStreamer WRITEME Dynamic ParametersGetting Started The Dynamic Parameters subsystem is contained within the gstcontrol library. You need to include the header in your application's source file: ... #include <gst/gst.h> #include <gst/control/control.h> ... Your application should link to the shared library gstcontrol. The gstcontrol library needs to be initialized when your application is run. This can be done after the the GStreamer library has been initialized. ... gst_init(&argc,&argv); gst_control_init(&argc,&argv); ... Creating and Attaching Dynamic Parameters Once you have created your elements you can create and attach dparams to them. First you need to get the element's dparams manager. If you know exactly what kind of element you have, you may be able to get the dparams manager directly. However if this is not possible, you can get the dparams manager by calling gst_dpman_get_manager. Once you have the dparams manager, you must set the mode that the manager will run in. There is currently only one mode implemented called "synchronous" - this is used for real-time applications where the dparam value cannot be known ahead of time (such as a slider in a GUI). The mode is called "synchronous" because the dparams are polled by the element for changes before each buffer is processed. Another yet-to-be-implemented mode is "asynchronous". This is used when parameter changes are known ahead of time - such as with a timelined editor. The mode is called "asynchronous" because parameter changes may happen in the middle of a buffer being processed. GstElement *sinesrc; GstDParamManager *dpman; ... sinesrc = gst_element_factory_make("sinesrc","sine-source"); ... dpman = gst_dpman_get_manager (sinesrc); gst_dpman_set_mode(dpman, "synchronous"); If you don't know the names of the required dparams for your element you can call gst_dpman_list_dparam_specs(dpman) to get a NULL terminated array of param specs. This array should be freed after use. You can find the name of the required dparam by calling g_param_spec_get_name on each param spec in the array. In our example, "volume" will be the name of our required dparam. Each type of dparam currently has its own new function. This may eventually be replaced by a factory method for creating new instances. A default dparam instance can be created with the gst_dparam_new function. Once it is created it can be attached to a required dparam in the element. GstDParam *volume; ... volume = gst_dparam_new(G_TYPE_DOUBLE); if (gst_dpman_attach_dparam (dpman, "volume", volume)){ /* the dparam was successfully attached */ ... } Changing Dynamic Parameter Values All interaction with dparams to actually set the dparam value is done through simple GObject properties. There is a property value for each type that dparams supports - these currently being "value_double", "value_float", "value_int" and "value_int64". To set the value of a dparam, simply set the property which matches the type of your dparam instance. #define ZERO(mem) memset(&mem, 0, sizeof(mem)) ... gdouble set_to_value; GstDParam *volume; GValue set_val; ZERO(set_val); g_value_init(&set_val, G_TYPE_DOUBLE); ... g_value_set_double(&set_val, set_to_value); g_object_set_property(G_OBJECT(volume), "value_double", &set_val); Or if you create an actual GValue instance: gdouble set_to_value; GstDParam *volume; GValue *set_val; set_val = g_new0(GValue,1); g_value_init(set_val, G_TYPE_DOUBLE); ... g_value_set_double(set_val, set_to_value); g_object_set_property(G_OBJECT(volume), "value_double", set_val); Different Types of Dynamic Parameter There are currently only two implementations of dparams so far. They are both for real-time use so should be run in the "synchronous" mode. GstDParam - the base dparam type All dparam implementations will subclass from this type. It provides a basic implementation which simply propagates any value changes as soon as it can. A new instance can be created with the function GstDParam* gst_dparam_new (GType type). It has the following object properties: "value_double" - the property to set and get if it is a double dparam "value_float" - the property to set and get if it is a float dparam "value_int" - the property to set and get if it is an integer dparam "value_int64" - the property to set and get if it is a 64 bit integer dparam "is_log" - readonly boolean which is TRUE if the param should be displayed on a log scale "is_rate" - readonly boolean which is TRUE if the value is a proportion of the sample rate. For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz. GstDParamSmooth - smoothing real-time dparam Some parameter changes can create audible artifacts if they change too rapidly. The GstDParamSmooth implementation can greatly reduce these artifacts by limiting the rate at which the value can change. This is currently only supported for double and float dparams - the other types fall back to the default implementation. A new instance can be created with the function GstDParam* gst_dpsmooth_new (GType type). It has the following object properties: "update_period" - an int64 value specifying the number nanoseconds between updates. This will be ignored in "synchronous" mode since the buffer size dictates the update period. "slope_time" - an int64 value specifying the time period to use in the maximum slope calculation "slope_delta_double" - a double specifying the amount a double value can change in the given slope_time. "slope_delta_float" - a float specifying the amount a float value can change in the given slope_time. Audible artifacts may not be completely eliminated by using this dparam. The only way to eliminate artifacts such as "zipper noise" would be for the element to implement its required dparams using the array method. This would allow dparams to change parameters at the sample rate which should eliminate any artifacts. Timelined dparams A yet-to-be-implemented subclass of GstDParam will add an API which allows the creation and manipulation of points on a timeline. This subclass will also provide a dparam implementation which uses linear interpolation between these points to find the dparam value at any given time. Further subclasses can extend this functionality to implement more exotic interpolation algorithms such as splines. Threads GStreamer has support for multithreading through the use of the GstThread object. This object is in fact a special GstBin that will start a new thread (using Glib's GThread system) when started. To create a new thread, you can simply use gst_thread_new (). From then on, you can use it similar to how you would use a GstBin. You can add elements to it, change state and so on. The largest difference between a thread and other bins is that the thread does not require iteration. Once set to the GST_STATE_PLAYING state, it will iterate its contained children elements automatically. shows how a thread can be visualised. A threadWhen would you want to use a thread? There are several reasons to use threads. However, there's also some reasons to limit the use of threads as much as possible. We will go into the drawbacks of threading in GStreamer in the next section. Let's first list some situations where threads can be useful: Data buffering, for example when dealing with network streams or when recording data from a live stream such as a video or audio card. Short hickups elsewhere in the pipeline will not cause data loss. See for a visualization of this idea. Synchronizing output devices, e.g. when playing a stream containing both video and audio data. By using threads for both outputs, they will run independently and their synchronization will be better. Data pre-rolls. You can use threads and queues (thread boundaries) to cache a few seconds of data before playing. By using this approach, the whole pipeline will already be setup and data will already be decoded. When activating the rest of the pipeline, the switch from PAUSED to PLAYING will be instant. a two-threaded decoder with a queue Above, we've mentioned the queue element several times now. A queue is a thread boundary element. It does so by using a classic provider/receiver model as learned in threading classes at universities all around the world. By doing this, it acts both as a means to make data throughput between threads threadsafe, and it can also act as a buffer. Queues have several GObject properties to be configured for specific uses. For example, you can set lower and upper tresholds for the element. If there's less data than the lower treshold (default: disabled), it will block output. If there's more data than the upper treshold, it will block input or (if configured to do so) drop data. Constraints placed on the pipeline by the GstThread Within the pipeline, everything is the same as in any other bin. The difference lies at the thread boundary, at the link between the thread and the outside world (containing bin). Since GStreamer is fundamentally buffer-oriented rather than byte-oriented, the natural solution to this problem is an element that can "buffer" the buffers between the threads, in a thread-safe fashion. This element is the queue element. A queue should be placed in between any two elements whose pads are linked together while the elements live in different threads. It doesn't matter if the queue is placed in the containing bin or in the thread itself, but it needs to be present on one side or the other to enable inter-thread communication. If you are writing a GUI application, making the top-level bin a thread will make your GUI more responsive. If it were a pipeline instead, it would have to be iterated by your application's event loop, which increases the latency between events (say, keyboard presses) and responses from the GUI. In addition, any slight hang in the GUI would delay iteration of the pipeline, which (for example) could cause pops in the output of the sound card, if it is an audio pipeline. A problem with using threads is, however, thread contexts. If you connect to a signal that is emitted inside a thread, then the signal handler for this thread will be executed in that same thread! This is very important to remember, because many graphical toolkits can not run multi-threaded. Gtk+, for example, only allows threaded access to UI objects if you explicitely use mutexes. Not doing so will result in random crashes and X errors. A solution many people use is to place an idle handler in the signal handler, and have the actual signal emission code be executed in the idle handler, which will be executed from the mainloop. Generally, if you use threads, you will encounter some problems. Don't hesistate to ask us for help in case of problems. A threaded example application As an example we show the helloworld program that we coded in using a thread. Note that the whole application lives in a thread (as opposed to half of the application living in a thread and the other half being another thread or a pipeline). Therefore, it does not need a queue element in this specific case. #include <gst/gst.h> GstElement *thread, *source, *decodebin, *audiosink; static gboolean idle_eos (gpointer data) { g_print ("Have idle-func in thread %p\n", g_thread_self ()); gst_main_quit (); /* do this function only once */ return FALSE; } /* * EOS will be called when the src element has an end of stream. * Note that this function will be called in the thread context. * We will place an idle handler to the function that really * quits the application. */ static void cb_eos (GstElement *thread, gpointer data) { g_print ("Have eos in thread %p\n", g_thread_self ()); g_idle_add ((GSourceFunc) idle_eos, NULL); } /* * On error, too, you'll want to forward signals to the main * thread, especially when using GUI applications. */ static void cb_error (GstElement *thread, GstElement *source, GError *error, gchar *debug, gpointer data) { g_print ("Error in thread %p: %s\n", g_thread_self (), error->message); g_idle_add ((GSourceFunc) idle_eos, NULL); } /* * Link new pad from decodebin to audiosink. * Contains no further error checking. */ static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) { gst_pad_link (pad, gst_element_get_pad (audiosink, "sink")); gst_bin_add (GST_BIN (thread), audiosink); gst_bin_sync_children_state (GST_BIN (thread)); } gint main (gint argc, gchar *argv[]) { /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have a filename argument */ if (argc != 2) { g_print ("usage: %s <Ogg/Vorbis filename>\n", argv[0]); return -1; } /* create a new thread to hold the elements */ thread = gst_thread_new ("thread"); g_signal_connect (thread, "eos", G_CALLBACK (cb_eos), NULL); g_signal_connect (thread, "error", G_CALLBACK (cb_error), NULL); /* create elements */ source = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (source), "location", argv[1], NULL); decodebin = gst_element_factory_make ("decodebin", "decoder"); g_signal_connect (decodebin, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); audiosink = gst_element_factory_make ("alsasink", "audiosink"); /* setup */ gst_bin_add_many (GST_BIN (thread), source, decodebin, NULL); gst_element_link (source, decodebin); gst_element_set_state (audiosink, GST_STATE_PAUSED); gst_element_set_state (thread, GST_STATE_PLAYING); /* no need to iterate. We can now use a mainloop */ gst_main (); /* unset */ gst_element_set_state (thread, GST_STATE_NULL); gst_object_unref (GST_OBJECT (thread)); return 0; } Scheduling By now, you've seen several example applications. All of them would set up a pipeline and call gst_bin_iterate () to start media processing. You might have started wondering what happens during pipeline iteration. This whole process of media processing is called scheduling. Scheduling is considered one of the most complex parts of GStreamer. Here, we will do no more than give a global overview of scheduling, most of which will be purely informative. It might help in understanding the underlying parts of GStreamer. The scheduler is responsible for managing the plugins at runtime. Its main responsibilities are: Managing data throughput between pads and elements in a pipeline. This might sometimes imply temporary data storage between elements. Calling functions in elements that do the actual data processing. Monitoring state changes and enabling/disabling elements in the chain. Selecting and distributing the global clock. The scheduler is a pluggable component; this means that alternative schedulers can be written and plugged into GStreamer. There is usually no need for interaction in the process of choosing the scheduler, though. The default scheduler in GStreamer is called opt. Some of the concepts discussed here are specific to opt. Managing elements and data throughput To understand some specifics of scheduling, it is important to know how elements work internally. Largely, there are four types of elements: _chain ()-based elements, _loop ()-based elements, _get ()-based elements and decoupled elements. Each of those have a set of features and limitations that are important for how they are scheduled. _chain ()-based elements are elements that have a _chain ()-function defined for each of their sinkpads. Those functions will receive data whenever input data is available. In those functions, the element can push data over its source pad(s) to peer elements. _chain ()-based elements cannot pull additional data from their sinkpad(s). Most elements in GStreamer are _chain ()-based. _loop ()-based elements are elements that have a _loop ()-function defined for the whole element. Inside this function, the element can pull buffers from its sink pad(s) and push data over its source pad(s) as it sees fit. Such elements usually require specific control over their input. Muxers and demuxers are usually _loop ()-based. _get ()-based elements are elements with only source pads. For each source pad, a _get ()-function is defined, which is called whenever the peer element needs additional input data. Most source elements are, in fact, _get ()-based. Such an element cannot actively push data. Decoupled elements are elements whose source pads are _get ()-based and whose sink pads are _chain ()-based. The _chain ()-function cannot push data over its source pad(s), however. One such element is the queue element, which is a thread boundary element. Since only one side of such elements are interesting for one particular scheduler, we can safely handle those elements as if they were either _get ()- or _chain ()-based. Therefore, we will further omit this type of elements in the discussion. Obviously, the type of elements that are linked together have implications for how the elements will be scheduled. If a get-based element is linked to a loop-based element and the loop-based element requests data from its sinkpad, we can just call the get-function and be done with it. However, if two loop-based elements are linked to each other, it's a lot more complicated. Similarly, a loop-based element linked to a chain-based element is a lot easier than two loop-based elements linked to each other. The default GStreamer scheduler, opt, uses a concept of chains and groups. A group is a series of elements that do not require any context switches or intermediate data stores to be executed. In practice, this implies zero or one loop-based elements, one get-based element (at the beginning) and an infinite amount of chain-based elements. If there is a loop-based element, then the scheduler will simply call this elements loop-function to iterate. If there is no loop-based element, then data will be pulled from the get-based element and will be pushed over the chain-based elements. A chain is a series of groups that depend on each other for data. For example, two linked loop-based elements would end up in different groups, but in the same chain. Whenever the first loop-based element pushes data over its source pad, the data will be temporarily stored inside the scheduler until the loop-function returns. When it's done, the loop-function of the second element will be called to process this data. If it pulls data from its sinkpad while no data is available, the scheduler will emulate a get-function and, in this function, iterate the first group until data is available. The above is roughly how scheduling works in GStreamer. This has some implications for ideal pipeline design. An pipeline would ideally contain at most one loop-based element, so that all data processing is immediate and no data is stored inside the scheduler during group switches. You would think that this decreases overhead significantly. In practice, this is not so bad, however. It's something to keep in the back of your mind, nothing more. Autoplugging In , you've learned to build a simple media player for Ogg/Vorbis files. By using alternative elements, you are able to build media players for other media types, such as Ogg/Speex, MP3 or even video formats. However, you would rather want to build an application that can automatically detect the media type of a stream and automatically generate the best possible pipeline by looking at all available elements in a system. This process is called autoplugging, and GStreamer contains high-quality autopluggers. If you're looking for an autoplugger, don't read any further and go to . This chapter will explain the concept of autoplugging and typefinding. It will explain what systems GStreamer includes to dynamically detect the type of a media stream, and how to generate a pipeline of decoder elements to playback this media. The same principles can also be used for transcoding. Because of the full dynamicity of this concept, GStreamer can be automatically extended to support new media types without needing any adaptations to its autopluggers. We will first introduce the concept of MIME types as a dynamic and extendible way of identifying media streams. After that, we will introduce the concept of typefinding to find the type of a media stream. Lastly, we will explain how autoplugging and the GStreamer registry can be used to setup a pipeline that will convert media from one mimetype to another, for example for media decoding. MIME-types as a way to identity streams We have previously introduced the concept of capabilities as a way for elements (or, rather, pads) to agree on a media type when streaming data from one element to the next (see ). We have explained that a capability is a combination of a mimetype and a set of properties. For most container formats (those are the files that you will find on your hard disk; Ogg, for example, is a container format), no properties are needed to describe the stream. Only a MIME-type is needed. A full list of MIME-types and accompanying properties can be found in the Plugin Writer's Guide. An element must associate a MIME-type to its source and sink pads when it is loaded into the system. GStreamer knows about the different elements and what type of data they expect and emit through the GStreamer registry. This allows for very dynamic and extensible element creation as we will see. In , we've learned to build a music player for Ogg/Vorbis files. Let's look at the MIME-types associated with each pad in this pipeline. shows what MIME-type belongs to each pad in this pipeline. The Hello world pipeline with MIME types Now that we have an idea how GStreamer identifies known media streams, we can look at methods GStreamer uses to setup pipelines for media handling and for media type detection. Media stream type detection Usually, when loading a media stream, the type of the stream is not known. This means that before we can choose a pipeline to decode the stream, we first need to detect the stream type. GStreamer uses the concept of typefinding for this. Typefinding is a normal part of a pipeline, it will read data for as long as the type of a stream is unknown. During this period, it will provide data to all plugins that implement a typefinder. when one of the typefinders recognizes the stream, the typefind element will emit a signal and act as a passthrough module from that point on. If no type was found, it will emit an error and further media processing will stop. Once the typefind element has found a type, the application can use this to plug together a pipeline to decode the media stream. This will be discussed in the next section. Plugins in GStreamer can, as mentioned before, implement typefinder functionality. A plugin implementing this functionality will submit a mimetype, optionally a set of file extensions commonly used for this media type, and a typefind function. Once this typefind function inside the plugin is called, the plugin will see if the data in this media stream matches a specific pattern that marks the media type identified by that mimetype. If it does, it will notify the typefind element of this fact, telling which mediatype was recognized and how certain we are that this stream is indeed that mediatype. Once this run has been completed for all plugins implementing a typefind functionality, the typefind element will tell the application what kind of media stream it thinks to have recognized. The following code should explain how to use the typefind element. It will print the detected media type, or tell that the media type was not found. The next section will introduce more useful behaviours, such as plugging together a decoding pipeline. #include <gst/gst.h> static void cb_typefound (GstElement *typefind, guint probability, GstCaps *caps, gpointer data) { gchar *type; type = gst_caps_to_string (caps); g_print ("Media type %s found, probability %d%%\n", type, probability); g_free (type); /* done */ (* (gboolean *) data) = TRUE; } static void cb_error (GstElement *pipeline, GstElement *source, GError *error, gchar *debug, gpointer data) { g_print ("Error: %s\n", error->message); /* done */ (* (gboolean *) data) = TRUE; } gint main (gint argc, gchar *argv[]) { GstElement *pipeline, *filesrc, *typefind; gboolean done = FALSE; /* init GStreamer */ gst_init (&argc, &argv); /* check args */ if (argc != 2) { g_print ("Usage: %s <filename>\n", argv[0]); return -1; } /* create a new pipeline to hold the elements */ pipeline = gst_pipeline_new ("pipe"); g_signal_connect (pipeline, "error", G_CALLBACK (cb_error), &done); /* create file source and typefind element */ filesrc = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); typefind = gst_element_factory_make ("typefind", "typefinder"); g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), &done); /* setup */ gst_bin_add_many (GST_BIN (pipeline), filesrc, typefind, NULL); gst_element_link (filesrc, typefind); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); /* now iterate until the type is found */ do { if (!gst_bin_iterate (GST_BIN (pipeline))) break; } while (!done); /* unset */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Once a media type has been detected, you can plug an element (e.g. a demuxer or decoder) to the source pad of the typefind element, and decoding of the media stream will start right after. Plugging together dynamic pipelines In this chapter we will see how you can create a dynamic pipeline. A dynamic pipeline is a pipeline that is updated or created while data is flowing through it. We will create a partial pipeline first and add more elements while the pipeline is playing. The basis of this player will be the application that we wrote in the previous section () to identify unknown media streams. Once the type of the media has been found, we will find elements in the registry that can decode this streamtype. For this, we will get all element factories (which we've seen before in ) and find the ones with the given MIME-type and capabilities on their sinkpad. Note that we will only use parsers, demuxers and decoders. We will not use factories for any other element types, or we might get into a loop of encoders and decoders. For this, we will want to build a list of allowed factories right after initializing GStreamer. static GList *factories; /* * This function is called by the registry loader. Its return value * (TRUE or FALSE) decides whether the given feature will be included * in the list that we're generating further down. */ static gboolean cb_feature_filter (GstPluginFeature *feature, gpointer data) { const gchar *klass; guint rank; /* we only care about element factories */ if (!GST_IS_ELEMENT_FACTORY (feature)) return FALSE; /* only parsers, demuxers and decoders */ klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); if (g_strrstr (klass, "Demux") == NULL && g_strrstr (klass, "Decoder") == NULL && g_strrstr (klass, "Parse") == NULL) return FALSE; /* only select elements with autoplugging rank */ rank = gst_plugin_feature_get_rank (feature); if (rank < GST_RANK_MARGINAL) return FALSE; return TRUE; } /* * This function is called to sort features by rank. */ static gint cb_compare_ranks (GstPluginFeature *f1, GstPluginFeature *f2) { return gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); } static void init_factories (void) { /* first filter out the interesting element factories */ factories = gst_registry_pool_feature_filter ( (GstPluginFeatureFilter) cb_feature_filter, FALSE, NULL); /* sort them according to their ranks */ factories = g_list_sort (factories, (GCompareFunc) cb_compare_ranks); } From this list of element factories, we will select the one that most likely will help us decoding a media stream to a given output type. For each newly created element, we will again try to autoplug new elements to its source pad(s). Also, if the element has dynamic pads (which we've seen before in ), we will listen for newly created source pads and handle those, too. The following code replaces the cb_type_found from the previous section with a function to initiate autoplugging, which will continue with the above approach. static void try_to_plug (GstPad *pad, const GstCaps *caps); static GstElement *audiosink; static void cb_newpad (GstElement *element, GstPad *pad, gpointer data) { GstCaps *caps; caps = gst_pad_get_caps (pad); try_to_plug (pad, caps); gst_caps_free (caps); } static void close_link (GstPad *srcpad, GstElement *sinkelement, const gchar *padname, const GList *templlist) { gboolean has_dynamic_pads = FALSE; g_print ("Plugging pad %s:%s to newly created %s:%s\n", gst_object_get_name (GST_OBJECT (gst_pad_get_parent (srcpad))), gst_pad_get_name (srcpad), gst_object_get_name (GST_OBJECT (sinkelement)), padname); /* add the element to the pipeline and set correct state */ gst_element_set_state (sinkelement, GST_STATE_PAUSED); gst_bin_add (GST_BIN (pipeline), sinkelement); gst_pad_link (srcpad, gst_element_get_pad (sinkelement, padname)); gst_bin_sync_children_state (GST_BIN (pipeline)); /* if we have static source pads, link those. If we have dynamic * source pads, listen for new-pad signals on the element */ for ( ; templlist != NULL; templlist = templlist->next) { GstPadTemplate *templ = GST_PAD_TEMPLATE (templlist->data); /* only sourcepads, no request pads */ if (templ->direction != GST_PAD_SRC || templ->presence == GST_PAD_REQUEST) { continue; } switch (templ->presence) { case GST_PAD_ALWAYS: { GstPad *pad = gst_element_get_pad (sinkelement, templ->name_template); GstCaps *caps = gst_pad_get_caps (pad); /* link */ try_to_plug (pad, caps); gst_caps_free (caps); break; } case GST_PAD_SOMETIMES: has_dynamic_pads = TRUE; break; default: break; } } /* listen for newly created pads if this element supports that */ if (has_dynamic_pads) { g_signal_connect (sinkelement, "new-pad", G_CALLBACK (cb_newpad), NULL); } } static void try_to_plug (GstPad *pad, const GstCaps *caps) { GstObject *parent = GST_OBJECT (gst_pad_get_parent (pad)); const gchar *mime; const GList *item; GstCaps *res, *audiocaps; /* don't plug if we're already plugged */ if (GST_PAD_IS_LINKED (gst_element_get_pad (audiosink, "sink"))) { g_print ("Omitting link for pad %s:%s because we're already linked\n", gst_object_get_name (parent), gst_pad_get_name (pad)); return; } /* as said above, we only try to plug audio... Omit video */ mime = gst_structure_get_name (gst_caps_get_structure (caps, 0)); if (g_strrstr (mime, "video")) { g_print ("Omitting link for pad %s:%s because mimetype %s is non-audio\n", gst_object_get_name (parent), gst_pad_get_name (pad), mime); return; } /* can it link to the audiopad? */ audiocaps = gst_pad_get_caps (gst_element_get_pad (audiosink, "sink")); res = gst_caps_intersect (caps, audiocaps); if (res && !gst_caps_is_empty (res)) { g_print ("Found pad to link to audiosink - plugging is now done\n"); close_link (pad, audiosink, "sink", NULL); gst_caps_free (audiocaps); gst_caps_free (res); return; } gst_caps_free (audiocaps); gst_caps_free (res); /* try to plug from our list */ for (item = factories; item != NULL; item = item->next) { GstElementFactory *factory = GST_ELEMENT_FACTORY (item->data); const GList *pads; for (pads = gst_element_factory_get_pad_templates (factory); pads != NULL; pads = pads->next) { GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data); /* find the sink template - need an always pad*/ if (templ->direction != GST_PAD_SINK || templ->presence != GST_PAD_ALWAYS) { continue; } /* can it link? */ res = gst_caps_intersect (caps, templ->caps); if (res && !gst_caps_is_empty (res)) { GstElement *element; gchar *name_template = g_strdup (templ->name_template); /* close link and return */ gst_caps_free (res); element = gst_element_factory_create (factory, NULL); close_link (pad, element, name_template, gst_element_factory_get_pad_templates (factory)); g_free (name_template); return; } gst_caps_free (res); /* we only check one sink template per factory, so move on to the * next factory now */ break; } } /* if we get here, no item was found */ g_print ("No compatible pad found to decode %s on %s:%s\n", mime, gst_object_get_name (parent), gst_pad_get_name (pad)); } static void cb_typefound (GstElement *typefind, guint probability, GstCaps *caps, gpointer data) { gchar *s; s = gst_caps_to_string (caps); g_print ("Detected media type %s\n", s); g_free (s); /* actually plug now */ try_to_plug (gst_element_get_pad (typefind, "src"), caps); } By doing all this, we will be able to make a simple autoplugger that can automatically setup a pipeline for any media type. In the example below, we will do this for audio only. However, we can also do this for video to create a player that plays both audio and video. The example above is a good first try for an autoplugger. Next steps would be to listen for pad-removed signals, so we can dynamically change the plugged pipeline if the stream changes (this happens for DVB or Ogg radio). Also, you might want special-case code for input with known content (such as a DVD or an audio-CD), and much, much more. Moreover, you'll want many checks to prevent infinite loops during autoplugging, maybe you'll want to implement shortest-path-finding to make sure the most optimal pipeline is chosen, and so on. Basically, the features that you implement in an autoplugger depend on what you want to use it for. For full-blown implementations, see the playbin, decodebin and spider elements. Pipeline manipulation This chapter will discuss how you can manipulate your pipeline in several ways from your application on. Parts of this chapter are downright hackish, so be assured that you'll need some programming knowledge before you start reading this. Topics that will be discussed here include how you can insert data into a pipeline from your application, how to read data from a pipeline, how to manipulate the pipeline's speed, length, starting point and how to listen to a pipeline's data processing. Data probes Probes are best envisioned as pad listeners. They are attached to a pad in a pipeline, and you can add callback functions to this probe. Those callback functions will be called whenever data is being sent over this pad. The callback can then decide whether the data should be discarded or it can replace the piece of data with another piece of data. In this callback, it can also trigger actions in the application itself. For pipeline manipulation, probes are rather limited, but for pipeline tracking, they can be very useful. Manually adding or removing data from/to a pipeline Many people have expressed the wish to use their own sources to inject data into a pipeline. Some people have also expressed the wish to grab the output in a pipeline and take care of the actual output inside their application. While either of these methods are stongly discouraged, GStreamer offers hacks to do this. However, there is no support for those methods. If it doesn't work, you're on your own. Also, synchronization, thread-safety and other things that you've been able to take for granted so far are no longer guanranteed if you use any of those methods. It's always better to simply write a plugin and have the pipeline schedule and manage it. See the Plugin Writer's Guide for more information on this topic. Also see the next section, which will explain how to embed plugins statically in your application. After all those disclaimers, let's start. There's three possible elements that you can use for the above-mentioned purposes. Those are called fakesrc (an imaginary source), fakesink (an imaginary sink) and identity (an imaginary filter). The same method applies to each of those elements. Here, we will discuss how to use those elements to insert (using fakesrc) or grab (using fakesink or identity) data from a pipeline, and how to set negotiation. Inserting or grabbing data The three before-mentioned elements (fakesrc, fakesink and identity) each have a handoff signal that will be called in the _get ()- (fakesrc) or _chain ()-function (identity, fakesink). In the signal handler, you can set (fakesrc) or get (identity, fakesink) data to/from the provided buffer. Note that in the case of fakesrc, you have to set the size of the provided buffer using the sizemax property. For both fakesrc and fakesink, you also have to set the signal-handoffs property for this method to work. Note that your handoff function should not block, since this will block pipeline iteration. Also, do not try to use all sort of weird hacks in such functions to accomplish something that looks like synchronization or so; it's not the right way and will lead to issues elsewhere. If you're doing any of this, you're basically misunderstanding the GStreamer design. Forcing a format Sometimes, when using fakesrc as a source in your pipeline, you'll want to set a specific format, for example a video size and format or an audio bitsize and number of channels. You can do this by forcing a specific GstCaps on the pipeline, which is possible by using filtered caps. You can set a filtered caps on a link by using gst_pad_link_filtered (), where the third argument is the format to force on the link. Example application This example application will generate black/white (it switches every second) video to an X-window output by using fakesrc as a source and using filtered caps to force a format. Since the depth of the image depends on your X-server settings, we use a colorspace conversion element to make sure that the output to your X server will have the correct bitdepth. You can also set timestamps on the provided buffers to override the fixed framerate. #include <string.h> /* for memset () */ #include <gst/gst.h> static void cb_handoff (GstElement *fakesrc, GstBuffer *buffer, GstPad *pad, gpointer user_data) { static gboolean white = FALSE; /* this makes the image black/white */ memset (GST_BUFFER_DATA (buffer), white ? 0xff : 0x0, GST_BUFFER_SIZE (buffer)); white = !white; } gint main (gint argc, gchar *argv[]) { GstElement *pipeline, *fakesrc, *conv, *videosink; GstCaps *filter; /* init GStreamer */ gst_init (&argc, &argv); /* setup pipeline */ pipeline = gst_pipeline_new ("pipeline"); fakesrc = gst_element_factory_make ("fakesrc", "source"); conv = gst_element_factory_make ("ffmpegcolorspace", "conv"); videosink = gst_element_factory_make ("ximagesink", "videosink"); /* setup */ filter = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, 384, "height", G_TYPE_INT, 288, "framerate", G_TYPE_DOUBLE, (gdouble) 1.0, "bpp", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL); gst_element_link_filtered (fakesrc, conv, filter); gst_element_link (conv, videosink); gst_bin_add_many (GST_BIN (pipeline), fakesrc, conv, videosink, NULL); /* setup fake source */ g_object_set (G_OBJECT (fakesrc), "signal-handoffs", TRUE, "sizemax", 384 * 288 * 2, "sizetype", 2, NULL); g_signal_connect (fakesrc, "handoff", G_CALLBACK (cb_handoff), NULL); /* play */ gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))) ; /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Embedding static elements in your application The Plugin Writer's Guide describes in great detail how to write elements for the GStreamer framework. In this section, we will solely discuss how to embed such elements statically in your application. This can be useful for application-specific elements that have no use elsewhere in GStreamer. Dynamically loaded plugins contain a structure that's defined using GST_PLUGIN_DEFINE (). This structure is loaded when the plugin is loaded by the GStreamer core. The structure contains an initialization function (usually called plugin_init) that will be called right after that. It's purpose is to register the elements provided by the plugin with the GStreamer framework. If you want to embed elements directly in your application, the only thing you need to do is to manually run this structure using _gst_plugin_register_static (). The initialization will then be called, and the elements will from then on be available like any other element, without them having to be dynamically loadable libraries. In the example below, you would be able to call gst_element_factory_make ("my-element-name", "some-name") to create an instance of the element. /* * Here, you would write the actual plugin code. */ [..] static gboolean register_elements (GstPlugin *plugin) { return gst_element_register (plugin, "my-element-name", GST_RANK_NONE, MY_PLUGIN_TYPE); } static GstPluginDesc plugin_desc = { GST_VERSION_MAJOR, GST_VERSION_MINOR, "my-private-plugins", "Private elements of my application", register_elements, NULL, "0.0.1", "LGPL", "my-application", "http://www.my-application.net/", GST_PADDING_INIT }; /* * Call this function right after calling gst_init (). */ void my_elements_init (void) { _gst_plugin_register_static (&plugin_desc); } Higher-level interfaces for GStreamer applications In the previous two parts, you have learned many of the internals and their corresponding low-level interfaces into GStreamer application programming. Many people will, however, not need so much control (and as much code), but will prefer to use a standard playback interface that does most of the difficult internals for them. In this chapter, we will introduce you into the concept of autopluggers, playback managing elements, XML-based pipelines and other such things. Those higher-level interfaces are intended to simplify GStreamer-based application programming. They do, however, also reduce the flexibility. It is up to the application developer to choose which interface he will want to use. Components GStreamer includes several higher-level components to simplify your applications life. All of the components discussed here (for now) are targetted at media playback. The idea of each of these components is to integrate as closely as possible with a GStreamer pipeline, but to hide the complexity of media type detection and several other rather complex topics that have been discussed in . We currently recommend people to use either playbin (see ) or decodebin (see ), depending on their needs. The other components discussed here are either outdated or deprecated. The documentation is provided for legacy purposes. Use of those other components is not recommended. Playbin Playbin is an element that can be created using the standard GStreamer API (e.g. gst_element_factory_make ()). The factory is conveniently called playbin. By being a GstElement, playbin automatically supports all of the features of this class, including error handling, tag support, state handling, getting stream positions, seeking, and so on. Setting up a playbin pipeline is as simple as creating an instance of the playbin element, setting a file location (this has to be a valid URI, so <protocol>://<location>, e.g. file:///tmp/my.ogg or http://www.example.org/stream.ogg) using the uri property on playbin, and then setting the element to the GST_STATE_PLAYING state. Internally, playbin uses threads, so there's no need to iterate the element or anything. However, one thing to keep in mind is that signals fired by playbin might come from another than the main thread, so be sure to keep this in mind in your signal handles. Most application programmers will want to use a function such as g_idle_add () to make sure that the signal is handled in the main thread. #include <gst/gst.h> static void cb_eos (GstElement *play, gpointer data) { gst_main_quit (); } static void cb_error (GstElement *play, GstElement *src, GError *err, gchar *debug, gpointer data) { g_print ("Error: %s\n", err->message); } gint main (gint argc, gchar *argv[]) { GstElement *play; /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have a URI */ if (argc != 2) { g_print ("Usage: %s <URI>\n", argv[0]); return -1; } /* set up */ play = gst_element_factory_make ("playbin", "play"); g_object_set (G_OBJECT (play), "uri", argv[1], NULL); g_signal_connect (play, "eos", G_CALLBACK (cb_eos), NULL); g_signal_connect (play, "error", G_CALLBACK (cb_error), NULL); if (gst_element_set_state (play, GST_STATE_PLAYING) != GST_STATE_SUCCESS) { g_print ("Failed to play\n"); return -1; } /* now run */ gst_main (); /* also clean up */ gst_element_set_state (play, GST_STATE_NULL); gst_object_unref (GST_OBJECT (play)); return 0; } Playbin has several features that have been discussed previously: Settable video and audio output (using the video-sink and audio-sink properties). Mostly controllable and trackable as a GstElement, including error handling, eos handling, tag handling, state handling, media position handling and seeking. Buffers network-sources. Supports visualizations for audio-only media. Supports subtitles, both in the media as well as from separate files. Supports stream selection and disabling. If your media has multiple audio or subtitle tracks, you can dynamically choose which one to play back, or decide to turn it off alltogther (which is especially useful to turn off subtitles). Decodebin Decodebin is the actual autoplugger backend of playbin, which was discussed in the previous section. Decodebin will, in short, accept input from a source that is linked to its sinkpad and will try to detect the media type contained in the stream, and set up decoder routines for each of those. It will automatically select decoders. For each decoded stream, it will emit the new-decoded-pad signal, to let the client know about the newly found decoded stream. For unknown streams (which might be the whole stream), it will emit the unknown-type signal. The application is then responsible for reporting the error to the user. The example code below will play back an audio stream of an input file. For readability, it does not include any error handling of any sort. #include <gst/gst.h> GstElement *pipeline, *audio; GstPad *audiopad; static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) { GstCaps *caps; GstStructure *str; /* only link audio; only link once */ if (GST_PAD_IS_LINKED (audiopad)) return; caps = gst_pad_get_caps (pad); str = gst_caps_get_structure (caps, 0); if (!g_strrstr (gst_structure_get_name (str), "audio")) return; /* link'n'play */ gst_pad_link (pad, audiopad); gst_bin_add (GST_BIN (pipeline), audio); gst_bin_sync_children_state (GST_BIN (pipeline)); } gint main (gint argc, gchar *argv[]) { GstElement *src, *dec, *conv, *scale, *sink; /* init GStreamer */ gst_init (&argc, &argv); /* make sure we have input */ if (argc != 2) { g_print ("Usage: %s <filename>\n", argv[0]); return -1; } /* setup */ pipeline = gst_pipeline_new ("pipeline"); src = gst_element_factory_make ("filesrc", "source"); g_object_set (G_OBJECT (src), "location", argv[1], NULL); dec = gst_element_factory_make ("decodebin", "decoder"); g_signal_connect (dec, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); audio = gst_bin_new ("audiobin"); conv = gst_element_factory_make ("audioconvert", "aconv"); audiopad = gst_element_get_pad (conv, "sink"); scale = gst_element_factory_make ("audioscale", "scale"); sink = gst_element_factory_make ("alsasink", "sink"); gst_bin_add_many (GST_BIN (audio), conv, scale, sink, NULL); gst_element_link_many (conv, scale, sink, NULL); gst_bin_add_many (GST_BIN (pipeline), src, dec, NULL); gst_element_link (src, dec); /* run */ gst_element_set_state (audio, GST_STATE_PAUSED); gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))) ; /* cleanup */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Decodebin, similar to playbin, supports the following features: Can decode an unlimited number of contained streams to decoded output pads. Is handled as a GstElement in all ways, including tag or error forwarding and state handling. Although decodebin is a good autoplugger, there's a whole lot of things that it does not do and is not intended to do: Taking care of input streams with a known media type (e.g. a DVD, an audio-CD or such). Selection of streams (e.g. which audio track to play in case of multi-language media streams). Overlaying subtitles over a decoded video stream. Decodebin can be easily tested on the commandline, e.g. by using the command gst-launch-0.8 filesrc location=file.ogg ! decodebin ! audioconvert ! audioscale ! alsasink. Spider Spider is an autoplugger that looks and feels very much like decodebin. On the commandline, you can literally switch between spider and decodebin and it'll mostly just work. Try, for example, gst-launch-0.8 filesrc location=file.ogg ! spider ! audioconvert ! audioscale ! alsasink. Although the two may seem very much alike from the outside, they are very different from the inside. Those internal differences are the main reason why spider is currently considered deprecated (along with the fact that it was hard to maintain). As opposed to decodebin, spider does not decode pads and emit signals for each detected stream. Instead, you have to add output sinks to spider by create source request pads and connecting those to sink elements. This means that streams decoded by spider cannot be dynamic. Also, spider uses many loop-based elements internally, which is rather heavy scheduler-wise. Code for using spider would look almost identical to the code of decodebin, and is therefore omitted. Also, featureset and limitations are very much alike, except for the above-mentioned extra limitations for spider with respect to decodebin. GstPlay GstPlay is a GtkWidget with a simple API to play, pause and stop a media file. GstEditor GstEditor is a set of widgets to display a graphical representation of a pipeline. XML in GStreamer GStreamer uses XML to store and load its pipeline definitions. XML is also used internally to manage the plugin registry. The plugin registry is a file that contains the definition of all the plugins GStreamer knows about to have quick access to the specifics of the plugins. We will show you how you can save a pipeline to XML and how you can reload that XML file again for later use. Turning GstElements into XML We create a simple pipeline and write it to stdout with gst_xml_write_file (). The following code constructs an MP3 player pipeline with two threads and then writes out the XML both to stdout and to a file. Use this program with one argument: the MP3 file on disk. #include <stdlib.h> #include <gst/gst.h> gboolean playing; int main (int argc, char *argv[]) { GstElement *filesrc, *osssink, *queue, *queue2, *decode; GstElement *bin; GstElement *thread, *thread2; gst_init (&argc,&argv); if (argc != 2) { g_print ("usage: %s <mp3 filename>\n", argv[0]); exit (-1); } /* create a new thread to hold the elements */ thread = gst_element_factory_make ("thread", "thread"); g_assert (thread != NULL); thread2 = gst_element_factory_make ("thread", "thread2"); g_assert (thread2 != NULL); /* create a new bin to hold the elements */ bin = gst_bin_new ("bin"); g_assert (bin != NULL); /* create a disk reader */ filesrc = gst_element_factory_make ("filesrc", "disk_source"); g_assert (filesrc != NULL); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); queue = gst_element_factory_make ("queue", "queue"); queue2 = gst_element_factory_make ("queue", "queue2"); /* and an audio sink */ osssink = gst_element_factory_make ("osssink", "play_audio"); g_assert (osssink != NULL); decode = gst_element_factory_make ("mad", "decode"); g_assert (decode != NULL); /* add objects to the main bin */ gst_bin_add_many (GST_BIN (bin), filesrc, queue, NULL); gst_bin_add_many (GST_BIN (thread), decode, queue2, NULL); gst_bin_add (GST_BIN (thread2), osssink); gst_element_link_many (filesrc, queue, decode, queue2, osssink, NULL); gst_bin_add_many (GST_BIN (bin), thread, thread2, NULL); /* write the bin to stdout */ gst_xml_write_file (GST_ELEMENT (bin), stdout); /* write the bin to a file */ gst_xml_write_file (GST_ELEMENT (bin), fopen ("xmlTest.gst", "w")); exit (0); } The most important line is: gst_xml_write_file (GST_ELEMENT (bin), stdout); gst_xml_write_file () will turn the given element into an xmlDocPtr that is then formatted and saved to a file. To save to disk, pass the result of a fopen(2) as the second argument. The complete element hierarchy will be saved along with the inter element pad links and the element parameters. Future GStreamer versions will also allow you to store the signals in the XML file. Loading a GstElement from an XML file Before an XML file can be loaded, you must create a GstXML object. A saved XML file can then be loaded with the gst_xml_parse_file (xml, filename, rootelement) method. The root element can optionally left NULL. The following code example loads the previously created XML file and runs it. #include <stdlib.h> #include <gst/gst.h> int main(int argc, char *argv[]) { GstXML *xml; GstElement *bin; gboolean ret; gst_init (&argc, &argv); xml = gst_xml_new (); ret = gst_xml_parse_file(xml, "xmlTest.gst", NULL); g_assert (ret == TRUE); bin = gst_xml_get_element (xml, "bin"); g_assert (bin != NULL); gst_element_set_state (bin, GST_STATE_PLAYING); while (gst_bin_iterate(GST_BIN(bin))); gst_element_set_state (bin, GST_STATE_NULL); exit (0); } gst_xml_get_element (xml, "name") can be used to get a specific element from the XML file. gst_xml_get_topelements (xml) can be used to get a list of all toplevel elements in the XML file. In addition to loading a file, you can also load a from a xmlDocPtr and an in memory buffer using gst_xml_parse_doc and gst_xml_parse_memory respectively. Both of these methods return a gboolean indicating success or failure of the requested action. Adding custom XML tags into the core XML data It is possible to add custom XML tags to the core XML created with gst_xml_write. This feature can be used by an application to add more information to the save plugins. The editor will for example insert the position of the elements on the screen using the custom XML tags. It is strongly suggested to save and load the custom XML tags using a namespace. This will solve the problem of having your XML tags interfere with the core XML tags. To insert a hook into the element saving procedure you can link a signal to the GstElement using the following piece of code: xmlNsPtr ns; ... ns = xmlNewNs (NULL, "http://gstreamer.net/gst-test/1.0/", "test"); ... thread = gst_element_factory_make ("thread", "thread"); g_signal_connect (G_OBJECT (thread), "object_saved", G_CALLBACK (object_saved), g_strdup ("decoder thread")); ... When the thread is saved, the object_save method will be called. Our example will insert a comment tag: static void object_saved (GstObject *object, xmlNodePtr parent, gpointer data) { xmlNodePtr child; child = xmlNewChild (parent, ns, "comment", NULL); xmlNewChild (child, ns, "text", (gchar *)data); } Adding the custom tag code to the above example you will get an XML file with the custom tags in it. Here's an excerpt: ... <gst:element> <gst:name>thread</gst:name> <gst:type>thread</gst:type> <gst:version>0.1.0</gst:version> ... </gst:children> <test:comment> <test:text>decoder thread</test:text> </test:comment> </gst:element> ... To retrieve the custom XML again, you need to attach a signal to the GstXML object used to load the XML data. You can then parse your custom XML from the XML tree whenever an object is loaded. We can extend our previous example with the following piece of code. xml = gst_xml_new (); g_signal_connect (G_OBJECT (xml), "object_loaded", G_CALLBACK (xml_loaded), xml); ret = gst_xml_parse_file (xml, "xmlTest.gst", NULL); g_assert (ret == TRUE); Whenever a new object has been loaded, the xml_loaded function will be called. This function looks like: static void xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data) { xmlNodePtr children = self->xmlChildrenNode; while (children) { if (!strcmp (children->name, "comment")) { xmlNodePtr nodes = children->xmlChildrenNode; while (nodes) { if (!strcmp (nodes->name, "text")) { gchar *name = g_strdup (xmlNodeGetContent (nodes)); g_print ("object %s loaded with comment '%s'\n", gst_object_get_name (object), name); } nodes = nodes->next; } } children = children->next; } } As you can see, you'll get a handle to the GstXML object, the newly loaded GstObject and the xmlNodePtr that was used to create this object. In the above example we look for our special tag inside the XML tree that was used to load the object and we print our comment to the console. Appendices By now, you've learned all about the internals of GStreamer and application programming using the GStreamer framework. This part will go into some random bits that are useful to know if you're going to use GStreamer for serious application programming. It will touch upon things related to integration with popular desktop environments that we run on (GNOME, KDE, OS X, Windows), it will shortly explain how applications included with GStreamer can help making your life easier, and some information on debugging. Things to check when writing an application This chapter contains a fairly random selection of things that can be useful to keep in mind when writing GStreamer-based applications. It's up to you how much you're going to use the information provided here. We will shortly discuss how to debug pipeline problems using GStreamer applications. Also, we will touch upon how to acquire knowledge about plugins and elements and how to test simple pipelines before building applications around them. Good programming habits Always connect to the error signal of your topmost pipeline to be notified of errors in your pipeline. Always check return values of GStreamer functions. Especially, check return values of gst_element_link () and gst_element_set_state (). Always use your pipeline object to keep track of the current state of your pipeline. Don't keep private variables in your application. Also, don't update your user interface if a user presses the play button. Instead, connect to the state-changed signal of your topmost pipeline and update the user interface whenever this signal is triggered. Debugging Applications can make use of the extensive GStreamer debugging system to debug pipeline problems. Elements will write output to this system to log what they're doing. It's not used for error reporting, but it is very useful for tracking what an element is doing exactly, which can come in handy when debugging application issues (such as failing seeks, out-of-sync media, etc.). Most GStreamer-based applications accept the commandline option --gst-debug=LIST and related family members. The list consists of a comma-separated list of category/level pairs, which can set the debugging level for a specific debugging category. For example, --gst-debug=oggdemux:5 would turn on debugging for the Ogg demuxer element. You can use wildcards as well. A debugging level of 0 will turn off all debugging, and a level of 5 will turn on all debugging. Intermediate values only turn on some debugging (based on message severity; 2, for example, will only display errors and warnings). Here's a list of all available options: --gst-debug-help will print available debug categories and exit. --gst-debug-level=LEVEL will set the default debug level (which can range from 0 (no output) to 5 (everything)). --gst-debug=LIST takes a comma-separated list of category_name:level pairs to set specific levels for the individual categories. Example: GST_AUTOPLUG:5,avidemux:3. --gst-debug-no-color will disable color debugging. --gst-debug-disable disables debugging alltogether. --gst-plugin-spew enables printout of errors while loading GStreamer plugins. Conversion plugins GStreamer contains a bunch of conversion plugins that most applications will find useful. Specifically, those are videoscalers (videoscale), colorspace convertors (ffmpegcolorspace), audio format convertors and channel resamplers (audioconvert) and audio samplerate convertors (audioscale). Those convertors don't do anything when not required, they will act in passthrough mode. They will activate when the hardware doesn't support a specific request, though. All applications are recommended to use those elements. Utility applications provided with GStreamer GStreamer comes with a default set of command-line utilities that can help in application development. We will discuss only gst-launch and gst-inspect here. gst-launch gst-launch is a simple script-like commandline application that can be used to test pipelines. For example, the command gst-launch sinesrc ! alsasink will run a pipeline which generates a sine-wave audio stream and plays it to your ALSA audio card. gst-launch also allows the use of threads (using curly brackets, so { and }) and bins (using brackets, so ( and )). You can use dots to imply padnames on elements, or even omit the padname to automatically select a pad. Using all this, the pipeline gst-launch filesrc location=file.ogg ! oggdemux name=d { d. ! theoradec ! ffmpegcolorspace ! xvimagesink } { d. ! vorbisdec ! alsasink } will play an Ogg file containing a Theora video-stream and a Vorbis audio-stream. You can also use autopluggers such as decodebin on the commandline. See the manual page of gst-launch for more information. gst-inspect gst-inspect can be used to inspect all properties, signals, dynamic parameters and the object hierarchy of an element. This can be very useful to see which GObject properties or which signals (and using what arguments) an element supports. Run gst-inspect fakesrc to get an idea of what it does. See the manual page of gst-inspect for more information. Integration GStreamer tries to integrate closely with operating systems (such as Linux and UNIX-like operating systems, OS X or Windows) and desktop environments (such as GNOME or KDE). In this chapter, we'll mention some specific techniques to integrate your application with your operating system or desktop environment of choice. Linux and UNIX-like operating systems GStreamer provides a basic set of elements that are useful when integrating with Linux or a UNIX-like operating system. For audio input and output, GStreamer provides input and output elements for several audio subsystems. Amongst others, GStreamer includes elements for ALSA (alsasrc, alsamixer, alsasink), OSS (osssrc, ossmixer, osssink) and Sun audio (sunaudiosrc, sunaudiomixer, sunaudiosink). For video input, GStreamer contains source elements for Video4linux (v4lsrc, v4lmjpegsrc, v4lelement and v4lmjpegisnk) and Video4linux2 (v4l2src, v4l2element). For video output, GStreamer provides elements for output to X-windows (ximagesink), Xv-windows (xvimagesink; for hardware-accelerated video), direct-framebuffer (dfbimagesink) and openGL image contexts (glsink). GNOME desktop GStreamer has been the media backend of the GNOME desktop since GNOME-2.2 onwards. Nowadays, a whole bunch of GNOME applications make use of GStreamer for media-processing, including (but not limited to) Rhythmbox, Totem and Sound Juicer. Most of these GNOME applications make use of some specific techniques to integrate as closely as possible with the GNOME desktop: GNOME applications call gnome_program_init () to parse command-line options and initialize the necessary gnome modules. GStreamer applications would normally call gst_init () to do the same for GStreamer. This would mean that only one of the two can parse command-line options. To work around this issue, GStreamer can provide a poptOption array which can be passed to gnome_program_init (). #include <gnome.h> #include <gst/gst.h> gint main (gint argc, gchar *argv[]) { struct poptOption options[] = { {NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL}, POPT_TABLEEND }; /* init GStreamer and GNOME using the GStreamer popt tables */ options[0].arg = (void *) gst_init_get_popt_table (); gnome_program_init ("my-application", "0.0.1", LIBGNOMEUI_MODULE, argc, argv, GNOME_PARAM_POPT_TABLE, options, NULL); [..] } GNOME stores the default video and audio sources and sinks in GConf. GStreamer provides a small utility library that can be used to get the elements from the registry using functions such as gst_gconf_get_default_video_sink (). See the header file (gst/gconf/gconf.h) for details. All GNOME applications are recommended to use those variables. GStreamer provides data input/output elements for use with the GNOME-VFS system. These elements are called gnomevfssrc and gnomevfssink. KDE desktop GStreamer has been proposed for inclusion in KDE-4.0. Currently, GStreamer is included as an optional component, and it's used by several KDE applications, including AmaroK and JuK. A backend for KMPlayer is currently under development. Although not yet as complete as the GNOME integration bits, there are already some KDE integration specifics available. This list will probably grow as GStreamer starts to be used in KDE-4.0: AmaroK contains a kiosrc element, which is a source element that integrates with the KDE VFS subsystem KIO. OS X GStreamer provides native video and audio output elements for OS X. It builds using the standard development tools for OS X. Windows GStreamer builds using Microsoft Visual C .NET 2003 and using Cygwin. Licensing advisoryHow to license the applications you build with GStreamer The licensing of GStreamer is no different from a lot of other libraries out there like GTK+ or glibc: we use the LGPL. What complicates things with regards to GStreamer is its plugin-based design and the heavily patented and proprietary nature of many multimedia codecs. While patents on software are currently only allowed in a small minority of world countries (the US and Australia being the most important of those), the problem is that due to the central place the US hold in the world economy and the computing industry, software patents are hard to ignore wherever you are. Due to this situation, many companies, including major GNU/Linux distributions, get trapped in a situation where they either get bad reviews due to lacking out-of-the-box media playback capabilities (and attempts to educate the reviewers have met with little success so far), or go against their own - and the free software movement's - wish to avoid proprietary software. Due to competitive pressure, most choose to add some support. Doing that through pure free software solutions would have them risk heavy litigation and punishment from patent owners. So when the decision is made to include support for patented codecs, it leaves them the choice of either using special proprietary applications, or try to integrate the support for these codecs through proprietary plugins into the multimedia infrastructure provided by GStreamer. Faced with one of these two evils the GStreamer community of course prefer the second option. The problem which arises is that most free software and open source applications developed use the GPL as their license. While this is generally a good thing, it creates a dilemma for people who want to put together a distribution. The dilemma they face is that if they include proprietary plugins in GStreamer to support patented formats in a way that is legal for them, they do risk running afoul of the GPL license of the applications. We have gotten some conflicting reports from lawyers on whether this is actually a problem, but the official stance of the FSF is that it is a problem. We view the FSF as an authority on this matter, so we are inclined to follow their interpretation of the GPL license. So what does this mean for you as an application developer? Well, it means you have to make an active decision on whether you want your application to be used together with proprietary plugins or not. What you decide here will also influence the chances of commercial distributions and Unix vendors shipping your application. The GStreamer community suggest you license your software using a license that will allow proprietary plugins to be bundled with GStreamer and your applications, in order to make sure that as many vendors as possible go with GStreamer instead of less free solutions. This in turn we hope and think will let GStreamer be a vehicle for wider use of free formats like the Xiph.org formats. If you do decide that you want to allow for non-free plugins to be used with your application you have a variety of choices. One of the simplest is using licenses like LGPL, MPL or BSD for your application instead of the GPL. Or you can add a exceptions clause to your GPL license stating that you except GStreamer plugins from the obligations of the GPL. A good example of such a GPL exception clause would be, using the Muine music player project as an example: The Muine project hereby grants permission for non-GPL-compatible GStreamer plugins to be used and distributed together with GStreamer and Muine. This permission goes above and beyond the permissions granted by the GPL license Muine is covered by. Our suggestion among these choices is to use the LGPL license, as it is what resembles the GPL most and it makes it a good licensing fit with the major GNU/Linux desktop projects like GNOME and KDE. It also allows you to share code more openly with projects that have compatible licenses. Obviously, pure GPL code without the above-mentioned clause is not usable in your application as such. By choosing the LGPL, there is no need for an exception clause and thus code can be shared more freely. I have above outlined the practical reasons for why the GStreamer community suggest you allow non-free plugins to be used with your applications. We feel that in the multimedia arena, the free software community is still not strong enough to set the agenda and that blocking non-free plugins to be used in our infrastructure hurts us more than it hurts the patent owners and their ilk. This view is not shared by everyone. The Free Software Foundation urges you to use an unmodified GPL for your applications, so as to push back against the temptation to use non-free plug-ins. They say that since not everyone else has the strength to reject them because they are unethical, they ask your help to give them a legal reason to do so. This advisory is part of a bigger advisory with a FAQ which you can find on the GStreamer website Windows supportBuilding GStreamer under Win32There are different makefiles that can be used to build GStreamer with the usual Microsoft compiling tools.The Makefile is meant to be used with the GNU make program and the free version of the Microsoft compiler (http://msdn.microsoft.com/visualc/vctoolkit2003/). You also have to modify your system environment variables to use it from the command-line. You will also need a working Platform SDK for Windows that is available for free from Microsoft.The projects/makefiles will generate automatically some source files needed to compile GStreamer. That requires that you have installed on your system some GNU tools and that they are available in your system PATH.The GStreamer project depends on other libraries, namely :GLibpoptlibxml2libintllibiconvThere is now an existing package that has all these dependencies built with MSVC7.1. It exists either as precompiled librairies and headers in both Release and Debug mode, or as the source package to build it yourself. You can find it on http://mukoli.free.fr/gstreamer/deps/.NotesGNU tools needed that you can find on http://gnuwin32.sourceforge.net/GNU flex (tested with 2.5.4)GNU bison (tested with 1.35)and http://www.mingw.org/GNU make (tested with 3.80)the generated files from the -auto makefiles will be available soon separately on the net for convenience (people who don't want to install GNU tools).Installation on the systemBy default, GSTreamer needs a registry. You have to generate it using "gst-register.exe". It will create the file in c:\gstreamer\registry.xml that will hold all the plugins you can use.You should install the GSTreamer core in c:\gstreamer\bin and the plugins in c:\gstreamer\plugins. Both directories should be added to your system PATH. The library dependencies should be installed in c:\usrFor example, my current setup is :c:\gstreamer\registry.xmlc:\gstreamer\bin\gst-inspect.exec:\gstreamer\bin\gst-launch.exec:\gstreamer\bin\gst-register.exec:\gstreamer\bin\gstbytestream.dllc:\gstreamer\bin\gstelements.dllc:\gstreamer\bin\gstoptimalscheduler.dllc:\gstreamer\bin\gstspider.dllc:\gstreamer\bin\libgtreamer-0.8.dllc:\gstreamer\plugins\gst-libs.dllc:\gstreamer\plugins\gstmatroska.dllc:\usr\bin\iconv.dllc:\usr\bin\intl.dllc:\usr\bin\libglib-2.0-0.dllc:\usr\bin\libgmodule-2.0-0.dllc:\usr\bin\libgobject-2.0-0.dllc:\usr\bin\libgthread-2.0-0.dllc:\usr\bin\libxml2.dllc:\usr\bin\popt.dllQuotes from the Developers As well as being a cool piece of software, GStreamer is a lively project, with developers from around the globe very actively contributing. We often hang out on the #gstreamer IRC channel on irc.freenode.net: the following are a selection of amusingNo guarantee of sense of humour compatibility is given. quotes from our conversations. 14 Oct 2004 * zaheerm wonders how he can break gstreamer today :) ensonic: zaheerm, spider is always a good starting point 14 Jun 2004 teuf: ok, things work much better when I don't write incredibly stupid and buggy code thaytan: I find that too 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 --- wingo-party is now known as wingo * wingo holds head 16 Feb 2001 wtay: I shipped a few commerical products to >40000 people now but GStreamer is way more exciting... 16 Feb 2001 * tool-man is a gstreamer groupie 14 Jan 2001 Omega: did you run ldconfig? maybe it talks to init? wtay: not sure, don't think so... I did run gstreamer-register though :-) Omega: ah, that did it then ;-) wtay: right Omega: probably not, but in case GStreamer starts turning into an OS, someone please let me know? 9 Jan 2001 wtay: me tar, you rpm? wtay: hehe, forgot "zan" Omega: ? wtay: me tar"zan", you ... 7 Jan 2001 Omega: that means probably building an agreggating, cache-massaging queue to shove N buffers across all at once, forcing cache transfer. wtay: never done that before... Omega: nope, but it's easy to do in gstreamer <g> wtay: sure, I need to rewrite cp with gstreamer too, someday :-) 7 Jan 2001 wtay: GStreamer; always at least one developer is awake... 5/6 Jan 2001 wtay: we need to cut down the time to create an mp3 player down to seconds... richardb: :) Omega: I'm wanting to something more interesting soon, I did the "draw an mp3 player in 15sec" back in October '99. wtay: by the time Omega gets his hands on the editor, you'll see a complete audio mixer in the editor :-) richardb: Well, it clearly has the potential... Omega: Working on it... ;-) 28 Dec 2000 MPAA: We will sue you now, you have violated our IP rights! wtay: hehehe MPAA: How dare you laugh at us? We have lawyers! We have Congressmen! We have LARS! wtay: I'm so sorry your honor MPAA: Hrumph. * wtay bows before thy 4 Jun 2001taaz: you witchdoctors and your voodoo mpeg2 black magic... omega_: um. I count three, no four different cults there <g> ajmitch: hehe omega_: witchdoctors, voodoo, black magic, omega_: and mpeg Done. Copying .css files: base.css Copying .png images: build/images/bin-element-ghost.png build/images/bin-element-noghost.png build/images/bin-element.png build/images/filter-element-multi.png build/images/filter-element.png build/images/hello-world.png build/images/linked-elements.png build/images/mime-world.png build/images/queue.png build/images/sink-element.png build/images/src-element.png build/images/state-diagram.png build/images/thread.png /bin/sh ../../mkinstalldirs /usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc cp -pr html /usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc test -z "/usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc" || mkdir -p -- "/usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc" make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/manual' Making install in pwg make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' cd build && xmllint -noout -valid pwg.xml make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg/build/pwg.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" RichardJohnBoulton richard-gst@tartarus.org ErikWalthinsen omega@temple-baptist.com SteveBaker stevebaker_org@yahoo.co.uk LeifJohnson leif@ambient.2y.net RonaldS.Bultje rbultje@ronald.bitfreak.net This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). GStreamer Plugin Writer's Guide (0.8.11)Introduction GStreamer is an exremely powerful and versatile framework for creating streaming media applications. Many of the virtues of the GStreamer framework come from its modularity: GStreamer can seamlessly incorporate new plugin modules. But because modularity and power often come at a cost of greater complexity (consider, for example, CORBA), writing new plugins is not always easy. This guide is intended to help you understand the GStreamer framework (version 0.8.11) so you can develop new plugins to extend the existing functionality. The guide addresses most issues by following the development of an example plugin - an audio filter plugin - written in C. However, the later parts of the guide also present some issues involved in writing other types of plugins, and the end of the guide describes some of the Python bindings for GStreamer. PrefaceWho Should Read This Guide? This guide explains how to write new modules for GStreamer. The guide is relevant to several groups of people: Anyone who wants to add support for new ways of processing data in GStreamer. For example, a person in this group might want to create a new data format converter, a new visualization tool, or a new decoder or encoder. Anyone who wants to add support for new input and output devices. For example, people in this group might want to add the ability to write to a new video output system or read data from a digital camera or special microphone. Anyone who wants to extend GStreamer in any way. You need to have an understanding of how the plugin system works before you can understand the constraints that the plugin system places on the rest of the code. Also, you might be surprised after reading this at how much can be done with plugins. This guide is not relevant to you if you only want to use the existing functionality of GStreamer, or if you just want to use an application that uses GStreamer. If you are only interested in using existing plugins to write a new application - and there are quite a lot of plugins already - you might want to check the GStreamer Application Development Manual. If you are just trying to get help with a GStreamer application, then you should check with the user manual for that particular application. Preliminary Reading This guide assumes that you are somewhat familiar with the basic workings of GStreamer. For a gentle introduction to programming concepts in GStreamer, you may wish to read the GStreamer Application Development Manual first. Also check out the documentation available on the GStreamer web site. Since GStreamer adheres to the GObject programming model, this guide also assumes that you understand the basics of GObject programming. There are several good introductions to the GObject library, including the GTK+ Tutorial and the Glib Object system. Structure of This Guide To help you navigate through this guide, it is divided into several large parts. Each part addresses a particular broad topic concerning GStreamer plugin development. The parts of this guide are laid out in the following order: - Introduction to the structure of a plugin, using an example audio filter for illustration. This part covers all the basic steps you generally need to perform to build a plugin, such as registering the element with GStreamer and setting up the basics so it can receive data from and send data to neighbour elements. The discussion begins by giving examples of generating the basic structures and registering an element in . Then, you will learn how to write the code to get a basic filter plugin working in , and . After that, we will show some of the GObject concepts on how to make an element configurable for applications and how to do application-element interaction in and . Next, you will learn to build a quick test application to test all that you've just learned in . We will just touch upon basics here. For full-blown application development, you should look at the Application Development Manual. - Information on advanced features of GStreamer plugin development. After learning about the basic steps, you should be able to create a functional audio or video filter plugin with some nice features. However, GStreamer offers more for plugin writers. This part of the guide includes chapters on more advanced topics, such as scheduling, media type definitions in GStreamer, clocks, interfaces and tagging. Since these features are purpose-specific, you can read them in any order, most of them don't require knowledge from other sections. The first chapter, named , will explain some of the basics of element scheduling. It is not very in-depth, but is mostly some sort of an introduction on why other things work as they do. Read this chapter if you're interested in GStreamer internals. Next, we will apply this knowledge and discuss another type of data transmission than what you learned in : . Loop-based elements will give you more control over input rate. This is useful when writing, for example, muxers or demuxers. Next, we will discuss media identification in GStreamer in . You will learn how to define new media types and get to know a list of standard media types defined in GStreamer. In the next chapter, you will learn the concept of request- and sometimes-pads, which are pads that are created dynamically, either because the application asked for it (request) or because the media stream requires it (sometimes). This will be in . The next chapter, , will explain the concept of clocks in GStreamer. You need this information when you want to know how elements should achieve audio/video synchronization. The next few chapters will discuss advanced ways of doing application-element interaction. Previously, we learned on the GObject-ways of doing this in and . We will discuss dynamic parameters, which are a way of defining element behaviour over time in advance, in . Next, you will learn about interfaces in . Interfaces are very target- specific ways of application-element interaction, based on GObject's GInterface. Lastly, you will learn about how metadata is handled in GStreamer in . The last chapter, , will discuss the concept of events in GStreamer. Events are, on the one hand, another way of doing application-element interaction. It takes care of seeking, for example. On the other hand, it is also a way in which elements interact with each other, such as letting each other know about media stream discontinuities, forwarding tags inside a pipeline and so on. - Explanation of writing other plugin types. Because the first two parts of the guide use an audio filter as an example, the concepts introduced apply to filter plugins. But many of the concepts apply equally to other plugin types, including sources, sinks, and autopluggers. This part of the guide presents the issues that arise when working on these more specialized plugin types. The part includes chapters on , , , and . - Further information for plugin developers. The appendices contain some information that stubbornly refuses to fit cleanly in other sections of the guide. Most of this section is not yet finished. The remainder of this introductory part of the guide presents a short overview of the basic concepts involved in GStreamer plugin development. Topics covered include , , and . If you are already familiar with this information, you can use this short overview to refresh your memory, or you can skip to . As you can see, there a lot to learn, so let's get started! Creating compound and complex elements by extending from a GstBin. This will allow you to create plugins that have other plugins embedded in them. Adding new mime-types to the registry along with typedetect functions. This will allow your plugin to operate on a completely new media type. Basic Concepts This chapter of the guide introduces the basic concepts of GStreamer. Understanding these concepts will help you grok the issues involved in extending GStreamer. Many of these concepts are explained in greater detail in the GStreamer Application Development Manual; the basic concepts presented here serve mainly to refresh your memory. Elements and Plugins Elements are at the core of GStreamer. In the context of plugin development, an element is an object derived from the GstElement class. Elements provide some sort of functionality when linked with other elements: For example, a source element provides data to a stream, and a filter element acts on the data in a stream. Without elements, GStreamer is just a bunch of conceptual pipe fittings with nothing to link. A large number of elements ship with GStreamer, but extra elements can also be written. Just writing a new element is not entirely enough, however: You will need to encapsulate your element in a plugin to enable GStreamer to use it. A plugin is essentially a loadable block of code, usually called a shared object file or a dynamically linked library. A single plugin may contain the implementation of several elements, or just a single one. For simplicity, this guide concentrates primarily on plugins containing one element. A filter is an important type of element that processes a stream of data. Producers and consumers of data are called source and sink elements, respectively. Bin elements contain other elements. One type of bin is responsible for scheduling the elements that they contain so that data flows smoothly. Another type of bin, called autoplugger elements, automatically add other elements to the bin and links them together so that they act as a filter between two arbitary stream types. The plugin mechanism is used everywhere in GStreamer, even if only the standard packages are being used. A few very basic functions reside in the core library, and all others are implemented in plugins. A plugin registry is used to store the details of the plugins in an XML file. This way, a program using GStreamer does not have to load all plugins to determine which are needed. Plugins are only loaded when their provided elements are requested. See the GStreamer Library Reference for the current implementation details of GstElement and GstPlugin. Pads Pads are used to negotiate links and data flow between elements in GStreamer. A pad can be viewed as a place or port on an element where links may be made with other elements, and through which data can flow to or from those elements. Pads have specific data handling capabilities: A pad can restrict the type of data that flows through it. Links are only allowed between two pads when the allowed data types of the two pads are compatible. An analogy may be helpful here. A pad is similar to a plug or jack on a physical device. Consider, for example, a home theater system consisting of an amplifier, a DVD player, and a (silent) video projector. Linking the DVD player to the amplifier is allowed because both devices have audio jacks, and linking the projector to the DVD player is allowed because both devices have compatible video jacks. Links between the projector and the amplifier may not be made because the projector and amplifier have different types of jacks. Pads in GStreamer serve the same purpose as the jacks in the home theater system. For the most part, all data in GStreamer flows one way through a link between elements. Data flows out of one element through one or more source pads, and elements accept incoming data through one or more sink pads. Source and sink elements have only source and sink pads, respectively. See the GStreamer Library Reference for the current implementation details of a GstPad. Data, Buffers and Events All streams of data in GStreamer are chopped up into chunks that are passed from a source pad on one element to a sink pad on another element. Data are structures used to hold these chunks of data. Data contains the following important types: An exact type indicating what type of data (control, content, ...) this Data is. A reference count indicating the number of elements currently holding a reference to the buffer. When the buffer reference count falls to zero, the buffer will be unlinked, and its memory will be freed in some sense (see below for more details). There are two types of data defined: events (control) and buffers (content). Buffers may contain any sort of data that the two linked pads know how to handle. Normally, a buffer contains a chunk of some sort of audio or video data that flows from one element to another. Buffers also contain metadata describing the buffer's contents. Some of the important types of metadata are: A pointer to the buffer's data. An integer indicating the size of the buffer's data. A timestamp indicating the preferred display timestamp of the content in the buffer. Events contain information on the state of the stream flowing between the two linked pads. Events will only be sent if the element explicitely supports them, else the core will (try to) handle the events automatically. Events are used to indicate, for example, a clock discontinuity, the end of a media stream or that the cache should be flushed. Events may contain several of the following items: A subtype indicating the type of the contained event. The other contents of the event depend on the specific event type. Events will be discussed extensively in . Until then, the only event that will be used is the EOS event, which is used to indicate the end-of-stream (usually end-of-file). See the GStreamer Library Reference for the current implementation details of a GstData, GstBuffer and GstEvent. Buffer Allocation Buffers are able to store chunks of memory of several different types. The most generic type of buffer contains memory allocated by malloc(). Such buffers, although convenient, are not always very fast, since data often needs to be specifically copied into the buffer. Many specialized elements create buffers that point to special memory. For example, the filesrc element usually maps a file into the address space of the application (using mmap()), and creates buffers that point into that address range. These buffers created by filesrc act exactly like generic buffers, except that they are read-only. The buffer freeing code automatically determines the correct method of freeing the underlying memory. Downstream elements that recieve these kinds of buffers do not need to do anything special to handle or unreference it. Another way an element might get specialized buffers is to request them from a downstream peer. These are called downstream-allocated buffers. Elements can ask a peer connected to a source pad to create an empty buffer of a given size. If a downstream element is able to create a special buffer of the correct size, it will do so. Otherwise GStreamer will automatically create a generic buffer instead. The element that requested the buffer can then copy data into the buffer, and push the buffer to the source pad it was allocated from. Many sink elements have accelerated methods for copying data to hardware, or have direct access to hardware. It is common for these elements to be able to create downstream-allocated buffers for their upstream peers. One such example is ximagesink. It creates buffers that contain XImages. Thus, when an upstream peer copies data into the buffer, it is copying directly into the XImage, enabling ximagesink to draw the image directly to the screen instead of having to copy data into an XImage first. Filter elements often have the opportunity to either work on a buffer in-place, or work while copying from a source buffer to a destination buffer. It is optimal to implement both algorithms, since the GStreamer framework can choose the fastest algorithm as appropriate. Naturally, this only makes sense for strict filters -- elements that have exactly the same format on source and sink pads. Mimetypes and Properties GStreamer uses a type system to ensure that the data passed between elements is in a recognized format. The type system is also important for ensuring that the parameters required to fully specify a format match up correctly when linking pads between elements. Each link that is made between elements has a specified type and optionally a set of properties. The Basic Types GStreamer already supports many basic media types. Following is a table of a few of the the basic types used for buffers in GStreamer. The table contains the name ("mime type") and a description of the type, the properties associated with the type, and the meaning of each property. A full list of supported types is included in . Table of Basic TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Descriptionaudio/* All audio types rateintegergreater than 0 The sample rate of the data, in samples (per channel) per second. channelsintegergreater than 0 The number of channels of audio data. audio/x-raw-int Unstructured and uncompressed raw integer audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). signedbooleanTRUE or FALSE Whether the values of the integer samples are signed or not. Signed samples use one bit to indicate sign (negative or positive) of the value. Unsigned samples are always positive. widthintegergreater than 0 Number of bits allocated per sample. depthintegergreater than 0 The number of bits used per sample. This must be less than or equal to the width: If the depth is less than the width, the low bits are assumed to be the ones used. For example, a width of 32 and a depth of 24 means that each sample is stored in a 32 bit word, but only the low 24 bits are actually used. audio/mpeg Audio data compressed using the MPEG audio encoding scheme. mpegversioninteger1, 2 or 4 The MPEG-version used for encoding the data. The value 1 refers to MPEG-1, -2 and -2.5 layer 1, 2 or 3. The values 2 and 4 refer to the MPEG-AAC audio encoding schemes. framedboolean0 or 1 A true value indicates that each buffer contains exactly one frame. A false value indicates that frames and buffers do not necessarily match up. layerinteger1, 2, or 3 The compression scheme layer used to compress the data (only if mpegversion=1). bitrateintegergreater than 0 The bitrate, in bits per second. For VBR (variable bitrate) MPEG data, this is the average bitrate. audio/x-vorbisVorbis audio data There are currently no specific properties defined for this type. Building a Plugin You are now ready to learn how to build a plugin. In this part of the guide, you will learn how to apply basic GStreamer programming concepts to write a simple plugin. The previous parts of the guide have contained no explicit example code, perhaps making things a bit abstract and difficult to understand. In contrast, this section will present both applications and code by following the development of an example audio filter plugin called ExampleFilter. The example filter element will begin with a single input pad and a single output pad. The filter will, at first, simply pass media and event data from its sink pad to its source pad without modification. But by the end of this part of the guide, you will learn to add some more interesting functionality, including properties and signal handlers. And after reading the next part of the guide, , you will be able to add even more functionality to your plugins. The example code used in this part of the guide can be found in examples/pwg/examplefilter/ in your GStreamer directory. Constructing the Boilerplate In this chapter you will learn how to construct the bare minimum code for a new plugin. Starting from ground zero, you will see how to get the GStreamer template source. Then you will learn how to use a few basic tools to copy and modify a template plugin to create a new plugin. If you follow the examples here, then by the end of this chapter you will have a functional audio filter plugin that you can compile and use in GStreamer applications. Getting the GStreamer Plugin Templates There are currently two ways to develop a new plugin for GStreamer: You can write the entire plugin by hand, or you can copy an existing plugin template and write the plugin code you need. The second method is by far the simpler of the two, so the first method will not even be described here. (Errm, that is, it is left as an exercise to the reader.) The first step is to check out a copy of the gst-template CVS module to get an important tool and the source code template for a basic GStreamer plugin. To check out the gst-template module, make sure you are connected to the internet, and type the following commands at a command console: shell $ cvs -d:pserver:anoncvs@cvs.freedesktop.org/cvs/gstreamer login Logging in to :pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer CVS password: [ENTER] shell $ cvs -z3 -d:pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer co gst-template U gst-template/README U gst-template/gst-app/AUTHORS U gst-template/gst-app/ChangeLog U gst-template/gst-app/Makefile.am U gst-template/gst-app/NEWS U gst-template/gst-app/README U gst-template/gst-app/autogen.sh U gst-template/gst-app/configure.ac U gst-template/gst-app/src/Makefile.am ... After the first command, you will have to press ENTER to log in to the CVS server. (You might have to log in twice.) The second command will check out a series of files and directories into ./gst-template. The template you will be using is in ./gst-template/gst-plugin/ directory. You should look over the files in that directory to get a general idea of the structure of a source tree for a plugin. Using the Project Stamp The first thing to do when making a new element is to specify some basic details about it: what its name is, who wrote it, what version number it is, etc. We also need to define an object to represent the element and to store the data the element needs. These details are collectively known as the boilerplate. The standard way of defining the boilerplate is simply to write some code, and fill in some structures. As mentioned in the previous section, the easiest way to do this is to copy a template and add functionality according to your needs. To help you do so, there are some tools in the ./gst-plugins/tools/ directory. One tool, gst-quick-stamp, is a quick command line tool. The other, gst-project-stamp, is a full GNOME druid application that takes you through the steps of creating a new project (either a plugin or an application). To use pluginstamp.sh, first open up a terminal window. Change to the gst-template directory, and then run the pluginstamp.sh command. The arguments to the pluginstamp.sh are: the name of the plugin, and the directory that should hold a new subdirectory for the source tree of the plugin. Note that capitalization is important for the name of the plugin. Under some operating systems, capitalization is also important when specifying directory names. For example, the following commands create the ExampleFilter plugin based on the plugin template and put the output files in a new directory called ~/src/examplefilter/: shell $ cd gst-template shell $ tools/pluginstamp.sh ExampleFilter ~/src Examining the Basic Code First we will examine the code you would be likely to place in a header file (although since the interface to the code is entirely defined by the plugin system, and doesn't depend on reading a header file, this is not crucial.) The code here can be found in examples/pwg/examplefilter/boiler/gstexamplefilter.h. Example Plugin Header File /* Definition of structure storing data for this element. */ typedef struct _GstExample GstExample; struct _GstExample { GstElement element; GstPad *sinkpad, *srcpad; gboolean silent; }; /* Standard definition defining a class for this element. */ typedef struct _GstExampleClass GstExampleClass; struct _GstExampleClass { GstElementClass parent_class; }; /* Standard macros for defining types for this element. */ #define GST_TYPE_EXAMPLE \ (gst_example_get_type()) #define GST_EXAMPLE(obj) \ (G_TYPE_CHECK_CAST((obj),GST_TYPE_EXAMPLE,GstExample)) #define GST_EXAMPLE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EXAMPLE,GstExample)) #define GST_IS_EXAMPLE(obj) \ (G_TYPE_CHECK_TYPE((obj),GST_TYPE_EXAMPLE)) #define GST_IS_EXAMPLE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE)) /* Standard function returning type information. */ GType gst_example_get_type (void); GstElementDetails The GstElementDetails structure gives a hierarchical type for the element, a human-readable description of the element, as well as author and version data. The entries are: A long, english, name for the element. The type of the element, as a hierarchy. The hierarchy is defined by specifying the top level category, followed by a "/", followed by the next level category, etc. The type should be defined according to the guidelines elsewhere in this document. (FIXME: write the guidelines, and give a better reference to them) A brief description of the purpose of the element. The name of the author of the element, optionally followed by a contact email address in angle brackets. For example: static GstElementDetails example_details = { "An example plugin", "Example/FirstExample", "Shows the basic structure of a plugin", "your name <your.name@your.isp>" }; The element details are registered with the plugin during the _base_init () function, which is part of the GObject system. The _base_init () function should be set for this GObject in the function where you register the type with Glib. static void gst_my_filter_base_init (GstMyFilterClass *klass) { static GstElementDetails my_filter_details = { [..] }; GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] gst_element_class_set_details (element_class, &my_filter_details); } GstStaticPadTemplate A GstStaticPadTemplate is a description of a pad that the element will (or might) create and use. It contains: A short name for the pad.Pad direction. Existence property. This indicates whether the pad exists always (an always pad), only in some cases (a sometimes pad) or only if the application requested such a pad (a request pad). Supported types by this element (capabilities). For example: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); Those pad templates are registered during the _base_init () function. Pads are created from these templates in the element's _init () function using gst_pad_new_from_template (). The template can be retrieved from the element class using gst_element_class_get_pad_template (). See below for more details on this. In order to create a new pad from this template using gst_pad_new_from_template (), you will need to declare the pad template as a global variable. More on this subject in . static GstStaticPadTemplate sink_factory = [..], src_factory = [..]; static void gst_my_filter_base_init (GstMyFilterClass *klass) { [..] GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory)); [..] } The last argument in a template is its type or list of supported types. In this example, we use 'ANY', which means that this element will accept all input. In real-life situations, you would set a mimetype and optionally a set of properties to make sure that only supported input will come in. This representation should be a string that starts with a mimetype, then a set of comma-separates properties with their supported values. In case of an audio filter that supports raw integer 16-bit audio, mono or stereo at any samplerate, the correct template would look like this: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ( "audio/x-raw-int, " "width = (int) 16, " "depth = (int) 16, " "endianness = (int) BYTE_ORDER, " "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]" ) ); Values surrounded by curly brackets ({ and }) are lists, values surrounded by square brackets ([ and ]) are ranges. Multiple sets of types are supported too, and should be separated by a semicolon (;). Later, in the chapter on pads, we will see how to use types to know the exact format of a stream: . Constructor Functions Each element has three functions which are used for construction of an element. These are the _base_init() function which is meant to initialize class and child class properties during each new child class creation; the _class_init() function, which is used to initialise the class only once (specifying what signals, arguments and virtual functions the class has and setting up global state); and the _init() function, which is used to initialise a specific instance of this type. The plugin_init function Once we have written code defining all the parts of the plugin, we need to write the plugin_init() function. This is a special function, which is called as soon as the plugin is loaded, and should return TRUE or FALSE depending on whether it loaded initialized any dependencies correctly. Also, in this function, any supported element type in the plugin should be registered. static gboolean plugin_init (GstPlugin *plugin) { return gst_element_register (plugin, "my_filter", GST_RANK_NONE, GST_TYPE_MY_FILTER); } GST_PLUGIN_DEFINE ( GST_VERSION_MAJOR, GST_VERSION_MINOR, "my_filter", "My filter plugin", plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/" ) Note that the information returned by the plugin_init() function will be cached in a central registry. For this reason, it is important that the same information is always returned by the function: for example, it must not make element factories available based on runtime conditions. If an element can only work in certain conditions (for example, if the soundcard is not being used by some other process) this must be reflected by the element being unable to enter the READY state if unavailable, rather than the plugin attempting to deny existence of the plugin. Specifying the pads As explained before, pads are the port through which data goes in and out of your element, and that makes them a very important item in the process of element creation. In the boilerplate code, we have seen how static pad templates take care of registering pad templates with the element class. Here, we will see how to create actual elements, use _link () and _getcaps () functions to let other elements know their capabilities and how to register functions to let data flow through the element. In the element _init () function, you create the pad from the pad template that has been registered with the element class in the _base_init () function. After creating the pad, you have to set a _link () function pointer and a _getcaps () function pointer. Optionally, you can set a _chain () function pointer (on sink pads in filter and sink elements) through which data will come in to the element, or (on source pads in source elements) a _get () function pointer through which data will be pulled from the element. After that, you have to register the pad with the element. This happens like this: static GstPadLinkReturn gst_my_filter_link (GstPad *pad, const GstCaps *caps); static GstCaps * gst_my_filter_getcaps (GstPad *pad); static void gst_my_filter_chain (GstPad *pad, GstData *data); static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); /* pad through which data comes in to the element */ filter->sinkpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink"); gst_pad_set_link_function (filter->sinkpad, gst_my_filter_link); gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps); gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain); gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); /* pad through which data goes out of the element */ filter->srcpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "src"), "src"); gst_pad_set_link_function (filter->srcpad, gst_my_filter_link); gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps); gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); [..] } The link function The _link () is called during caps negotiation. This is the process where the linked pads decide on the streamtype that will transfer between them. A full list of type-definitions can be found in . A _link () receives a pointer to a GstCaps struct that defines the proposed streamtype, and can respond with either yes (GST_PAD_LINK_OK), no (GST_PAD_LINK_REFUSED) or don't know yet (GST_PAD_LINK_DELAYED). If the element responds positively towards the streamtype, that type will be used on the pad. An example: static GstPadLinkReturn gst_my_filter_link (GstPad *pad, const GstCaps *caps) { GstStructure *structure = gst_caps_get_structure (caps, 0); GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; GstPadLinkReturn ret; const gchar *mime; /* Since we're an audio filter, we want to handle raw audio * and from that audio type, we need to get the samplerate and * number of channels. */ mime = gst_structure_get_name (structure); if (strcmp (mime, "audio/x-raw-int") != 0) { GST_WARNING ("Wrong mimetype %s provided, we only support %s", mime, "audio/x-raw-int"); return GST_PAD_LINK_REFUSED; } /* we're a filter and don't touch the properties of the data. * That means we can set the given caps unmodified on the next * element, and use that negotiation return value as ours. */ ret = gst_pad_try_set_caps (otherpad, gst_caps_copy (caps)); if (GST_PAD_LINK_FAILED (ret)) return ret; /* Capsnego succeeded, get the stream properties for internal * usage and return success. */ gst_structure_get_int (structure, "rate", &filter->samplerate); gst_structure_get_int (structure, "channels", &filter->channels); g_print ("Caps negotiation succeeded with %d Hz @ %d channels\n", filter->samplerate, filter->channels); return ret; } In here, we check the mimetype of the provided caps. Normally, you don't need to do that in your own plugin/element, because the core does that for you. We simply use it to show how to retrieve the mimetype from a provided set of caps. Types are stored in GstStructure internally. A GstCaps is nothing more than a small wrapper for 0 or more structures/types. From the structure, you can also retrieve properties, as is shown above with the function gst_structure_get_int (). If your _link () function does not need to perform any specific operation (i.e. it will only forward caps), you can set it to gst_pad_proxy_link. This is a link forwarding function implementation provided by the core. It is useful for elements such as identity. The getcaps function The _getcaps () funtion is used to request the list of supported formats and properties from the element. In some cases, this will be equal to the formats provided by the pad template, in which case this function can be omitted. In some cases, too, it will not depend on anything inside this element, but it will rather depend on the input from another element linked to this element's sink or source pads. In that case, you can use gst_pad_proxy_getcaps as implementation, it provides getcaps forwarding in the core. However, in many cases, the format supported by this element cannot be defined externally, but is more specific than those provided by the pad template. In this case, you should use a _getcaps () function. In the case as specified below, we assume that our filter is able to resample sound, so it would be able to provide any samplerate (indifferent from the samplerate specified on the other pad) on both pads. It explains how a _getcaps () can be used to do this. static GstCaps * gst_my_filter_getcaps (GstPad *pad) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps; gint n; if (gst_caps_is_empty (othercaps)) return othercaps; /* We support *any* samplerate, indifferent from the samplerate * supported by the linked elements on both sides. */ for (i = 0; i < gst_caps_get_size (othercaps); i++) { GstStructure *structure = gst_caps_get_structure (othercaps, i); gst_structure_remove_field (structure, "rate"); } caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad)); gst_caps_free (othercaps); return caps; } Explicit caps Obviously, many elements will not need this complex mechanism, because they are much simpler than that. They only support one format, or their format is fixed but the contents of the format depend on the stream or something else. In those cases, explicit caps are an easy way of handling caps. Explicit caps are an easy way of specifying one, fixed, supported format on a pad. Pads using explicit caps do not implement their own _getcaps () or _link () functions. When the exact format is known, an elements uses gst_pad_set_explicit_caps () to specify the exact format. This is very useful for demuxers, for example. static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); [..] filter->srcpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "src"), "src"); gst_pad_use_explicit_caps (filter->srcpad); [..] } static void gst_my_filter_somefunction (GstMyFilter *filter) { GstCaps *caps = ..; [..] gst_pad_set_explicit_caps (filter->srcpad, caps); [..] } The chain function The chain function is the function in which all data processing takes place. In the case of a simple filter, _chain () functions are mostly linear functions - so for each incoming buffer, one buffer will go out, too. Below is a very simple implementation of a chain function: static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstBuffer *buf = GST_BUFFER (data); if (!filter->silent) g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); } Obviously, the above doesn't do much useful. Instead of printing that the data is in, you would normally process the data there. Remember, however, that buffers are not always writable. In more advanced elements (the ones that do event processing), the incoming data might not even be a buffer. static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstBuffer *buf, *outbuf; if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (pad, event); break; } return; } buf = GST_BUFFER (data); outbuf = gst_my_filter_process_data (buf); gst_buffer_unref (buf); if (!outbuf) { /* something went wrong - signal an error */ gst_element_error (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL)); return; } gst_pad_push (filter->srcpad, GST_DATA (outbuf)); } In some cases, it might be useful for an element to have control over the input data rate, too. In that case, you probably want to write a so-called loop-based element. Source elements (with only source pads) can also be get-based elements. These concepts will be explained in the advanced section of this guide, and in the section that specifically discusses source pads. What are states? A state describes whether the element instance is initialized, whether it is ready to transfer data and whether it is currently handling data. There are four states defined in GStreamer: GST_STATE_NULL, GST_STATE_READY, GST_STATE_PAUSED and GST_STATE_PLAYING. GST_STATE_NULL (from now on referred to as NULL) is the default state of an element. In this state, it has not allocated any runtime resources, it has not loaded any runtime libraries and it can obviously not handle data. GST_STATE_READY (from now on referred to as READY) is the next state that an element can be in. In the READY state, an element has all default resources (runtime-libraries, runtime-memory) allocated. However, it has not yet allocated or defined anything that is stream-specific. When going from NULL to READY state (GST_STATE_NULL_TO_READY), an element should allocate any non-stream-specific resources and should load runtime-loadable libraries (if any). When going the other way around (from READY to NULL, GST_STATE_READY_TO_NULL), an element should unload these libraries and free all allocated resources. Examples of such resources are hardware devices. Note that files are generally streams, and these should thus be considered as stream-specific resources; therefore, they should not be allocated in this state. GST_STATE_PAUSED (from now on referred to as PAUSED) is a state in which an element is by all means able to handle data; the only 'but' here is that it doesn't actually handle any data. When going from the READY state into the PAUSED state (GST_STATE_READY_TO_PAUSED), the element will usually not do anything at all: all stream-specific info is generally handled in the _link (), which is called during caps negotiation. Exceptions to this rule are, for example, files: these are considered stream-specific data (since one file is one stream), and should thus be opened in this state change. When going from the PAUSED back to READY (GST_STATE_PAUSED_TO_READY), all stream-specific data should be discarded. GST_STATE_PLAYING (from now on referred to as PLAYING) is the highest state that an element can be in. It is similar to PAUSED, except that now, data is actually passing over the pipeline. The transition from PAUSED to PLAYING (GST_STATE_PAUSED_TO_PLAYING) should be as small as possible and would ideally cause no delay at all. The same goes for the reverse transition (GST_STATE_PLAYING_TO_PAUSED). Managing filter state An element can be notified of state changes through a virtual function pointer. Inside this function, the element can initialize any sort of specific data needed by the element, and it can optionally fail to go from one state to another. Do not g_assert for unhandled state changes; this is taken care of by the GstElement base class. static GstElementStateReturn gst_my_filter_change_state (GstElement *element); static void gst_my_filter_class_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); element_class->change_state = gst_my_filter_change_state; } static GstElementStateReturn gst_my_filter_change_state (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: if (!gst_my_filter_allocate_memory (filter)) return GST_STATE_FAILURE; break; case GST_STATE_READY_TO_NULL: gst_my_filter_free_memory (filter); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } Adding Arguments The primary and most important way of controlling how an element behaves, is through GObject properties. GObject properties are defined in the _class_init () function. The element optionally implements a _get_property () and a _set_property () function. These functions will be notified if an application changes or requests the value of a property, and can then fill in the value or take action required for that property to change value internally. /* properties */ enum { ARG_0, ARG_SILENT /* FILL ME */ }; static void gst_my_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_my_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gst_my_filter_class_init (GstMyFilterClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /* define properties */ g_object_class_install_property (object_class, ARG_SILENT, g_param_spec_boolean ("silent", "Silent", "Whether to be very verbose or not", FALSE, G_PARAM_READWRITE)); /* define virtual function pointers */ object_class->set_property = gst_my_filter_set_property; object_class->get_property = gst_my_filter_get_property; } static void gst_my_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (object); switch (prop_id) { case ARG_SILENT: filter->silent = g_value_get_boolean (value); g_print ("Silent argument was changed to %s\n", filter->silent ? "true" : "false"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_my_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (object); switch (prop_id) { case ARG_SILENT: g_value_set_boolean (value, filter->silent); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } The above is a very simple example of how arguments are used. Graphical applications - for example GStreamer Editor - will use these properties and will display a user-controlleable widget with which these properties can be changed. This means that - for the property to be as user-friendly as possible - you should be as exact as possible in the definition of the property. Not only in defining ranges in between which valid properties can be located (for integers, floats, etc.), but also in using very descriptive (better yet: internationalized) strings in the definition of the property, and if possible using enums and flags instead of integers. The GObject documentation describes these in a very complete way, but below, we'll give a short example of where this is useful. Note that using integers here would probably completely confuse the user, because they make no sense in this context. The example is stolen from videotestsrc. typedef enum { GST_VIDEOTESTSRC_SMPTE, GST_VIDEOTESTSRC_SNOW, GST_VIDEOTESTSRC_BLACK } GstVideotestsrcPattern; [..] #define GST_TYPE_VIDEOTESTSRC_PATTERN (gst_videotestsrc_pattern_get_type ()) static GType gst_videotestsrc_pattern_get_type (void) { static GType videotestsrc_pattern_type = 0; if (!videotestsrc_pattern_type) { static GEnumValue pattern_types[] = { { GST_VIDEOTESTSRC_SMPTE, "smpte", "SMPTE 100% color bars" }, { GST_VIDEOTESTSRC_SNOW, "snow", "Random (television snow)" }, { GST_VIDEOTESTSRC_BLACK, "black", "0% Black" }, { 0, NULL, NULL }, }; videotestsrc_pattern_type = g_enum_register_static ("GstVideotestsrcPattern", pattern_types); } return videotestsrc_pattern_type; } [..] static void gst_videotestsrc_class_init (GstvideotestsrcClass *klass) { [..] g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TYPE, g_param_spec_enum ("pattern", "Pattern", "Type of test pattern to generate", GST_TYPE_VIDEOTESTSRC_PATTERN, 1, G_PARAM_READWRITE)); [..] } Signals GObject signals can be used to notify applications of events specific to this object. Note, however, that the application needs to be aware of signals and their meaning, so if you're looking for a generic way for application-element interaction, signals are probably not what you're looking for. In many cases, however, signals can be very useful. See the GObject documentation for all internals about signals. Building a Test Application Often, you will want to test your newly written plugin in an as small setting as possible. Usually, gst-launch is a good first step at testing a plugin. However, you will often need more testing features than gst-launch can provide, such as seeking, events, interactivity and more. Writing your own small testing program is the easiest way to accomplish this. This section explains - in a few words - how to do that. For a complete application development guide, see the Application Development Manual. At the start, you need to initialize the GStreamer core library by calling gst_init (). You can alternatively call gst_init_with_popt_tables (), which will return a pointer to popt tables. You can then use libpopt to handle the given argument table, and this will finish the GStreamer intialization. You can create elements using gst_element_factory_make (), where the first argument is the element type that you want to create, and the second argument is a free-form name. The example at the end uses a simple filesource - decoder - soundcard output pipeline, but you can use specific debugging elements if that's necessary. For example, an identity element can be used in the middle of the pipeline to act as a data-to-application transmitter. This can be used to check the data for misbehaviours or correctness in your test application. Also, you can use a fakesink element at the end of the pipeline to dump your data to the stdout (in order to do this, set the dump property to TRUE). Lastly, you can use the efence element (indeed, an eletric fence memory debugger wrapper element) to check for memory errors. During linking, your test application can use fixation or filtered caps as a way to drive a specific type of data to or from your element. This is a very simple and effective way of checking multiple types of input and output in your element. Running the pipeline happens through the gst_bin_iterate () function. Note that during running, you should connect to at least the error and eos signals on the pipeline and/or your plugin/element to check for correct handling of this. Also, you should add events into the pipeline and make sure your plugin handles these correctly (with respect to clocking, internal caching, etc.). Never forget to clean up memory in your plugin or your test application. When going to the NULL state, your element should clean up allocated memory and caches. Also, it should close down any references held to possible support libraries. Your application should unref () the pipeline and make sure it doesn't crash. #include <gst/gst.h> gint main (gint arcg, gchar *argv[]) { GstElement *pipeline, *filesrc, *decoder, *filter, *sink; /* initialization */ gst_init (&argc, &argv); /* create elements */ pipeline = gst_pipeline_new ("my_pipeline"); filesrc = gst_element_factory_make ("filesrc", "my_filesource"); decoder = gst_element_factory_make ("mad", "my_decoder"); filter = gst_element_factory_make ("my_filter", "my_filter"); sink = gst_element_factory_make ("osssink", "audiosink"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); /* link everything together */ gst_element_link_many (filesrc, decoder, filter, sink, NULL); gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, filter, sink, NULL); /* run */ gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Creating a Filter with a Filter Factory A plan for the future is to create a FilterFactory, to make the process of making a new filter a simple process of specifying a few details, and writing a small amount of code to perform the actual data processing. Ideally, a FilterFactory would perform the tasks of boilerplate creation, code functionality implementation, and filter registration. Unfortunately, this has not yet been implemented. Even when someone eventually does write a FilterFactory, this element will not be able to cover all the possibilities available for filter writing. Thus, some plugins will always need to be manually coded and registered. Here is a rough outline of what is planned: You run the FilterFactory and give the factory a list of appropriate function pointers and data structures to define a filter. With a reasonable measure of preprocessor magic, you just need to provide a name for the filter and definitions of the functions and data structures desired. Then you call a macro from within plugin_init() that registers the new filter. All the fluff that goes into the definition of a filter is thus be hidden from view. Advanced Filter Concepts By now, you should be able to create basic filter elements that can receive and send data. This is the simple model that GStreamer stands for. But GStreamer can do much more than only this! In this chapter, various advanced topics will be discussed, such as scheduling, special pad types, clocking, events, interfaces, tagging and more. These topics are the sugar that makes GStreamer so easy to use for applications. How scheduling works Scheduling is, in short, a method for making sure that every element gets called once in a while to process data and prepare data for the next element. Likewise, a kernel has a scheduler to for processes, and your brain is a very complex scheduler too in a way. Randomly calling elements' chain functions won't bring us far, however, so you'll understand that the schedulers in GStreamer are a bit more complex than this. However, as a start, it's a nice picture. GStreamer currently provides two schedulers: a basic scheduler and an optimal scheduler. As the name says, the basic scheduler (basic) is an unoptimized, but very complete and simple scheduler. The optimal scheduler (opt), on the other hand, is optimized for media processing, but therefore also more complex. Note that schedulers only operate on one thread. If your pipeline contains multiple threads, each thread will run with a separate scheduler. That is the reason why two elements running in different threads need a queue-like element (a DECOUPLED element) in between them. The Basic Scheduler The basic scheduler assumes that each element is its own process. We don't use UNIX processes or POSIX threads for this, however; instead, we use so-called co-threads. Co-threads are threads that run besides each other, but only one is active at a time. The advantage of co-threads over normal threads is that they're lightweight. The disadvantage is that UNIX or POSIX do not provide such a thing, so we need to include our own co-threads stack for this to run. The task of the scheduler here is to control which co-thread runs at what time. A well-written scheduler based on co-threads will let an element run until it outputs one piece of data. Upon pushing one piece of data to the next element, it will let the next element run, and so on. Whenever a running element requires data from the previous element, the scheduler will switch to that previous element and run that element until it has provided data for use in the next element. This method of running elements as needed has the disadvantage that a lot of data will often be queued in between two elements, as the one element has provided data but the other element hasn't actually used it yet. These storages of in-between-data are called bufpens, and they can be visualized as a light queue. Note that since every element runs in its own (co-)thread, this scheduler is rather heavy on your system for larger pipelines. The Optimal Scheduler The optimal scheduler takes advantage of the fact that several elements can be linked together in one thread, with one element controlling the other. This works as follows: in a series of chain-based elements, each element has a function that accepts one piece of data, and it calls a function that provides one piece of data to the next element. The optimal scheduler will make sure that the gst_pad_push () function of the first element directly calls the chain-function of the second element. This significantly decreases the latency in a pipeline. It takes similar advantage of other possibilities of short-cutting the data path from one element to the next. The disadvantage of the optimal scheduler is that it is not fully implemented. Also it is badly documented; for most developers, the opt scheduler is one big black box. Features that are not implemented include pad-unlinking within a group while running, pad-selecting (i.e. waiting for data to arrive on a list of pads), and it can't really cope with multi-input/-output elements (with the elements linked to each of these in-/outputs running in the same thread) right now. Some of our developers are intending to write a new scheduler, similar to the optimal scheduler (but better documented and more completely implemented). How a loopfunc works A _loop () function is a function that is called by the scheduler, but without providing data to the element. Instead, the element will become responsible for acquiring its own data, and it will still be responsible of sending data over to its source pads. This method noticeably complicates scheduling; you should only write loop-based elements when you need to. Normally, chain-based elements are preferred. Examples of elements that have to be loop-based are elements with multiple sink pads. Since the scheduler will push data into the pads as it comes (and this might not be synchronous), you will easily get asynchronous data on both pads, which means that the data that arrives on the first pad has a different display timestamp than the data arriving on the second pad at the same time. To get over these issues, you should write such elements in a loop-based form. Other elements that are easier to write in a loop-based form than in a chain-based form are demuxers and parsers. It is not required to write such elements in a loop-based form, though. Below is an example of the easiest loop-function that one can write: static void gst_my_filter_loopfunc (GstElement *element); static void gst_my_filter_init (GstMyFilter *filter) { [..] gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc); [..] } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstData *data; /* acquire data */ data = gst_pad_pull (filter->sinkpad); /* send data */ gst_pad_push (filter->srcpad, data); } Obviously, this specific example has no single advantage over a chain-based element, so you should never write such elements. However, it's a good introduction to the concept. Multi-Input Elements Elements with multiple sink pads need to take manual control over their input to assure that the input is synchronized. The following example code could (should) be used in an aggregator, i.e. an element that takes input from multiple streams and sends it out intermangled. Not really useful in practice, but a good example, again. typedef struct _GstMyFilterInputContext { gboolean eos; GstBuffer *lastbuf; } GstMyFilterInputContext; [..] static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); GstMyFilterInputContext *context; filter->sinkpad1 = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink_1"); context = g_new0 (GstMyFilterInputContext, 1); gst_pad_set_private_data (filter->sinkpad1, context); [..] filter->sinkpad2 = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink_2"); context = g_new0 (GstMyFilterInputContext, 1); gst_pad_set_private_data (filter->sinkpad2, context); [..] gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc); } [..] static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GList *padlist; GstMyFilterInputContext *first_context = NULL; /* Go over each sink pad, update the cache if needed, handle EOS * or non-responding streams and see which data we should handle * next. */ for (padlist = gst_element_get_padlist (element); padlist != NULL; padlist = g_list_next (padlist)) { GstPad *pad = GST_PAD (padlist->data); GstMyFilterInputContext *context = gst_pad_get_private_data (pad); if (GST_PAD_IS_SRC (pad)) continue; while (GST_PAD_IS_USABLE (pad) && !context->eos && !context->lastbuf) { GstData *data = gst_pad_pull (pad); if (GST_IS_EVENT (data)) { /* We handle events immediately */ GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: context->eos = TRUE; gst_event_unref (event); break; case GST_EVENT_DISCONTINUOUS: g_warning ("HELP! How do I handle this?"); /* fall-through */ default: gst_pad_event_default (pad, event); break; } } else { /* We store the buffer to handle synchronization below */ context->lastbuf = GST_BUFFER (data); } } /* synchronize streams by always using the earliest buffer */ if (context->lastbuf) { if (!first_context) { first_context = context; } else { if (GST_BUFFER_TIMESTAMP (context->lastbuf) < GST_BUFFER_TIMESTAMP (first_context->lastbuf)) first_context = context; } } } /* If we handle no data at all, we're at the end-of-stream, so * we should signal EOS. */ if (!first_context) { gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); return; } /* So we do have data! Let's forward that to our source pad. */ gst_pad_push (filter->srcpad, GST_DATA (first_context->lastbuf)); first_context->lastbuf = NULL; } Note that a loop-function is allowed to return. Better yet, a loop function has to return so the scheduler can let other elements run (this is particularly true for the optimal scheduler). Whenever the scheduler feels right, it will call the loop-function of the element again. The Bytestream Object A second type of elements that wants to be loop-based, are the so-called bytestream-elements. Until now, we've only dealt with elements that receive or pull full buffers of a random size from other elements. Often, however, it is wanted to have control over the stream at a byte-level, such as in stream parsers or demuxers. It is possible to manually pull buffers and merge them until a certain size; it is easier, however, to use bytestream, which wraps this behaviour. To use bytestream, you need to load the bytestream when your plugin is loaded; you should do this before registering the element, which you learned previously in . After that, all functions of the bytestream plugin are available in your plugin as well. #include <gst/bytestream/bytestream.h> static gboolean plugin_init (GstPlugin *plugin) { if (!gst_library_load ("gstbytestream")) return FALSE; /* and now, actually register the element */ [..] } Bytestream-using elements are usually stream parsers or demuxers. For now, we will take a parser as an example. Demuxers require some more magic that will be dealt with later in this guide: . The goal of this parser will be to parse a text-file and to push each line of text as a separate buffer over its source pad. static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); gint n, num; guint8 *data; for (n = 0; ; n++) { num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1); if (num != n + 1) { GstEvent *event = NULL; guint remaining; gst_bytestream_get_status (filter->bs, &remaining, &event); if (event) { if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)) { /* end-of-file */ gst_pad_push (filter->srcpad, GST_DATA (event)); gst_element_set_eos (element); return; } gst_event_unref (event); } /* failed to read - throw error and bail out */ gst_element_error (element, STREAM, READ, (NULL), (NULL)); return; } /* check if the last character is a newline */ if (data[n] == '\n') { GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); /* read the line of text without newline - then flush the newline */ gst_bytestream_peek_data (filter->bs, &data, n); memcpy (GST_BUFFER_DATA (buf), data, n); GST_BUFFER_DATA (buf)[n] = '\0'; gst_bytestream_flush_fast (filter->bs, n + 1); g_print ("Pushing '%s'\n", GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); return; } } } static void gst_my_filter_change_state (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_READY_TO_PAUSED: filter->bs = gst_bytestream_new (filter->sinkpad); break; case GST_STATE_PAUSED_TO_READY: gst_bytestream_destroy (filter->bs); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } In the above example, you'll notice how bytestream handles buffering of data for you. The result is that you can handle the same data multiple times. Event handling in bytestream is currently sort of wacky, but it works quite well. The one big disadvantage of bytestream is that it requires the element to be loop-based. Long-term, we hope to have a chain-based usable version of bytestream, too. Adding a second output WRITEME Modifying the test application WRITEME Types and Properties There is a very large set of possible types that may be used to pass data between elements. Indeed, each new element that is defined may use a new data format (though unless at least one other element recognises that format, it will be most likely be useless since nothing will be able to link with it). In order for types to be useful, and for systems like autopluggers to work, it is necessary that all elements agree on the type definitions, and which properties are required for each type. The GStreamer framework itself simply provides the ability to define types and parameters, but does not fix the meaning of types and parameters, and does not enforce standards on the creation of new types. This is a matter for a policy to decide, not technical systems to enforce. For now, the policy is simple: Do not create a new type if you could use one which already exists. If creating a new type, discuss it first with the other GStreamer developers, on at least one of: IRC, mailing lists. Try to ensure that the name for a new format is as unlikely to conflict with anything else created already, and is not a more generalised name than it should be. For example: "audio/compressed" would be too generalised a name to represent audio data compressed with an mp3 codec. Instead "audio/mp3" might be an appropriate name, or "audio/compressed" could exist and have a property indicating the type of compression used. Ensure that, when you do create a new type, you specify it clearly, and get it added to the list of known types so that other developers can use the type correctly when writing their elements. Building a Simple Format for Testing If you need a new format that has not yet been defined in our , you will want to have some general guidelines on mimetype naming, properties and such. A mimetype would ideally be one defined by IANA; else, it should be in the form type/x-name, where type is the sort of data this mimetype handles (audio, video, ...) and name should be something specific for this specific type. Audio and video mimetypes should try to support the general audio/video properties (see the list), and can use their own properties, too. To get an idea of what properties we think are useful, see (again) the list. Take your time to find the right set of properties for your type. There is no reason to hurry. Also, experimenting with this is generally a good idea. Experience learns that theoretically thought-out types are good, but they still need practical use to assure that they serve their needs. Make sure that your property names do not clash with similar properties used in other types. If they match, make sure they mean the same thing; properties with different types but the same names are not allowed. Typefind Functions and Autoplugging With only defining the types, we're not yet there. In order for a random data file to be recognized and played back as such, we need a way of recognizing their type out of the blue. For this purpose, typefinding was introduced. Typefinding is the process of detecting the type of a datastream. Typefinding consists of two separate parts: first, there's an unlimited number of functions that we call typefind functions, which are each able to recognize one or more types from an input stream. Then, secondly, there's a small engine which registers and calls each of those functions. This is the typefind core. On top of this typefind core, you would normally write an autoplugger, which is able to use this type detection system to dynamically build a pipeline around an input stream. Here, we will focus only on typefind functions. A typefind function ususally lives in gst-plugins/gst/typefind/gsttypefindfunctions.c, unless there's a good reason (like library dependencies) to put it elsewhere. The reason for this centralization is to decreate the number of plugins that need to be loaded in order to detect a stream's type. Below is an example that will recognize AVI files, which start with a RIFF tag, then the size of the file and then an AVI tag: static void gst_my_typefind_function (GstTypeFind *tf, gpointer data) { guint8 *data = gst_type_find_peek (tf, 0, 12); if (data && GUINT32_FROM_LE (&((guint32 *) data)[0]) == GST_MAKE_FOURCC ('R','I','F','F') && GUINT32_FROM_LE (&((guint32 *) data)[2]) == GST_MAKE_FOURCC ('A','V','I',' ')) { gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, gst_caps_new_simple ("video/x-msvideo", NULL)); } } static gboolean plugin_init (GstPlugin *plugin) { static gchar *exts[] = { "avi", NULL }; if (!gst_type_find_register (plugin, "", GST_RANK_PRIMARY, gst_my_typefind_function, exts, gst_caps_new_simple ("video/x-msvideo", NULL), NULL)) return FALSE; } Note that gst-plugins/gst/typefind/gsttypefindfunctions.c has some simplification macros to decrease the amount of code. Make good use of those if you want to submit typefinding patches with new typefind functions. Autoplugging will be discussed in great detail in the chapter called . List of Defined Types Below is a list of all the defined types in GStreamer. They are split up in separate tables for audio, video, container, subtitle and other types, for the sake of readability. Below each table might follow a list of notes that apply to that table. In the definition of each type, we try to follow the types and rules as defined by IANA for as far as possible. Jump directly to a specific table: Note that many of the properties are not required, but rather optional properties. This means that most of these properties can be extracted from the container header, but that - in case the container header does not provide these - they can also be extracted by parsing the stream header or the stream content. The policy is that your element should provide the data that it knows about by only parsing its own content, not another element's content. Example: the AVI header provides samplerate of the contained audio stream in the header. MPEG system streams don't. This means that an AVI stream demuxer would provide samplerate as a property for MPEG audio streams, whereas an MPEG demuxer would not. A decoder needing this data would require a stream parser in between two extract this from the header or calculate it from the stream. Table of Audio TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description All audio types. audio/* All audio types rateintegergreater than 0 The sample rate of the data, in samples (per channel) per second. channelsintegergreater than 0 The number of channels of audio data. All raw audio types. audio/x-raw-int Unstructured and uncompressed raw fixed-integer audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). signedbooleanTRUE or FALSE Whether the values of the integer samples are signed or not. Signed samples use one bit to indicate sign (negative or positive) of the value. Unsigned samples are always positive. widthintegergreater than 0 Number of bits allocated per sample. depthintegergreater than 0 The number of bits used per sample. This must be less than or equal to the width: If the depth is less than the width, the low bits are assumed to be the ones used. For example, a width of 32 and a depth of 24 means that each sample is stored in a 32 bit word, but only the low 24 bits are actually used. audio/x-raw-float Unstructured and uncompressed raw floating-point audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). widthintegergreater than 0 The amount of bits used and allocated per sample. buffer-framesintegerAny The number of frames per buffer. The reason for this property is that the element does not need to reuse buffers or use data spanned over multiple buffers, so this property - when used rightly - will decrease latency. Note that some people think that this property is very ugly, whereas others think it is vital for the use of GStreamer in professional audio applications. The special value zero is reserved and implies that size is variable between buffers. All encoded audio types. audio/x-ac3AC-3 or A52 audio streams. There are currently no specific properties defined or needed for this type. audio/x-adpcmADPCM Audio streams.layoutstring quicktime, dvi, microsoft or 4xm. The layout defines the packing of the samples in the stream. In ADPCM, most formats store multiple samples per channel together. This number of samples differs per format, hence the different layouts. On the long term, we probably want this variable to die and use something more descriptive, but this will do for now. block_aligninteger Any Chunk buffer size. audio/x-cinepakAudio as provided in a Cinepak (Quicktime) stream. There are currently no specific properties defined or needed for this type. audio/x-dvAudio as provided in a Digital Video stream. There are currently no specific properties defined or needed for this type. audio/x-flacFree Lossless Audio codec (FLAC). There are currently no specific properties defined or needed for this type. audio/x-gsmData encoded by the GSM codec. There are currently no specific properties defined or needed for this type. audio/x-alawA-Law Audio. There are currently no specific properties defined or needed for this type. audio/x-mulawMu-Law Audio. There are currently no specific properties defined or needed for this type. audio/x-maceMACE Audio (used in Quicktime).maceversioninteger3 or 6 The version of the MACE audio codec used to encode the stream. audio/mpeg Audio data compressed using the MPEG audio encoding scehem. mpegversioninteger1, 2 or 4 The MPEG-version used for encoding the data. The value 1 refers to MPEG-1, -2 and -2.5 layer 1, 2 or 3. The values 2 and 4 refer to the MPEG-AAC audio encoding schemes. framedboolean0 or 1 A true value indicates that each buffer contains exactly one frame. A false value indicates that frames and buffers do not necessarily match up. layerinteger1, 2, or 3 The compression scheme layer used to compress the data (only if mpegversion=1). bitrateintegergreater than 0 The bitrate, in bits per second. For VBR (variable bitrate) MPEG data, this is the average bitrate. audio/x-qdm2Data encoded by the QDM version 2 codec. There are currently no specific properties defined or needed for this type. audio/x-pn-realaudioRealmedia Audio data.raversioninteger1 or 2 The version of the Real Audio codec used to encode the stream. 1 stands for a 14k4 stream, 2 stands for a 28k8 stream. audio/x-speexData encoded by the Speex audio codec There are currently no specific properties defined or needed for this type. audio/x-vorbisVorbis audio data There are currently no specific properties defined or needed for this type. audio/x-wmaWindows Media Audiowmaversioninteger1,2 or 3 The version of the WMA codec used to encode the stream. audio/x-parisEnsoniq PARIS audio There are currently no specific properties defined or needed for this type. audio/x-svxAmiga IFF / SVX8 / SV16 audio There are currently no specific properties defined or needed for this type. audio/x-nistSphere NIST audio There are currently no specific properties defined or needed for this type. audio/x-vocSound Blaster VOC audio There are currently no specific properties defined or needed for this type. audio/x-ircamBerkeley/IRCAM/CARL audio There are currently no specific properties defined or needed for this type. audio/x-w64Sonic Foundry's 64 bit RIFF/WAV There are currently no specific properties defined or needed for this type. Table of Video TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description All video types. video/* All video types widthintegergreater than 0The width of the video imageheightintegergreater than 0The height of the video imageframeratedoublegreater than 0 The (average) framerate in frames per second. Note that this property does not guarantee in any way that it will actually come close to this value. If you need a fixed framerate, please use an element that provides that (such as videodrop). All raw video types. video/x-raw-yuvYUV (or Y'Cb'Cr) video format.formatfourcc YUY2, YVYU, UYVY, Y41P, IYU2, Y42B, YV12, I420, Y41B, YUV9, YVU9, Y800 The layout of the video. See FourCC definition site for references and definitions. YUY2, YVYU and UYVY are 4:2:2 packed-pixel, Y41P is 4:1:1 packed-pixel and IYU2 is 4:4:4 packed-pixel. Y42B is 4:2:2 planar, YV12 and I420 are 4:2:0 planar, Y41B is 4:1:1 planar and YUV9 and YVU9 are 4:1:0 planar. Y800 contains Y-samples only (black/white). video/x-raw-rgbRed-Green-Blue (RBG) video.bppintegergreater than 0 The number of bits allocated per pixel. This is usually 16, 24 or 32. depthintegergreater than 0 The number of bits used per pixel by the R/G/B components. This is usually 15, 16 or 24. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). For 24/32bpp, this should always be big endian because the byte order can be given in both. red_mask, green_mask and blue_maskintegerany The masks that cover all the bits used by each of the samples. The mask should be given in the endianness specified above. This means that for 24/32bpp, the masks might be opposite to host byte order (if you are working on little-endian computers). All encoded video types. video/x-3ivx3ivx video. There are currently no specific properties defined or needed for this type. video/x-divxDivX video.divxversioninteger3, 4 or 5 Version of the DivX codec used to encode the stream. video/x-dxDigital Video.systemstreambooleanFALSE Indicates that this stream is not a system container stream. video/x-ffvFFMpeg video.ffvversioninteger1 Version of the FFMpeg video codec used to encode the stream. video/x-h263H-263 video. There are currently no specific properties defined or needed for this type. video/x-h264H-264 video. There are currently no specific properties defined or needed for this type. video/x-huffyuvHuffyuv video. There are currently no specific properties defined or needed for this type. video/x-indeoIndeo video.indeoversioninteger3 Version of the Indeo codec used to encode this stream. video/x-jpegMotion-JPEG video. There are currently no specific properties defined or needed for this type. Note that video/x-jpeg only applies to Motion-JPEG pictures (YUY2 colourspace). RGB colourspace JPEG images are referred to as image/jpeg (JPEG image). video/mpegMPEG video.mpegversioninteger1, 2 or 4 Version of the MPEG codec that this stream was encoded with. Note that we have different mimetypes for 3ivx, XviD, DivX and "standard" ISO MPEG-4. This is not a good thing and we're fully aware of this. However, we do not have a solution yet. systemstreambooleanFALSE Indicates that this stream is not a system container stream. video/x-msmpegMicrosoft MPEG-4 video deviations.msmpegversioninteger41, 42 or 43 Version of the MS-MPEG-4-like codec that was used to encode this version. A value of 41 refers to MS MPEG 4.1, 42 to 4.2 and 43 to version 4.3. video/x-msvideocodecMicrosoft Video 1 (oldish codec).msvideoversioninteger1 Version of the codec - always 1. video/x-pn-realvideoRealmedia video.rmversioninteger1, 2 or 3 Version of the Real Video codec that this stream was encoded with. video/x-rleRLE animation format.layoutstring"microsoft" or "quicktime" The RLE format inside the Microsoft AVI container has a different byte layout than the RLE format inside Apple's Quicktime container; this property keeps track of the layout. depthinteger1 to 64 Bitdepth of the used palette. This means that the palette that belongs to this format defines 2^depth colors. palette_dataGstBuffer Buffer containing a color palette (in native-endian RGBA) used by this format. The buffer is of size 4*2^depth. video/x-svqSorensen Video.svqversioninteger1 or 3 Version of the Sorensen codec that the stream was encoded with. video/x-tarkinTarkin video. There are currently no specific properties defined or needed for this type. video/x-theoraTheora video. There are currently no specific properties defined or needed for this type. video/x-vp3VP-3 video. There are currently no specific properties defined or needed for this type. Note that we have different mimetypes for VP-3 and Theora, which is not necessarily a good idea. This could probably be improved. video/x-wmvWindows Media Videowmvversioninteger1,2 or 3 Version of the WMV codec that the stream was encoded with. video/x-xvidXviD video. There are currently no specific properties defined or needed for this type. All image types. image/jpegJoint Picture Expert Group Image. There are currently no specific properties defined or needed for this type. Note that image/jpeg only applies to RGB-colourspace JPEG images; YUY2-colourspace JPEG pictures are referred to as video/x-jpeg ("Motion JPEG"). image/pngPortable Network Graphics Image. There are currently no specific properties defined or needed for this type. Table of Container TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Descriptionvideo/x-ms-asfAdvanced Streaming Format (ASF). There are currently no specific properties defined or needed for this type. video/x-msvideoAVI. There are currently no specific properties defined or needed for this type. video/x-dvDigital Video.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. video/x-matroskaMatroska. There are currently no specific properties defined or needed for this type. video/mpegMotion Pictures Expert Group System Stream.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. application/oggOgg. There are currently no specific properties defined or needed for this type. video/quicktimeQuicktime. There are currently no specific properties defined or needed for this type. video/x-pn-realvideoDigital Video.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. audio/x-wavWAV. There are currently no specific properties defined or needed for this type. Table of Subtitle TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description None defined yet. Table of Other TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description None defined yet. Request and Sometimes pads Until now, we've only dealt with pads that are always available. However, there's also pads that are only being created in some cases, or only if the application requests the pad. The first is called a sometimes; the second is called a request pad. The availability of a pad (always, sometimes or request) can be seen in a pad's template. This chapter will discuss when each of the two is useful, how they are created and when they should be disposed. Sometimes pads A sometimes pad is a pad that is created under certain conditions, but not in all cases. This mostly depends on stream content: demuxers will generally parse the stream header, decide what elementary (video, audio, subtitle, etc.) streams are embedded inside the system stream, and will then create a sometimes pad for each of those elementary streams. At its own choice, it can also create more than one instance of each of those per element instance. The only limitation is that each newly created pad should have a unique name. Sometimes pads are disposed when the stream data is disposed, too (i.e. when going from PAUSED to the READY state). You should not dispose the pad on EOS, because someone might re-activate the pipeline and seek back to before the end-of-stream point. The stream should still stay valid after EOS, at least until the stream data is disposed. In any case, the element is always the owner of such a pad. The example code below will parse a text file, where the first line is a number (n). The next lines all start with a number (0 to n-1), which is the number of the source pad over which the data should be sent. 3 0: foo 1: bar 0: boo 2: bye The code to parse this file and create the dynamic sometimes pads, looks like this: typedef struct _GstMyFilter { [..] gboolean firstrun; GList *srcpadlist; } GstMyFilter; static void gst_my_filter_base_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ( "src_%02d", GST_PAD_SRC, GST_PAD_SOMETIMES, GST_STATIC_CAPS ("ANY") ); [..] gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); [..] } static void gst_my_filter_init (GstMyFilter *filter) { [..] filter->firstrun = TRUE; filter->srcpadlist = NULL; } /* * Get one line of data - without newline. */ static GstBuffer * gst_my_filter_getline (GstMyFilter *filter) { guint8 *data; gint n, num; /* max. line length is 512 characters - for safety */ for (n = 0; n < 512; n++) { num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1); if (num != n + 1) return NULL; /* newline? */ if (data[n] == '\n') { GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); gst_bytestream_peek_bytes (filter->bs, &data, n); memcpy (GST_BUFFER_DATA (buf), data, n); GST_BUFFER_DATA (buf)[n] = '\0'; gst_bytestream_flush_fast (filter->bs, n + 1); return buf; } } } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstBuffer *buf; GstPad *pad; gint num, n; /* parse header */ if (filter->firstrun) { GstElementClass *klass; GstPadTemplate *templ; gchar *padname; if (!(buf = gst_my_filter_getline (filter))) { gst_element_error (element, STREAM, READ, (NULL), ("Stream contains no header")); return; } num = atoi (GST_BUFFER_DATA (buf)); gst_buffer_unref (buf); /* for each of the streams, create a pad */ klass = GST_ELEMENT_GET_CLASS (filter); templ = gst_element_class_get_pad_template (klass, "src_%02d"); for (n = 0; n < num; n++) { padname = g_strdup_printf ("src_%02d", n); pad = gst_pad_new_from_template (templ, padname); g_free (padname); /* here, you would set _getcaps () and _link () functions */ gst_element_add_pad (element, pad); filter->srcpadlist = g_list_append (filter->srcpadlist, pad); } } /* and now, simply parse each line and push over */ if (!(buf = gst_my_filter_getline (filter))) { GstEvent *event = gst_event_new (GST_EVENT_EOS); GList *padlist; for (padlist = srcpadlist; padlist != NULL; padlist = g_list_next (padlist)) { pad = GST_PAD (padlist->data); gst_event_ref (event); gst_pad_push (pad, GST_DATA (event)); } gst_event_unref (event); gst_element_set_eos (element); return; } /* parse stream number and go beyond the ':' in the data */ num = atoi (GST_BUFFER_DATA (buf)); if (num >= 0 && num < g_list_length (filter->srcpadlist)) { pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num); /* magic buffer parsing foo */ for (n = 0; GST_BUFFER_DATA (buf)[n] != ':' && GST_BUFFER_DATA (buf)[n] != '\0'; n++) ; if (GST_BUFFER_DATA (buf)[n] != '\0') { GstBuffer *sub; /* create subbuffer that starts right past the space. The reason * that we don't just forward the data pointer is because the * pointer is no longer the start of an allocated block of memory, * but just a pointer to a position somewhere in the middle of it. * That cannot be freed upon disposal, so we'd either crash or have * a memleak. Creating a subbuffer is a simple way to solve that. */ sub = gst_buffer_create_sub (buf, n + 1, GST_BUFFER_SIZE (buf) - n - 1); gst_pad_push (pad, GST_DATA (sub)); } } gst_buffer_unref (buf); } Note that we use a lot of checks everywhere to make sure that the content in the file is valid. This has two purposes: first, the file could be erronous, in which case we prevent a crash. The second and most important reason is that - in extreme cases - the file could be used maliciously to cause undefined behaviour in the plugin, which might lead to security issues. Always assume that the file could be used to do bad things. Request pads Request pads are similar to sometimes pads, except that request are created on demand of something outside of the element rather than something inside the element. This concept is often used in muxers, where - for each elementary stream that is to be placed in the output system stream - one sink pad will be requested. It can also be used in elements with a variable number of input or outputs pads, such as the tee (multi-output), switch or aggregator (both multi-input) elements. At the time of writing this, it is unclear to me who is responsible for cleaning up the created pad and how or when that should be done. Below is a simple example of an aggregator based on request pads. static GstPad * gst_my_filter_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name); static void gst_my_filter_base_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink_%d", GST_PAD_SINK, GST_PAD_REQUEST, GST_STATIC_CAPS ("ANY") ); [..] gst_element_class_add_pad_template (klass, gst_static_pad_template_get (&sink_factory)); } static void gst_my_filter_class_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] element_class->request_new_pad = gst_my_filter_request_new_pad; } static GstPad * gst_my_filter_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name) { GstPad *pad; GstMyFilterInputContext *context; context = g_new0 (GstMyFilterInputContext, 1); pad = gst_pad_new_from_template (templ, name); gst_element_set_private_data (pad, context); /* normally, you would set _link () and _getcaps () functions here */ gst_element_add_pad (element, pad); return pad; } The _loop () function is the same as the one given previously in . Clocking When playing complex media, each sound and video sample must be played in a specific order at a specific time. For this purpose, GStreamer provides a syncrhonization mechanism. Types of time There are two kinds of time in GStreamer. Clock time is an absolute time. By contrast, element time is the relative time, usually to the start of the current media stream. The element time represents the time that should have a media sample that is being processed by the element at this time. The element time is calculated by adding an offset to the clock time. Clocks GStreamer can use different clocks. Though the system time can be used as a clock, soundcards and other devices provides a better time source. For this reason some elements provide a clock. The method get_clock is implemented in elements that provide one. As clocks return an absolute measure of time, they are not usually used directly. Instead, a reference to a clock is stored in any element that needs it, and it is used internaly by GStreamer to calculate the element time. Flow of data between elements and time Now we will see how time information travels the pipeline in different states. The pipeline starts playing. The source element typically knows the time of each sample. Sometimes it is a parser element the one that knows the time, for instance if a pipeline contains a filesrc element connected to a MPEG decoder element, the former is the one that knows the time of each sample, because the knowledge of when to play each sample is embedded in the MPEG format. In this case this element will be regarded as the source element for this discussion. First, the source element sends a discontinous event. This event carries information about the current relative time of the next sample. This relative time is arbitrary, but it must be consistent with the timestamp that will be placed in buffers. It is expected to be the relative time to the start of the media stream, or whatever makes sense in the case of each media. When receiving it, the other elements adjust their offset of the element time so that this time matches the time written in the event. Then the source element sends media samples in buffers. This element places a timestamp in each buffer saying when the sample should be played. When the buffer reachs the sink pad of the last element, this element compares the current element time with the timestamp of the buffer. If the timestamp is higher or equal it plays the buffer, otherwise it waits until the time to place the buffer arrives with gst_element_wait(). If the stream is seeked, the next samples sent will have a timestamp that is not adjusted with the element time. Therefore, the source element must send a discontinous event. Obligations of each element. Let us clarify the contract between GStreamer and each element in the pipeline. Source elements Source elements (or parsers of formats that provide notion of time, such as MPEG, as explained above) must place a timestamp in each buffer that they deliver. The origin of the time used is arbitrary, but it must match the time delivered in the discontinous event (see below). However, it is expected that the origin is the origin of the media stream. In order to initialize the element time of the rest of the pipeline, a source element must send a discontinous event before starting to play. In addition, after seeking, a discontinious event must be sent, because the timestamp of the next element does not match the element time of the rest of the pipeline. Sink elements If the element is intended to emit samples at a specific time (real time playing), the element should require a clock, and thus implement the method set_clock. In addition, before playing each sample, if the current element time is less than the timestamp in the sample, it wait until the current time arrives should call gst_element_wait() With some schedulers, gst_element_wait() blocks the pipeline. For instance, if there is one audio sink element and one video sink element, while the audio element is waiting for a sample the video element cannot play other sample. This behaviour is under discussion, and might change in a future release. See an example in Supporting Dynamic Parameters Sometimes object properties are not powerful enough to control the parameters that affect the behaviour of your element. When this is the case you can expose these parameters as Dynamic Parameters which can be manipulated by any Dynamic Parameters aware application. Throughout this section, the term dparams will be used as an abbreviation for "Dynamic Parameters". Comparing Dynamic Parameters with GObject Properties Your first exposure to dparams may be to convert an existing element from using object properties to using dparams. The following table gives an overview of the difference between these approaches. The significance of these differences should become apparent later on. Object PropertiesDynamic ParametersParameter definitionClass level at compile timeAny level at run timeGetting and settingImplemented by element subclass as functionsHandled entirely by dparams subsystemExtra objects requiredNone - all functionality is derived from base GObjectElement needs to create and store a GstDParamManager at object creationFrequency and resolution of updatesObject properties will only be updated between calls to _get, _chain or _loopdparams can be updated at any rate independent of calls to _get, _chain or _loop up to sample-level accuracyGetting Started The dparams subsystem is contained within the gstcontrol library. You need to include the header in your element's source file: #include <gst/control/control.h> Even though the gstcontrol library may be linked into the host application, you should make sure it is loaded in your plugin_init function: static gboolean plugin_init (GModule *module, GstPlugin *plugin) { ... /* load dparam support library */ if (!gst_library_load ("gstcontrol")) { gst_info ("example: could not load support library: 'gstcontrol'\n"); return FALSE; } ... } You need to store an instance of GstDParamManager in your element's struct: struct _GstExample { GstElement element; ... GstDParamManager *dpman; ... }; The GstDParamManager can be initialised in your element's init function: static void gst_example_init (GstExample *example) { ... example->dpman = gst_dpman_new ("example_dpman", GST_ELEMENT(example)); ... } Defining Parameter Specifications You can define the dparams you need anywhere within your element but will usually need to do so in only a couple of places: In the element init function, just after the call to gst_dpman_new Whenever a new pad is created so that parameters can affect data going into or out of a specific pad. An example of this would be a mixer element where a separate volume parameter is needed on every pad. There are three different ways the dparams subsystem can pass parameters into your element. Which one you use will depend on how that parameter is used within your element. Each of these methods has its own function to define a required dparam: gst_dpman_add_required_dparam_directgst_dpman_add_required_dparam_callbackgst_dpman_add_required_dparam_array These functions will return TRUE if the required dparam was added successfully. The following function will be used as an example. gboolean gst_dpman_add_required_dparam_direct (GstDParamManager *dpman, GParamSpec *param_spec, gboolean is_log, gboolean is_rate, gpointer update_data) The common parameters to these functions are: GstDParamManager *dpman the element's dparam manager GParamSpec *param_spec the param spec which defines the required dparam gboolean is_log whether this dparam value should be interpreted on a log scale (such as a frequency or a decibel value) gboolean is_rate whether this dparam value is a proportion of the sample rate. For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz. Direct Method This method is the simplest and has the lowest overhead for parameters which change less frequently than the sample rate. First you need somewhere to store the parameter - this will usually be in your element's struct. struct _GstExample { GstElement element; ... GstDParamManager *dpman; gfloat volume; ... }; Then to define the required dparam just call gst_dpman_add_required_dparam_direct and pass in the location of the parameter to change. In this case the location is &(example->volume). gst_dpman_add_required_dparam_direct ( example->dpman, g_param_spec_float("volume","Volume","Volume of the audio", 0.0, 1.0, 0.8, G_PARAM_READWRITE), FALSE, FALSE, &(example->volume) ); You can now use example->volume anywhere in your element knowing that it will always contain the correct value to use. Callback Method This should be used if the you have other values to calculate whenever a parameter changes. If you used the direct method you wouldn't know if a parameter had changed so you would have to recalculate the other values every time you needed them. By using the callback method, other values only have to be recalculated when the dparam value actually changes. The following code illustrates an instance where you might want to use the callback method. If you had a volume dparam which was represented by a gfloat number, your element may only deal with integer arithmetic. The callback could be used to calculate the integer scaler when the volume changes. First you will need somewhere to store these values. struct _GstExample { GstElement element; ... GstDParamManager *dpman; gfloat volume_f; gint volume_i; ... }; When the required dparam is defined, the callback function gst_example_update_volume and some user data (which in this case is our element instance) is passed in to the call to gst_dpman_add_required_dparam_callback. gst_dpman_add_required_dparam_callback ( example->dpman, g_param_spec_float("volume","Volume","Volume of the audio", 0.0, 1.0, 0.8, G_PARAM_READWRITE), FALSE, FALSE, gst_example_update_volume, example ); The callback function needs to conform to this signature typedef void (*GstDPMUpdateFunction) (GValue *value, gpointer data); In our example the callback function looks like this static void gst_example_update_volume(GValue *value, gpointer data) { GstExample *example = (GstExample*)data; g_return_if_fail(GST_IS_EXAMPLE(example)); example->volume_f = g_value_get_float(value); example->volume_i = example->volume_f * 8192; } Now example->volume_i can be used elsewhere and it will always contain the correct value. Array Method This method is quite different from the other two. It could be thought of as a specialised method which should only be used if you need the advantages that it provides. Instead of giving the element a single value it provides an array of values where each item in the array corresponds to a sample of audio in your buffer. There are a couple of reasons why this might be useful. Certain optimisations may be possible since you can iterate over your dparams array and your buffer data together. Some dparams may be able to interpolate changing values at the sample rate. This would allow the array to contain very smoothly changing values which may be required for the stability and quality of some DSP algorithms. The array method is currently the least mature of the three methods and is not yet ready to be used in elements, but plugin writers should be aware of its existence for the future. The Data Processing Loop This is the most critical aspect of the dparams subsystem as it relates to elements. In a traditional audio processing loop, a for loop will usually iterate over each sample in the buffer, processing one sample at a time until the buffer is finished. A simplified loop with no error checking might look something like this. static void example_chain (GstPad *pad, GstBuffer *buf) { ... gfloat *float_data; int j; GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad)); int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat); float_data = (gfloat *)GST_BUFFER_DATA(buf); ... for (j = 0; j < num_samples; j++) { float_data[j] *= example->volume; } ... } To make this dparams aware, a couple of changes are needed. static void example_chain (GstPad *pad, GstBuffer *buf) { ... int j = 0; GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad)); int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat); gfloat *float_data = (gfloat *)GST_BUFFER_DATA(buf); int frame_countdown = GST_DPMAN_PREPROCESS(example->dpman, num_samples, GST_BUFFER_TIMESTAMP(buf)); ... while (GST_DPMAN_PROCESS_COUNTDOWN(example->dpman, frame_countdown, j)) { float_data[j++] *= example->volume; } ... } The biggest changes here are 2 new macros, GST_DPMAN_PREPROCESS and GST_DPMAN_PROCESS_COUNTDOWN. You will also notice that the for loop has become a while loop. GST_DPMAN_PROCESS_COUNTDOWN is called as the condition for the while loop so that any required dparams can be updated in the middle of a buffer if required. This is because one of the required behaviours of dparams is that they can be sample accurate. This means that parameters change at the exact timestamp that they are supposed to - not after the buffer has finished being processed. It may be alarming to see a macro as the condition for a while loop, but it is actually very efficient. The macro expands to the following. #define GST_DPMAN_PROCESS_COUNTDOWN(dpman, frame_countdown, frame_count) \ (frame_countdown-- || \ (frame_countdown = GST_DPMAN_PROCESS(dpman, frame_count))) So as long as frame_countdown is greater than 0, GST_DPMAN_PROCESS will not be called at all. Also in many cases, GST_DPMAN_PROCESS will do nothing and simply return 0, meaning that there is no more data in the buffer to process. The macro GST_DPMAN_PREPROCESS will do the following: Update any dparams which are due to be updated. Calculate how many samples should be processed before the next required update Return the number of samples until next update, or the number of samples in the buffer - whichever is less. In fact GST_DPMAN_PROCESS may do the same things as GST_DPMAN_PREPROCESS depending on the mode that the dparam manager is running in (see below). DParam Manager Modes A brief explanation of dparam manager modes might be useful here even though it doesn't generally affect the way your element is written. There are different ways media applications will be used which require that an element's parameters be updated in differently. These include: Timelined - all parameter changes are known in advance before the pipeline is run. Realtime low-latency - Nothing is known ahead of time about when a parameter might change. Changes need to be propagated to the element as soon as possible. When a dparam-aware application gets the dparam manager for an element, the first thing it will do is set the dparam manager mode. Current modes are "synchronous" and "asynchronous". If you are in a realtime low-latency situation then the "synchronous" mode is appropriate. During GST_DPMAN_PREPROCESS this mode will poll all dparams for required updates and propagate them. GST_DPMAN_PROCESS will do nothing in this mode. To then achieve the desired latency, the size of the buffers needs to be reduced so that the dparams will be polled for updates at the desired frequency. In a timelined situation, the "asynchronous" mode will be required. This mode hasn't actually been implemented yet but will be described anyway. The GST_DPMAN_PREPROCESS call will precalculate when and how often each dparam needs to update for the duration of the current buffer. From then on GST_DPMAN_PROCESS will propagate the calculated updates each time it is called until end of the buffer. If the application is rendering to disk in non-realtime, the render could be sped up by increasing the buffer size. In the "asynchronous" mode this could be done without affecting the sample accuracy of the parameter updates Dynamic Parameters for Video All of the explanation so far has presumed that the buffer contains audio data with many samples. Video should be regarded differently since a video buffer often contains only 1 frame. In this case some of the complexity of dparams isn't required but the other benefits still make it useful for video parameters. If a buffer only contains one frame of video, only a single call to GST_DPMAN_PREPROCESS should be required. For more than one frame per buffer, treat it the same as the audio case. MIDI WRITEME Interfaces Previously, in the chapter , we have introduced the concept of GObject properties of controlling an element's behaviour. This is very powerful, but it has two big disadvantages: first of all, it is too generic, and second, it isn't dynamic. The first disadvantage is related to the customizability of the end-user interface that will be built to control the element. Some properties are more important than others. Some integer properties are better shown in a spin-button widget, whereas others would be better represented by a slider widget. Such things are not possible because the UI has no actual meaning in the application. A UI widget that represents a bitrate property is the same as a UI widget that represents the size of a video, as long as both are of the same GParamSpec type. Another problem, is that things like parameter grouping, function grouping, or parameter coupling are not really possible. The second problem with parameters are that they are not dynamic. In many cases, the allowed values for a property are not fixed, but depend on things that can only be detected at runtime. The names of inputs for a TV card in a video4linux source element, for example, can only be retrieved from the kernel driver when we've opened the device; this only happens when the element goes into the READY state. This means that we cannot create an enum property type to show this to the user. The solution to those problems is to create very specialized types of controls for certain often-used controls. We use the concept of interfaces to achieve this. The basis of this all is the glib GTypeInterface type. For each case where we think it's useful, we've created interfaces which can be implemented by elements at their own will. We've also created a small extension to GTypeInterface (which is static itself, too) which allows us to query for interface availability based on runtime properties. This extension is called GstImplementsInterface. One important note: interfaces do not replace properties. Rather, interfaces should be built next to properties. There are two important reasons for this. First of all, properties can be saved in XML files. Second, properties can be specified on the commandline (gst-launch). How to Implement Interfaces Implementing interfaces is intiated in the _get_type () of your element. You can register one or more interfaces after having registered the type itself. Some interfaces have dependencies on other interfaces or can only be registered by certain types of elements. You will be notified of doing that wrongly when using the element: it will quit with failed assertions, which will explain what went wrong. In the case of GStreamer, the only dependency that some interfaces have is GstImplementsInterface. Per interface, we will indicate clearly when it depends on this extension. If it does, you need to register support for that interface before registering support for the interface that you're wanting to support. The example below explains how to add support for a simple interface with no further dependencies. For a small explanation on GstImplementsInterface, see the next section about the mixer interface: . static void gst_my_filter_some_interface_init (GstSomeInterface *iface); GType gst_my_filter_get_type (void) { static GType my_filter_type = 0; if (!my_filter_type) { static const GTypeInfo my_filter_info = { sizeof (GstMyFilterClass), (GBaseInitFunc) gst_my_filter_base_init, NULL, (GClassInitFunc) gst_my_filter_class_init, NULL, NULL, sizeof (GstMyFilter), 0, (GInstanceInitFunc) gst_my_filter_init }; static const GInterfaceInfo some_interface_info = { (GInterfaceInitFunc) gst_my_filter_some_interface_init, NULL, NULL }; my_filter_type = g_type_register_static (GST_TYPE_MY_FILTER, "GstMyFilter", &my_filter_info, 0); g_type_add_interface_static (my_filter_type, GST_TYPE_SOME_INTERFACE, &some_interface_info); } return my_filter_type; } static void gst_my_filter_some_interface_init (GstSomeInterface *iface) { /* here, you would set virtual function pointers in the interface */ } Mixer Interface The goal of the mixer interface is to provide a simple yet powerful API to applications for audio hardware mixer/volume control. Most soundcards have hardware mixers, where volume can be changed, they can be muted, inputs can be modified to mix their content into what will be read from the device by applications (in our case: audio source plugins). The mixer interface is the way to control those. The mixer interface can also be used for volume control in software (e.g. the volume element). The end goal of this interface is to allow development of hardware volume control applications and for the control of audio volume and input/output settings. The mixer interface requires the GstImplementsInterface interface to be implemented by the element. The example below will feature both, so it serves as an example for the GstImplementsInterface, too. In this interface, it is required to set a function pointer for the supported () function. If you don't, this function will always return FALSE (default implementation) and the mixer interface implementation will not work. For the mixer interface, the only required function is list_tracks (). All other function pointers in the mixer interface are optional, although it is strongly recommended to set function pointers for at least the get_volume () and set_volume () functions. The API reference for this interface documents the goal of each function, so we will limit ourselves to the implementation here. The following example shows a mixer implementation for a software N-to-1 element. It does not show the actual process of stream mixing, that is far too complicated for this guide. #include <gst/mixer/mixer.h> typedef struct _GstMyFilter { [..] gint volume; GList *tracks; } GstMyFilter; static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface); static void gst_my_filter_mixer_interface_init (GstMixerClass *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo implements_interface_info = { (GInterfaceInitFunc) gst_my_filter_implements_interface_init, NULL, NULL }; static const GInterfaceInfo mixer_interface_info = { (GInterfaceInitFunc) gst_my_filter_mixer_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); g_type_add_interface_static (my_filter_type, GST_TYPE_MIXER, &mixer_interface_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GstMixerTrack *track = NULL; [..] filter->volume = 100; filter->tracks = NULL; track = g_object_new (GST_TYPE_MIXER_TRACK, NULL); track->label = g_strdup ("MyTrack"); track->num_channels = 1; track->min_volume = 0; track->max_volume = 100; track->flags = GST_MIXER_TRACK_SOFTWARE; filter->tracks = g_list_append (filter->tracks, track); } static gboolean gst_my_filter_interface_supported (GstImplementsInterface *iface, GType iface_type) { g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); /* for the sake of this example, we'll always support it. However, normally, * you would check whether the device you've opened supports mixers. */ return TRUE; } static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface) { iface->supported = gst_my_filter_interface_supported; } /* * This function returns the list of support tracks (inputs, outputs) * on this element instance. Elements usually build this list during * _init () or when going from NULL to READY. */ static const GList * gst_my_filter_mixer_list_tracks (GstMixer *mixer) { GstMyFilter *filter = GST_MY_FILTER (mixer); return filter->tracks; } /* * Set volume. volumes is an array of size track->num_channels, and * each value in the array gives the wanted volume for one channel * on the track. */ static void gst_my_filter_mixer_set_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes) { GstMyFilter *filter = GST_MY_FILTER (mixer); filter->volume = volumes[0]; g_print ("Volume set to %d\n", filter->volume); } static void gst_my_filter_mixer_get_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes) { GstMyFilter *filter = GST_MY_FILTER (mixer); volumes[0] = filter->volume; } static void gst_my_filter_mixer_interface_init (GstMixerClass *iface) { /* the mixer interface requires a definition of the mixer type: * hardware or software? */ GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE; /* virtual function pointers */ iface->list_tracks = gst_my_filter_mixer_list_tracks; iface->set_volume = gst_my_filter_mixer_set_volume; iface->get_volume = gst_my_filter_mixer_get_volume; } The mixer interface is very audio-centric. However, with the software flag set, the mixer can be used to mix any kind of stream in a N-to-1 element to join (not aggregate!) streams together into one output stream. Conceptually, that's called mixing too. You can always use the element factory's category to indicate type of your element. In a software element that mixes random streams, you would not be required to implement the _get_volume () or _set_volume () functions. Rather, you would only implement the _set_record () to enable or disable tracks in the output stream. to make sure that a mixer-implementing element is of a certain type, check the element factory's category. Tuner Interface As opposed to the mixer interface, that's used to join together N streams into one output stream by mixing all streams together, the tuner interface is used in N-to-1 elements too, but instead of mixing the input streams, it will select one stream and push the data of that stream to the output stream. It will discard the data of all other streams. There is a flag that indicates whether this is a software-tuner (in which case it is a pure software implementation, with N sink pads and 1 source pad) or a hardware-tuner, in which case it only has one source pad, and the whole stream selection process is done in hardware. The software case can be used in elements such as switch. The hardware case can be used in elements with channel selection, such as video source elements (v4lsrc, v4l2src, etc.). If you need a specific element type, use the element factory's category to make sure that the element is of the type that you need. Note that the interface itself is highly analog-video-centric. This interface requires the GstImplemensInterface interface to work correctly. The following example shows how to implement the tuner interface in an element. It does not show the actual process of stream selection, that is irrelevant for this section. #include <gst/tuner/tuner.h> typedef struct _GstMyFilter { [..] gint active_input; GList *channels; } GstMyFilter; static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface); static void gst_my_filter_tuner_interface_init (GstTunerClass *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo implements_interface_info = { (GInterfaceInitFunc) gst_my_filter_implements_interface_init, NULL, NULL }; static const GInterfaceInfo tuner_interface_info = { (GInterfaceInitFunc) gst_my_filter_tuner_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); g_type_add_interface_static (my_filter_type, GST_TYPE_TUNER, &tunerr_interface_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GstTunerChannel *channel = NULL; [..] filter->active_input = 0; filter->channels = NULL; channel = g_object_new (GST_TYPE_TUNER_CHANNEL, NULL); channel->label = g_strdup ("MyChannel"); channel->flags = GST_TUNER_CHANNEL_INPUT; filter->channels = g_list_append (filter->channels, channel); } static gboolean gst_my_filter_interface_supported (GstImplementsInterface *iface, GType iface_type) { g_return_val_if_fail (iface_type == GST_TYPE_TUNER, FALSE); /* for the sake of this example, we'll always support it. However, normally, * you would check whether the device you've opened supports tuning. */ return TRUE; } static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface) { iface->supported = gst_my_filter_interface_supported; } static const GList * gst_my_filter_tuner_list_channels (GstTuner *tuner) { GstMyFilter *filter = GST_MY_FILTER (tuner); return filter->channels; } static GstTunerChannel * gst_my_filter_tuner_get_channel (GstTuner *tuner) { GstMyFilter *filter = GST_MY_FILTER (tuner); return g_list_nth_data (filter->channels, filter->active_input); } static void gst_my_filter_tuner_set_channel (GstTuner *tuner, GstTunerChannel *channel) { GstMyFilter *filter = GST_MY_FILTER (tuner); filter->active_input = g_list_index (filter->channels, channel); g_assert (filter->active_input >= 0); } static void gst_my_filter_tuner_interface_init (GstTunerClass *iface) { iface->list_channels = gst_my_filter_tuner_list_channels; iface->get_channel = gst_my_filter_tuner_get_channel; iface->set_channel = gst_my_filter_tuner_set_channel; } As said, the tuner interface is very analog video-centric. It features functions for selecting an input or output, and on inputs, it features selection of a tuning frequency if the channel supports frequency-tuning on that input. Likewise, it allows signal-strength-acquiring if the input supports that. Frequency tuning can be used for radio or cable-TV tuning. Signal-strength is an indication of the signal and can be used for visual feedback to the user or for autodetection. Next to that, it also features norm selection, which is only useful for analog video elements. Color Balance Interface WRITEME Property Probe Interface Property probing is a generic solution to the problem that properties' value lists in an enumeration are static. We've shown enumerations in . Property probing tries to accomplish a goal similar to enumeration lists: to have a limited, explicit list of allowed values for a property. There are two differences between enumeration lists and probing. Firstly, enumerations only allow strings as values; property probing works for any value type. Secondly, the contents of a probed list of allowed values may change during the life of an element. The contents of an enumeration list are static. Currently, property probing is being used for detection of devices (e.g. for OSS elements, Video4linux elements, etc.). It could - in theory - be used for any property, though. Property probing stores the list of allowed (or recommended) values in a GValueArray and returns that to the user. NULL is a valid return value, too. The process of property probing is separated over two virtual functions: one for probing the property to create a GValueArray, and one to retrieve the current GValueArray. Those two are separated because probing might take a long time (several seconds). Also, this simpliies interface implementation in elements. For the application, there are functions that wrap those two. For more information on this, have a look at the API reference for the GstPropertyProbe interface. Below is a example of property probing for the audio filter element; it will probe for allowed values for the silent property. Indeed, this value is a gboolean so it doesn't make much sense. Then again, it's only an example. #include <gst/propertyprobe/propertyprobe.h> static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo probe_interface_info = { (GInterfaceInitFunc) gst_my_filter_probe_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_PROPERTY_PROBE, &probe_interface_info); [..] } static const GList * gst_my_filter_probe_get_properties (GstPropertyProbe *probe) { GObjectClass *klass = G_OBJECT_GET_CLASS (probe); static GList *props = NULL; if (!props) { GParamSpec *pspec; pspec = g_object_class_find_property (klass, "silent"); props = g_list_append (props, pspec); } return props; } static gboolean gst_my_filter_probe_needs_probe (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { gboolean res = FALSE; switch (prop_id) { case ARG_SILENT: res = FALSE; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } return res; } static void gst_my_filter_probe_probe_property (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { switch (prop_id) { case ARG_SILENT: /* don't need to do much here... */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } } static GValueArray * gst_my_filter_get_silent_values (GstMyFilter *filter) { GValueArray *array = g_value_array_new (2); GValue value = { 0 }; g_value_init (&value, G_TYPE_BOOLEAN); /* add TRUE */ g_value_set_boolean (&value, TRUE); g_value_array_append (array, &value); /* add FALSE */ g_value_set_boolean (&value, FALSE); g_value_array_append (array, &value); g_value_unset (&value); return array; } static GValueArray * gst_my_filter_probe_get_values (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (probe); GValueArray *array = NULL; switch (prop_id) { case ARG_SILENT: array = gst_my_filter_get_silent_values (filter); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } return array; } static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface) { iface->get_properties = gst_my_filter_probe_get_properties; iface->needs_probe = gst_my_filter_probe_needs_probe; iface->probe_property = gst_my_filter_probe_probe_property; iface->get_values = gst_my_filter_probe_get_values; } You don't need to support any functions for getting or setting values. All that is handled via the standard GObject _set_property () and _get_property () functions. X Overlay Interface An X Overlay is basically a video output in a XFree86 drawable. Elements implementing this interface will draw video in a X11 window. Through this interface, applications will be proposed 2 different modes to work with a plugin implemeting it. The first mode is a passive mode where the plugin owns, creates and destroys the X11 window. The second mode is an active mode where the application handles the X11 window creation and then tell the plugin where it should output video. Let's get a bit deeper in those modes... A plugin drawing video output in a X11 window will need to have that window at one stage or another. Passive mode simply means that no window has been given to the plugin before that stage, so the plugin created the window by itself. In that case the plugin is responsible of destroying that window when it's not needed anymore and it has to tell the applications that a window has been created so that the application can use it. This is done using the have_xwindow_id signal that can be emitted from the plugin with the gst_x_overlay_got_xwindow_id method. As you probably guessed already active mode just means sending a X11 window to the plugin so that video output goes there. This is done using the gst_x_overlay_set_xwindow_id method. It is possible to switch from one mode to another at any moment, so the plugin implementing this interface has to handle all cases. There are only 2 methods that plugins writers have to implement and they most probably look like that : static void gst_my_filter_set_xwindow_id (GstXOverlay *overlay, XID xwindow_id) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); if (my_filter->window) gst_my_filter_destroy_window (my_filter->window); my_filter->window = xwindow_id; } static void gst_my_filter_get_desired_size (GstXOverlay *overlay, guint *width, guint *height) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); *width = my_filter->width; *height = my_filter->height; } static void gst_my_filter_xoverlay_init (GstXOverlayClass *iface) { iface->set_xwindow_id = gst_my_filter_set_xwindow_id; iface->get_desired_size = gst_my_filter_get_desired_size; } You will also need to use the interface methods to fire signals when needed such as in the pad link function where you will know the video geometry and maybe create the window. static MyFilterWindow * gst_my_filter_window_create (GstMyFilter *my_filter, gint width, gint height) { MyFilterWindow *window = g_new (MyFilterWindow, 1); ... gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (my_filter), window->win); } static GstPadLinkReturn gst_my_filter_sink_link (GstPad *pad, const GstCaps *caps) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); gint width, height; gboolean ret; ... ret = gst_structure_get_int (structure, "width", &width); ret &= gst_structure_get_int (structure, "height", &height); if (!ret) return GST_PAD_LINK_REFUSED; if (!my_filter->window) my_filter->window = gst_my_filter_create_window (my_filter, width, height); gst_x_overlay_got_desired_size (GST_X_OVERLAY (my_filter), width, height); ... } Navigation Interface WRITEME Tagging (Metadata and Streaminfo) Tags are pieces of information stored in a stream that are not the content itself, but they rather describe the content. Most media container formats support tagging in one way or another. Ogg uses VorbisComment for this, MP3 uses ID3, AVI and WAV use RIFF's INFO list chunk, etc. GStreamer provides a general way for elements to read tags from the stream and expose this to the user. The tags (at least the metadata) will be part of the stream inside the pipeline. The consequence of this is that transcoding of files from one format to another will automatically preserve tags, as long as the input and output format elements both support tagging. Tags are separated in two categories in GStreamer, even though applications won't notice anything of this. The first are called metadata, the second are called streaminfo. Metadata are tags that describe the non-technical parts of stream content. They can be changed without needing to re-encode the stream completely. Examples are author, title or album. The container format might still need to be re-written for the tags to fit in, though. Streaminfo, on the other hand, are tags that describe the stream contents technically. To change them, the stream needs to be re-encoded. Examples are codec or bitrate. Note that some container formats (like ID3) store various streaminfo tags as metadata in the file container, which means that they can be changed so that they don't match the content in the file anymore. Still, they are called metadata because technically, they can be changed without re-encoding the whole stream, even though that makes them invalid. Files with such metadata tags will have the same tag twice: once as metadata, once as streaminfo. A tag reading element is called TagGetter in GStreamer. A tag writer is called TagSetter. An element supporting both can be used in a tag editor for quick tag changing. Reading Tags from Streams The basic object for tags is a GstTagList . An element that is reading tags from a stream should create an empty taglist and fill this with individual tags. Empty tag lists can be created with gst_tag_list_new (). Then, the element can fill the list using gst_tag_list_add_values () . Note that an element probably reads metadata as strings, but values might not necessarily be strings. Be sure to use gst_value_transform () to make sure that your data is of the right type. After data reading, the application can be notified of the new taglist by calling gst_element_found_tags (). The tags should also be part of the datastream, so they should be pushed over all source pads. The function gst_event_new_tag () creates an event from a taglist. This can be pushed over source pads using gst_pad_push (). Simple elements with only one source pad can combine all these steps all-in-one by using the function gst_element_found_tags_for_pad (). The following example program will parse a file and parse the data as metadata/tags rather than as actual content-data. It will parse each line as name:value, where name is the type of metadata (title, author, ...) and value is the metadata value. The _getline () is the same as the one given in . static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstBuffer *buf; GstTagList *taglist = gst_tag_list_new (); /* get each line and parse as metadata */ while ((buf = gst_my_filter_getline (filter))) { gchar *line = GST_BUFFER_DATA (buf), *colon_pos, *type = NULL;a /* get the position of the ':' and go beyond it */ if (!(colon_pos = strchr (line, ':'))) goto next: /* get the string before that as type of metadata */ type = g_strndup (line, colon_pos - line); /* content is one character beyond the ':' */ colon_pos = &colon_pos[1]; if (*colon_pos == '\0') goto next; /* get the metadata category, it's value type, store it in that * type and add it to the taglist. */ if (gst_tag_exists (type)) { GValue from = { 0 }, to = { 0 }; GType to_type; to_type = gst_tag_get_type (type); g_value_init (&from, G_TYPE_STRING); g_value_set_string (&from, colon_pos); g_value_init (&to, to_type); g_value_transform (&from, &to); g_value_unset (&from); gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND, type, &to, NULL); g_value_unset (&to); } next: g_free (type); gst_buffer_unref (buf); } /* signal metadata */ gst_element_found_tags_for_pad (element, filter->srcpad, 0, taglist); gst_tag_list_free (taglist); /* send EOS */ gst_pad_send_event (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); } We currently assume the core to already know the mimetype (gst_tag_exists ()). You can add new tags to the list of known tags using gst_tag_register (). If you think the tag will be useful in more cases than just your own element, it might be a good idea to add it to gsttag.c instead. That's up to you to decide. If you want to do it in your own element, it's easiest to register the tag in one of your class init functions, preferrably _class_init (). static void gst_my_filter_class_init (GstMyFilterClass *klass) { [..] gst_tag_register ("my_tag_name", GST_TAG_FLAG_META, G_TYPE_STRING, _("my own tag"), _("a tag that is specific to my own element"), NULL); [..] } Writing Tags to Streams Tag writers are the opposite of tag readers. Tag writers only take metadata tags into account, since that's the only type of tags that have to be written into a stream. Tag writers can receive tags in three ways: internal, application and pipeline. Internal tags are tags read by the element itself, which means that the tag writer is - in that case - a tag reader, too. Application tags are tags provided to the element via the TagSetter interface (which is just a layer). Pipeline tags are tags provided to the element from within the pipeline. The element receives such tags via the GST_EVENT_TAG event, which means that tags writers should automatically be event aware. The tag writer is responsible for combining all these three into one list and writing them to the output stream. The example below will receive tags from both application and pipeline, combine them and write them to the output stream. It implements the tag setter so applications can set tags, and retrieves pipeline tags from incoming events. GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_TAG_SETTER, &tag_setter_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GST_FLAG_SET (filter, GST_ELEMENT_EVENT_AWARE); [..] } /* * Write one tag. */ static void gst_my_filter_write_tag (const GstTagList *taglist, const gchar *tagname, gpointer data) { GstMyFilter *filter = GST_MY_FILTER (data); GstBuffer *buffer; guint num_values = gst_tag_list_get_tag_size (list, tag_name), n; const GValue *from; GValue to = { 0 }; g_value_init (&to, G_TYPE_STRING); for (n = 0; n < num_values; n++) { from = gst_tag_list_get_value_index (taglist, tagname, n); g_value_transform (from, &to); buf = gst_buffer_new (); GST_BUFFER_DATA (buf) = g_strdup_printf ("%s:%s", tagname, g_value_get_string (&to)); GST_BUFFER_SIZE (buf) = strlen (GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); } g_value_unset (&to); } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstTagSetter *tagsetter = GST_TAG_SETTER (element); GstData *data; GstEvent *event; gboolean eos = FALSE; GstTagList *taglist = gst_tag_list_new (); while (!eos) { data = gst_pad_pull (filter->sinkpad); /* We're not very much interested in data right now */ if (GST_IS_BUFFER (data)) gst_buffer_unref (GST_BUFFER (data)); event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG: gst_tag_list_insert (taglist, gst_event_tag_get_list (event), GST_TAG_MERGE_PREPEND); gst_event_unref (event); break; case GST_EVENT_EOS: eos = TRUE; gst_event_unref (event); break; default: gst_pad_event_default (filter->sinkpad, event); break; } } /* merge tags with the ones retrieved from the application */ if (gst_tag_setter_get_list (tagsetter)) { gst_tag_list_insert (taglist, gst_tag_setter_get_list (tagsetter), gst_tag_setter_get_merge_mode (tagsetter)); } /* write tags */ gst_tag_list_foreach (taglist, gst_my_filter_write_tag, filter); /* signal EOS */ gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); } Note that normally, elements would not read the full stream before processing tags. Rather, they would read from each sinkpad until they've received data (since tags usually come in before the first data buffer) and process that. Events: Seeking, Navigation and More There are many different event types but only 2 ways they can travel across the pipeline: downstream or upstream. It is very important to understand how both of those methods work because if one element in the pipeline is not handling them correctly the whole event system of the pipeline is broken. We will try to explain here how these methods work and how elements are supposed to implement them. Downstream events Downstream events are received through the sink pad's dataflow. Depending if your element is loop or chain based you will receive events in your loop/chain function as a GstData with gst_pad_pull or directly in the function call arguments. So when receiving dataflow from the sink pad you have to check first if this data chunk is an event. If that's the case you check what kind of event it is to react on relevant ones and then forward others downstream using gst_pad_event_default. Here is an example for both loop and chain based elements. /* Chain based element */ static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); ... if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (pad, event); break; } return; } ... } /* Loop based element */ static void gst_my_filter_loop (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstData *data = NULL; data = gst_pad_pull (filter->sinkpad); if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (filter->sinkpad, event); break; } return; } ... } Upstream events Upstream events are generated by an element somewhere in the pipeline and sent using the gst_pad_send_event function. This function simply realizes the pad and call the default event handler of that pad. The default event handler of pads is gst_pad_event_default , it basically sends the event to the peer pad. So upstream events always arrive on the src pad of your element and are handled by the default event handler except if you override that handler to handle it yourself. There are some specific cases where you have to do that : If you have multiple sink pads in your element. In that case you will have to decide which one of the sink pads you will send the event to. If you need to handle that event locally. For example a navigation event that you will want to convert before sending it upstream. The processing you will do in that event handler does not really matter but there are important rules you have to absolutely respect because one broken element event handler is breaking the whole pipeline event handling. Here they are : Always forward events you won't handle upstream using the default gst_pad_event_default method. If you are generating some new event based on the one you received don't forget to gst_event_unref the event you received. Event handler function are supposed to return TRUE or FALSE indicating if the event has been handled or not. Never simply return TRUE/FALSE in that handler except if you really know that you have handled that event. Here is an example of correct upstream event handling for a plugin that wants to modify navigation events. static gboolean gst_my_filter_handle_src_event (GstPad *pad, GstEvent *event) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: GstEvent *new_event = gst_event_new (GST_EVENT_NAVIGATION);; /* Create a new event based on received one and then send it */ ... gst_event_unref (event); return gst_pad_event_default (pad, new_event); default: /* Falling back to default event handling for that pad */ return gst_pad_event_default (pad, event); } } All Events Together In this chapter follows a list of all defined events that are currently being used, plus how they should be used/interpreted. Events are stored in a GstEvent structure, which is simply a big C union with the types for each event in it. For the next development cycle, we intend to switch events over to GstStructure , but you don't need to worry about that too much for now. In this chapter, we will discuss the following events: End of Stream (EOS) End-of-stream events are sent if the stream that an element sends out is finished. An element receiving this event (from upstream, so it receives it on its sinkpad) will generally forward the event further downstream and set itself to EOS (gst_element_set_eos ()). gst_pad_event_default () takes care of all this, so most elements do not need to support this event. Exceptions are elements that explicitly need to close a resource down on EOS, and N-to-1 elements. Note that the stream itself is not a resource that should be closed down on EOS! Applications might seek back to a point before EOS and set the pipeline to PLAYING again. N-to-1 elements have been discussed previously in . The EOS event (GST_EVENT_EOS) has no properties, and that makes it one of the simplest events in GStreamer. It is created using gst_event_new (GST_EVENT_EOS);. Some elements support the EOS event upstream, too. This signals the element to go into EOS as soon as possible and signal the EOS event forward downstream. This is useful for elements that have no concept of end-of-stream themselves. Examples are TV card sources, audio card sources, etc. This is not (yet) part of the official specifications of this event, though. Flush The flush event is being sent downstream if all buffers and caches in the pipeline should be emptied. Queue elements will empty their internal list of buffers when they receive this event, for example. File sink elements (e.g. filesink) will flush the kernel-to-disk cache (fdatasync () or fflush ()) when they receive this event. Normally, elements receiving this event will simply just forward it, since most filter or filter-like elements don't have an internal cache of data. gst_pad_event_default () does just that, so for most elements, it is enough to forward the event using the default event handler. The flush event is created with gst_event_new (GST_EVENT_FLUSH);. Like the EOS event, it has no properties. Stream Discontinuity A discontinuity event is sent downstream to indicate a discontinuity in the data stream. This can happen because the application used the seek event to seek to a different position in the stream, but it can also be because a real-time network source temporarily lost the connection. After the connection is restored, the data stream will continue, but not at the same point where it got lost. Therefore, a discontinuity event is being sent downstream, too. Depending on the element type, the event can simply be forwarded using gst_pad_event_default (), or it should be parsed and a modified event should be sent on. The last is true for demuxers, which generally have a byte-to-time conversion concept. Their input is usually byte-based, so the incoming event will have an offset in byte units (GST_FORMAT_BYTES), too. Elements downstream, however, expect discontinuity events in time units, so that it can be used to update the pipeline clock. Therefore, demuxers and similar elements should not forward the event, but parse it, free it and send a new discontinuity event (in time units, GST_FORMAT_TIME) further downstream. The discontinuity event is created using the function gst_event_new_discontinuous (). It should set a boolean value which indicates if the discontinuity event is sent because of a new media type (this can happen if - during iteration - a new location was set on a network source or on a file source). then, it should give a list of formats and offsets in that format. The list should be terminated by 0 as format. static void my_filter_some_function (GstMyFilter *filter) { GstEvent *event; [..] event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, 0, GST_FORMAT_TIME, 0, 0); gst_pad_push (filter->srcpad, GST_DATA (event)); [..] } Elements parsing this event can use macros and functions to access the various properties. GST_EVENT_DISCONT_NEW_MEDIA (event) checks the new-media boolean value. gst_event_discont_get_value (event, format, &value) gets the offset of the new stream position in the specified format. If that format was not specified when creating the event, the function returns FALSE. Seek Request Seek events are meant to request a new stream position to elements. This new position can be set in several formats (time, bytes or units [a term indicating frames for video, samples for audio, etc.]). Seeking can be done with respect to the end-of-file, start-of-file or current position, and can happen in both upstream and downstream direction. Elements receiving seek events should, depending on the element type, either forward it (filters, decoders), change the format in which the event is given and forward it (demuxers), handle the event by changing the file pointer in their internal stream resource (file sources) or something else. Seek events are, like discontinuity events, built up using positions in specified formats (time, bytes, units). They are created using the function gst_event_new_seek (), where the first argument is the seek type (indicating with respect to which position [current, end, start] the seek should be applied, and the format in which the new position is given (time, bytes, units), and an offset which is the requested position in the specified format. static void my_filter_some_function (GstMyFilter *filter) { GstEvent *event; [..] /* seek to the start of a resource */ event = gst_event_new_seek (GST_SEEK_SET | GST_FORMAT_BYTES, 0); gst_pad_push (filter->srcpad, GST_DATA (event)); [..] } Elements parsing this event can use macros and functions to access the properties. The seek type can be retrieved using GST_EVENT_SEEK_TYPE (event). This seek type contains both the indicator of with respect to what position the seek should be applied, and the format in which the seek event is given. To get either one of these properties separately, use GST_EVENT_SEEK_FORMAT (event) or GST_EVENT_SEEK_METHOD (event). The requested position is available through GST_EVENT_SEEK_OFFSET (event), and is given in the specified format. Stream Filler The filler event is, as the name says, a filler of the stream which has no special meaning associated with itself. It is used to provide data to downstream elements and should be interpreted as a way of assuring that the normal data flow will continue further downstream. The event is especially intended for real-time MIDI source elements, which only generate data when something changes. MIDI decoders will therefore stall if nothing changes for several seconds, and therefore playback will stop. The filler event is sent downstream to assure the MIDI decoder that nothing changed, so that the normal decoding process will continue and playback will, too. Unless you intend to work with MIDI or other control-language-based data types, you don't need this event. You can mostly simply forward it with gst_pad_event_default (). The stream filler is created using gst_event_new (GST_EVENT_FILLER);. It has no properties. Interruption The interrupt event is generated by queue elements and sent downstream if a timeout occurs on the stream. The scheduler will use this event to get back in its own main loop and schedule other elements. This prevents deadlocks or a stream stall if no data is generated over a part of the pipeline for a considerable amount of time. The scheduler will process this event internally, so any normal elements do not need to generate or handle this event at all. The difference between the filler event and the interrupt event is that the filler event is a real part of a pipeline, so it will reach fellow elements, which can use it to "do nothing else than what I used to do". The interrupt event never reaches fellow elements. The interrupt event (gst_event_new (GST_EVENT_INTERRUPT);) has no properties. Navigation WRITEME Tag (metadata) Tagging events are being sent downstream to indicate the tags as parsed from the stream data. This is currently used to preserve tags during stream transcoding from one format to the other. Tags are discussed extensively in . Most elements will simply forward the event by calling gst_pad_event_default (). The tag event is created using the function gst_event_new_tag (). It requires a filled taglist as argument. Elements parsing this event can use the function gst_event_tag_get_list (event) to acquire the taglist that was parsed. Other Element Types By now, we have looked at pretty much any feature that can be embedded into a GStreamer element. However, we have limited ourselves to the simple model of a filter element. In this chapter, we will look at the specific difficulties and things to keep in mind when writing specific types of elements. We will discuss output elements (sinks), input elements (sources), 1-to-N elements, N-to-1 elements, N-to-N elements, autopluggers and managers. Some of these represent elements that don't actually exist. Rather, they represent a general concept. Writing a Source Source elements are the start of a data streaming pipeline. Source elements have no sink pads and have one or more source pads. We will focus on single-sourcepad elements here, but the concepts apply equally well to multi-sourcepad elements. This chapter will explain the essentials of source elements, which features it should implement and which it doesn't have to, and how source elements will interact with other elements in a pipeline. The get()-function Source elements have the special option of having a _get ()-function rather than a _loop ()- or _chain ()-function. A _get ()-function is called by the scheduler every time the next elements needs data. Apart from corner cases, every source element will want to be _get ()-based. static GstData * gst_my_source_get (GstPad *pad); static void gst_my_source_init (GstMySource *src) { [..] gst_pad_set_get_function (src->srcpad, gst_my_source_get); } static GstData * gst_my_source_get (GstPad *pad) { GstBuffer *buffer; buffer = gst_buffer_new (); GST_BUFFER_DATA (buf) = g_strdup ("hello pipeline!"); GST_BUFFER_SIZE (buf) = strlen (GST_BUFFER_DATA (buf)); /* terminating '/0' */ GST_BUFFER_MAZSIZE (buf) = GST_BUFFER_SIZE (buf) + 1; return GST_DATA (buffer); } Events, querying and converting One of the most important functions of source elements is to implement correct query, convert and event handling functions. Those will continuously describe the current state of the stream. Query functions can be used to get stream properties such as current position and length. This can be used by fellow elements to convert this same value into a different unit, or by appliations to provide information about the length/position of the stream to the user. Conversion functions are used to convert such values from one unit to another. Lastly, events are mostly used to seek to positions inside the stream. Any function is essentially optional, but the element should try to provide as much information as it knows. Note that elements providing an event function should also list their supported events in an _get_event_mask () function. Elements supporting query operations should list the supported operations in a _get_query_types () function. Elements supporting either conversion or query operations should also implement a _get_formats () function. An example source element could, for example, be an element that continuously generates a wave tone at 44,1 kHz, mono, 16-bit. This element will generate 44100 audio samples per second or 88,2 kB/s. This information can be used to implement such functions: static GstFormat * gst_my_source_format_list (GstPad *pad); static GstQueryType * gst_my_source_query_list (GstPad *pad); static gboolean gst_my_source_convert (GstPad *pad, GstFormat from_fmt, gint64 from_val, GstFormat *to_fmt, gint64 *to_val); static gboolean gst_my_source_query (GstPad *pad, GstQueryType type, GstFormat *to_fmt, gint64 *to_val); static void gst_my_source_init (GstMySource *src) { [..] gst_pad_set_convert_function (src->srcpad, gst_my_source_convert); gst_pad_set_formats_function (src->srcpad, gst_my_source_format_list); gst_pad_set_query_function (src->srcpad, gst_my_source_query); gst_pad_set_query_type_function (src->srcpad, gst_my_source_query_list); } /* * This function returns an enumeration of supported GstFormat * types in the query() or convert() functions. See gst/gstformat.h * for a full list. */ static GstFormat * gst_my_source_format_list (GstPad *pad) { static const GstFormat formats[] = { GST_FORMAT_TIME, GST_FORMAT_DEFAULT, /* means "audio samples" */ GST_FORMAT_BYTES, 0 }; return formats; } /* * This function returns an enumeration of the supported query() * operations. Since we generate audio internally, we only provide * an indication of how many samples we've played so far. File sources * or such elements could also provide GST_QUERY_TOTAL for the total * stream length, or other things. See gst/gstquery.h for details. */ static GstQueryType * gst_my_source_query_list (GstPad *pad) { static const GstQueryType query_types[] = { GST_QUERY_POSITION, 0, }; return query_types; } /* * And below are the logical implementations. */ static gboolean gst_my_source_convert (GstPad *pad, GstFormat from_fmt, gint64 from_val, GstFormat *to_fmt, gint64 *to_val) { gboolean res = TRUE; GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (from_fmt) { case GST_FORMAT_TIME: switch (*to_fmt) { case GST_FORMAT_TIME: /* nothing */ break; case GST_FORMAT_BYTES: *to_val = from_val / (GST_SECOND / (44100 * 2)); break; case GST_FORMAT_DEFAULT: *to_val = from_val / (GST_SECOND / 44100); break; default: res = FALSE; break; } break; case GST_FORMAT_BYTES: switch (*to_fmt) { case GST_FORMAT_TIME: *to_val = from_val * (GST_SECOND / (44100 * 2)); break; case GST_FORMAT_BYTES: /* nothing */ break; case GST_FORMAT_DEFAULT: *to_val = from_val / 2; break; default: res = FALSE; break; } break; case GST_FORMAT_DEFAULT: switch (*to_fmt) { case GST_FORMAT_TIME: *to_val = from_val * (GST_SECOND / 44100); break; case GST_FORMAT_BYTES: *to_val = from_val * 2; break; case GST_FORMAT_DEFAULT: /* nothing */ break; default: res = FALSE; break; } break; default: res = FALSE; break; } return res; } static gboolean gst_my_source_query (GstPad *pad, GstQueryType type, GstFormat *to_fmt, gint64 *to_val) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); gboolean res = TRUE; switch (type) { case GST_QUERY_POSITION: res = gst_pad_convert (pad, GST_FORMAT_BYTES, src->total_bytes, to_fmt, to_val); break; default: res = FALSE; break; } return res; } Be sure to increase src->total_bytes after each call to your _get () function. Event handling has already been explained previously in the events chapter. Time, clocking and synchronization The above example does not provide any timing info, but will suffice for elementary data sources such as a file source or network data source element. Things become slightly more complicated, but still very simple, if we create artificial video or audio data sources, such as a video test image source or an artificial audio source (e.g. sinesrc or silence). It will become more complicated if we want the element to be a realtime capture source, such as a video4linux source (for reading video frames from a TV card) or an ALSA source (for reading data from soundcards supported by an ALSA-driver). Here, we will need to make the element aware of timing and clocking. Timestamps can essentially be generated from all the information given above without any difficulty. We could add a very small amount of code to generate perfectly timestamped buffers from our _get ()-function: static void gst_my_source_init (GstMySource *src) { [..] src->total_bytes = 0; } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; GstFormat fmt = GST_FORMAT_TIME; [..] GST_BUFFER_DURATION (buf) = GST_BUFFER_SIZE (buf) * (GST_SECOND / (44100 * 2)); GST_BUFFER_TIMESTAMP (buf) = src->total_bytes * (GST_SECOND / (44100 * 2)); src->total_bytes += GST_BUFFER_SIZE (buf); return GST_DATA (buf); } static GstStateReturn gst_my_source_change_state (GstElement *element) { GstMySource *src = GST_MY_SOURCE (element); switch (GST_STATE_PENDING (element)) { case GT_STATE_PAUSED_TO_READY: src->total_bytes = 0; break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } That wasn't too hard. Now, let's assume real-time elements. Those can either have hardware-timing, in which case we can rely on backends to provide sync for us (in which case you probably want to provide a clock), or we will have to emulate that internally (e.g. to acquire sync in artificial data elements such as sinesrc). Let's first look at the second option (software sync). The first option (hardware sync + providing a clock) does not require any special code with respect to timing, and the clocking section already explained how to provide a clock. enum { ARG_0, [..] ARG_SYNC, [..] }; static void gst_my_source_class_init (GstMySourceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); [..] g_object_class_install_property (object_class, ARG_SYNC, g_param_spec_boolean ("sync", "Sync", "Synchronize to clock", FALSE, G_PARAM_READWRITE)); [..] } static void gst_my_source_init (GstMySource *src) { [..] src->sync = FALSE; } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; [..] if (src->sync) { /* wait on clock */ gst_element_wait (GST_ELEMENT (src), GST_BUFFER_TIMESTAMP (buf)); } return GST_DATA (buf); } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: g_value_set_boolean (value, src->sync); break; [..] } } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, const GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: src->sync = g_value_get_boolean (value); break; [..] } } Most of this is GObject wrapping code. The actual code to do software-sync (in the _get ()-function) is relatively small. Using special memory In some cases, it might be useful to use specially allocated memory (e.g. mmap ()'ed DMA'able memory) in your buffers, and those will require special handling when they are being dereferenced. For this, GStreamer uses the concept of buffer-free functions. Those are special functions pointers that an element can set on buffers that it created itself. The given function will be called when the buffer has been dereferenced, so that the element can clean up or re-use memory internally rather than using the default implementation (which simply calls g_free () on the data pointer). static void gst_my_source_buffer_free (GstBuffer *buf) { GstMySource *src = GST_MY_SOURCE (GST_BUFFER_PRIVATE (buf)); /* do useful things here, like re-queueing the buffer which * makes it available for DMA again. The default handler will * not free this buffer because of the GST_BUFFER_DONTFREE * flag. */ } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; [..] buf = gst_buffer_new (); GST_BUFFER_FREE_DATA_FUNC (buf) = gst_my_source_buffer_free; GST_BUFFER_PRIVATE (buf) = src; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY | GST_BUFFER_DONTFREE); [..] return GST_DATA (buf); } Note that this concept should not be used to decrease the number of calls made to functions such as g_malloc () inside your element. We have better ways of doing that elsewhere (GStreamer core, Glib, Glibc, Linux kernel, etc.). Writing a Sink Sinks are output elements that, opposite to sources, have no source pads and one or more (usually one) sink pad. They can be sound card outputs, disk writers, etc. This chapter will discuss the basic implementation of sink elements. Data processing, events, synchronization and clocks Except for corner cases, sink elements will be _chain ()-based elements. The concept of such elements has been discussed before in detail, so that will be skipped here. What is very important in sink elements, specifically in real-time audio and video sources (such as osssink or ximagesink), is event handling in the _chain ()-function, because most elements rely on EOS-handling of the sink element, and because A/V synchronization can only be perfect if the element takes this into account. How to achieve synchronization between streams depends on whether you're a clock-providing or a clock-receiving element. If you're the clock provider, you can do with time whatever you want. Correct handling would mean that you check whether the end of the previous buffer (if any) and the start of the current buffer are the same. If so, there's no gap between the two and you can continue playing right away. If there is a gap, then you'll need to wait for your clock to reach that time. How to do that depends on the element type. In the case of audio output elements, you would output silence for a while. In the case of video, you would show background color. In case of subtitles, show no subtitles at all. In the case that the provided clock and the received clock are not the same (or in the case where your element provides no clock, which is the same), you simply wait for the clock to reach the timestamp of the current buffer and then you handle the data in it. A simple data handling function would look like this: static void gst_my_sink_chain (GstPad *pad, GstData *data) { GstMySink *sink = GST_MY_SINK (gst_pad_get_parent (pad)); GstBuffer *buf; GstClockTime time; /* only needed if the element is GST_EVENT_AWARE */ if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: [ if your element provides a clock, disable (inactivate) it here ] /* pass-through */ default: /* the default handler handles discontinuities, even if your * element provides a clock! */ gst_pad_event_default (pad, event); break; } return; } buf = GST_BUFFER (data); if (GST_BUFFER_TIME_IS_VALID (buf)) time = GST_BUFFER_TIMESTAMP (buf); else time = sink->expected_next_time; /* Synchronization - the property is only useful in case the * element has the option of not syncing. So it is not useful * for hardware-sync (clock-providing) elements. */ if (sink->sync) { /* This check is only needed if you provide a clock. Else, * you can always execute the 'else' clause. */ if (sink->provided_clock == sink->received_clock) { /* GST_SECOND / 10 is 0,1 sec, it's an arbitrary value. The * casts are needed because else it'll be unsigned and we * won't detect negative values. */ if (llabs ((gint64) sink->expected_next_time - (gint64) time) > (GST_SECOND / 10)) { /* so are we ahead or behind? */ if (time > sink->expected_time) { /* we need to wait a while... In case of audio, output * silence. In case of video, output background color. * In case of subtitles, display nothing. */ [..] } else { /* Drop data. */ [..] } } } else { /* You could do more sophisticated things here, but we'll * keep it simple for the purpose of the example. */ gst_element_wait (GST_ELEMENT (sink), time); } } /* And now handle the data. */ [..] } Special memory Like source elements, sink elements can sometimes provide externally allocated (such as X-provided or DMA'able) memory to elements earlier in the pipeline, and thereby prevent the need for memcpy () for incoming data. We do this by providing a pad-allocate-buffer function. static GstBuffer * gst_my_sink_buffer_allocate (GstPad *pad, guint64 offset, guint size); static void gst_my_sink_init (GstMySink *sink) { [..] gst_pad_set_bufferalloc_function (sink->sinkpad, gst_my_sink_buffer_allocate); } static void gst_my_sink_buffer_free (GstBuffer *buf) { GstMySink *sink = GST_MY_SINK (GST_BUFFER_PRIVATE (buf)); /* Do whatever is needed here. */ [..] } static GstBuffer * gst_my_sink_buffer_allocate (GstPad *pad, guint64 offset, guint size) { GstBuffer *buf = gst_buffer_new (); /* So here it's up to you to wrap your private buffers and * return that. */ GST_BUFFER_FREE_DATA_FUNC (buf) = gst_my_sink_buffer_free; GST_BUFFER_PRIVATE (buf) = sink; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE); [..] return buf; } Writing a 1-to-N Element, Demuxer or Parser 1-to-N elements don't have much special needs or requirements that haven't been discussed already. The most important thing to take care of in 1-to-N elements (things like tee-elements or so) is to use proper buffer refcounting and caps negotiation. If those two are taken care of (see the tee element if you need example code), there's little that can go wrong. Demuxers are the 1-to-N elements that need very special care, though. They are responsible for timestamping raw, unparsed data into elementary video or audio streams, and there are many things that you can optimize or do wrong. Here, several culprits will be mentioned and common solutions will be offered. Parsers are demuxers with only one source pad. Also, they only cut the stream into buffers, they don't touch the data otherwise. Demuxer Caps Negotiation Demuxers will usually contain several elementary streams, and each of those streams' properties will be defined in a stream header at the start of the file (or, rather, stream) that you're parsing. Since those are fixed and there is no possibility to negotiate stream properties with elements earlier in the pipeline, you should always use explicit caps on demuxer source pads. This prevents a whole lot of caps negotiation or re-negotiation errors. Data processing and downstream events Data parsing, pulling this into subbuffers and sending that to the source pads of the elementary streams is the one single most important task of demuxers and parsers. Usually, an element will have a _loop () function using the bytestream object to read data. Try to have a single point of data reading from the bytestream object. In this single point, do proper event handling (in case there is any) and proper error handling in case that's needed. Make your element as fault-tolerant as possible, but do not go further than possible. Parsing versus interpreting One particular convention that GStreamer demuxers follow is that of separation of parsing and interpreting. The reason for this is maintainability, clarity and code reuse. An easy example of this is something like RIFF, which has a chunk header of 4 bytes, then a length indicator of 4 bytes and then the actual data. We write special functions to read one chunk, to peek a chunk ID and all those; that's the parsing part of the demuxer. Then, somewhere else, we like to write the main data processing function, which calls this parse function, reads one chunk and then does with the data whatever it needs to do. Some example code for RIFF-reading to illustrate the above two points: static gboolean gst_my_demuxer_peek (GstMyDemuxer *demux, guint32 *id, guint32 *size) { guint8 *data; while (gst_bytestream_peek_bytes (demux->bs, &data, 4) != 4) { guint32 remaining; GstEvent *event; gst_bytestream_get_status (demux->bs, &remaining, &event); if (event) { GstEventType type = GST_EVENT_TYPE (event); /* or maybe custom event handling, up to you - we lose reference! */ gst_pad_event_default (demux->sinkpad, event); if (type == GST_EVENT_EOS) return FALSE; } else { GST_ELEMENT_ERROR (demux, STREAM, READ, (NULL), (NULL)); return FALSE; } } *id = GUINT32_FROM_LE (((guint32 *) data)[0]); *size = GUINT32_FROM_LE (((guint32 *) data)[0]); return TRUE; } static void gst_my_demuxer_loop (GstElement *element) { GstMyDemuxer *demux = GST_MY_DEMUXER (element); guint32 id, size; if (!gst_my_demuxer_peek (demux, &id, &size)) return; switch (id) { [.. normal chunk handling ..] } } Reason for this is that event handling is now centralized in one place and the _loop () function is a lot cleaner and more readable. Those are common code practices, but since the mistake of not using such common code practices has been made too often, we explicitely mention this here. Simple seeking and indexes Sources will generally receive a seek event in the exact supported format by the element. Demuxers, however, can not seek in themselves directly, but need to convert from one unit (e.g. time) to the other (e.g. bytes) and send a new event to its sink pad. Given this, the _convert ()-function (or, more general: unit conversion) is the most important function in a demuxer. Some demuxers (AVI, Matroska) and parsers will keep an index of all chunks in a stream, firstly to improve seeking precision and secondly so they won't lose sync. Some other demuxers will seek the stream directly without index (e.g. MPEG, Ogg) - usually based on something like a cumulative bitrate - and then find the closest next chunk from their new position. The best choice depends on the format. Note that it is recommended for demuxers to implement event, conversion and query handling functions (using time units or so), in addition to the ones (usually in byte units) provided by the pipeline source element. Writing a N-to-1 Element or Muxer N-to-1 elements have been previously mentioned and discussed in both and in . The main noteworthy thing about N-to-1 elements is that they should always, without any single exception, be _loop ()-based. Apart from that, there is not much general that you need to know. We will discuss one special type of N-to-1 elements here, these being muxers. The first two of these sections apply to N-to-1 elements in general, though. The Data Loop Function As previously mentioned in , N-to-1 elements generally try to have one buffer from each sink pad and then handle the one with the earliest timestamp. There's some exceptions to this rule, we will come to those later. This only works if all streams actually continuously provide input. There might be cases where this is not true, for example subtitles (there might be no subtitle for a while), overlay images and so forth. For this purpose, there is a _select () function in GStreamer. It checks whether input is available on a (list of) pad(s). In this way, you can skip over the pads that are 'non- continuous'. /* Pad selection is currently broken, FIXME some day */ Events in the Loop Function N-to-1 elements using a cache will sometimes receive events, and it is often unclear how to handle those. For example, how do you seek to a frame in an output file (and what's the point of it anyway)? So, do discontinuity or seek events make sense, and should you use them? Discontinuities and flushes Don't do anything. They specify a discontinuity in the output, and you should continue to playback as you would otherwise. You generally do not need to put a discontinuity in the output stream in muxers; you would have to manually start adapting timestamps of output frames (if appliccable) to match the previous timescale, though. Note that the output data stream should be continuous. For other types of N-to-1-elements, it is generally fine to forward the discontinuity once it has been received from all pads. This depends on the specific element. Seeks Depends on the element. Muxers would generally not implement this, because the concept of seeking in an output stream at frame level is not very useful. Seeking at byte level can be useful, but that is more generally done by muxers on sink elements. End-of-Stream Speaks for itself. Negotiation Most container formats will have a fair amount of issues with changing content on an elementary stream. Therefore, you should not allow caps to be changed once you've started using data from them. The easiest way to achieve this is by using explicit caps, which have been explained before. However, we're going to use them in a slightly different way then what you're used to, having the core do all the work for us. The idea is that, as long as the stream/file headers have not been written yet and no data has been processed yet, a stream is allowed to renegotiate. After that point, the caps should be fixed, because we can only use a stream once. Caps may then only change within an allowed range (think MPEG, where changes in FPS are allowed), or sometimes not at all (such as AVI audio). In order to do that, we will, after data retrieval and header writing, set an explicit caps on each sink pad, that is the minimal caps describing the properties of the format that may not change. As an example, for MPEG audio inside an MPEG system stream, this would mean a wide caps of audio/mpeg with mpegversion=1 and layer=[1,2]. For the same audio type in MPEG, though, the samplerate, bitrate, layer and number of channels would become static, too. Since the (request) pads will be removed when the stream ends, the static caps will cease to exist too, then. While the explicit caps exist, the _link ()- function will not be called, since the core will do all necessary checks for us. Note that the property of using explicit caps should be added along with the actual explicit caps, not any earlier. Below here follows the simple example of an AVI muxer's audio caps negotiation. The _link ()-function is fairly normal, but the -Loop ()-function does some of the tricks mentioned above. There is no _getcaps ()- function since the pad template contains all that information already (not shown). static GstPadLinkReturn gst_avi_mux_audio_link (GstPad *pad, const GstCaps *caps) { GstAviMux *mux = GST_AVI_MUX (gst_pad_get_parent (pad)); GstStructure *str = gst_caps_get_structure (caps, 0); const gchar *mime = gst_structure_get_name (str); if (!strcmp (str, "audio/mpeg")) { /* get version, make sure it's 1, get layer, make sure it's 1-3, * then create the 2-byte audio tag (0x0055) and fill an audio * stream structure (strh/strf). */ [..] return GST_PAD_LINK_OK; } else if !strcmp (str, "audio/x-raw-int")) { /* See above, but now with the raw audio tag (0x0001). */ [..] return GST_PAD_LINK_OK; } else [..] [..] } static void gst_avi_mux_loop (GstElement *element) { GstAviMux *mux = GST_AVI_MUX (element); [..] /* As we get here, we should have written the header if we hadn't done * that before yet, and we're supposed to have an internal buffer from * each pad, also from the audio one. So here, we check again whether * this is the first run and if so, we set static caps. */ if (mux->first_cycle) { const GList *padlist = gst_element_get_pad_list (element); GList *item; for (item = padlist; item != NULL; item = item->next) { GstPad *pad = item->data; GstCaps *caps; if (!GST_PAD_IS_SINK (pad)) continue; /* set static caps here */ if (!strncmp (gst_pad_get_name (pad), "audio_", 6)) { /* the strf is the struct you filled in the _link () function. */ switch (strf->format) { case 0x0055: /* mp3 */ caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, "bitrate", G_TYPE_INT, strf->av_bps, "rate", G_TYPE_INT, strf->rate, "channels", G_TYPE_INT, strf->channels, NULL); break; case 0x0001: /* pcm */ caps = gst_caps_new_simple ("audio/x-raw-int", [..]); break; [..] } } else if (!strncmp (gst_pad_get_name (pad), "video_", 6)) { [..] } else { g_warning ("oi!"); continue; } /* set static caps */ gst_pad_use_explicit_caps (pad); gst_pad_set_explicit_caps (pad, caps); } } [..] /* Next runs will never be the first again. */ mux->first_cycle = FALSE; } Note that there are other ways to achieve that, which might be useful for more complex cases. This will do for the simple cases, though. This method is provided to simplify negotiation and renegotiation in muxers, it is not a complete solution, nor is it a pretty one. Markup vs. data processing As we noted on demuxers before, we love common programming paradigms such as clean, lean and mean code. To achieve that in muxers, it's generally a good idea to separate the actual data stream markup from the data processing. To illustrate, here's how AVI muxers should write out RIFF tag chunks: static void gst_avi_mux_write_chunk (GstAviMux *mux, guint32 id, GstBuffer *data) { GstBuffer *hdr; hdr = gst_buffer_new_and_alloc (8); ((guint32 *) GST_BUFFER_DATA (buf))[0] = GUINT32_TO_LE (id); ((guint32 *) GST_BUFFER_DATA (buf))[1] = GUINT32_TO_LE (GST_BUFFER_SIZE (data)); gst_pad_push (mux->srcpad, hdr); gst_pad_push (mux->srcpad, data); } static void gst_avi_mux_loop (GstElement *element) { GstAviMux *mux = GST_AVI_MUX (element); GstBuffer *buf; [..] buf = gst_pad_pull (mux->sinkpad[0]); [..] gst_avi_mux_write_chunk (GST_MAKE_FOURCC ('0','0','d','b'), buf); } In general, try to program clean code, that should cover pretty much everything. Writing a N-to-N element FIXME: write. Writing an Autoplugger FIXME: write. Writing a Manager Managers are elements that add a function or unify the function of another (series of) element(s). Managers are generally a GstBin with one or more ghostpads. Inside them is/are the actual element(s) that matters. There is several cases where this is useful. For example: To add support for private events with custom event handling to another element. To add support for custom pad _query () or _convert () handling to another element. To add custom data handling before or after another element's data handler function (generally its _chain () function). This chapter will explain the setup of managers. As a specific example, we will try to add EOS event support to source elements. This can be used to finish capturing an audio stream to a file. Source elements normally don't do any EOS handling at all, so a manager is perfect to extend those element's functionalities. Specifically, this element will contain two child elements: the actual source element and a helper element that implement an event handler on its source pad. This event handler will respond to EOS events by storing them internally and returning the event (rather than data) on the next call to the _get () function. After that, it will go into EOS and set the parent (and thereby the contained source element) to EOS as well. Other events will be forwarded to the source element, which will handle them as usual. .. Appendices This chapter contains things that don't belong anywhere else. Things to check when writing an element This chapter contains a fairly random selection of things to take care of when writing an element. It's up to you how far you're going to stick to those guidelines. However, keep in mind that when you're writing an element and hope for it to be included in the mainstream GStreamer distribution, it has to meet those requirements. As far as possible, we will try to explain why those requirements are set. About states Make sure the state of an element gets reset when going to NULL. Ideally, this should set all object properties to their original state. This function should also be called from _init. Make sure an element forgets everything about its contained stream when going from PAUSED to READY. In READY, all stream states are reset. An element that goes from PAUSED to READY and back to PAUSED should start reading the stream from he start again. People that use gst-launch for testing have the tendency to not care about cleaning up. This is wrong. An element should be tested using various applications, where testing not only means to make sure it doesn't crash, but also to test for memory leaks using tools such as valgrind. Elements have to be reusable in a pipeline after having been reset. Debugging Elements should never use their standard output for debugging (using functions such as printf () or g_print ()). Instead, elements should use the logging functions provided by GStreamer, named GST_DEBUG (), GST_LOG (), GST_INFO (), GST_WARNING () and GST_ERROR (). The various logging levels can be turned on and off at runtime and can thus be used for solving issues as they turn up. Instead of GST_LOG () (as an example), you can also use GST_LOG_OBJECT () to print the object that you're logging output for. Ideally, elements should use their own debugging category. Most elements use the following code to do that: GST_DEBUG_CATEGORY_STATIC (myelement_debug); #define GST_CAT_DEFAULT myelement_debug [..] static void gst_myelement_class_init (GstMyelementClass *klass) { [..] GST_DEBUG_CATEGORY_INIT (myelement_debug, "myelement", 0, "My own element"); } At runtime, you can turn on debugging using the commandline option --gst-debug=myelement:5. Querying, events and the like All elements to which it applies (sources, sinks, demuxers) should implement query functions on their pads, so that applications and neighbour elements can request the current position, the stream length (if known) and so on. All elements that are event-aware (their GST_ELEMENT_EVENT_AWARE flag is set) should implement event handling for all events, either specifically or using gst_pad_event_default (). Elements that you should handle specifically are the interrupt event, in order to properly bail out as soon as possible if state is changed. Events may never be dropped unless specifically intended. Loop-based elements should always implement event handling, in order to prevent hangs (infinite loop) on state changes. Testing your element gst-launch is not a good tool to show that your element is finished. Applications such as Rhythmbox and Totem (for GNOME) or AmaroK (for KDE) are. gst-launch will not test various things such as proper clean-up on reset, interrupt event handling, querying and so on. Parsers and demuxers should make sure to check their input. Input cannot be trusted. Prevent possible buffer overflows and the like. Feel free to error out on unrecoverable stream errors. Test your demuxer using stream corruption elements such as breakmydata (included in gst-plugins). It will randomly insert, delete and modify bytes in a stream, and is therefore a good test for robustness. If your element crashes when adding this element, your element needs fixing. If it errors out properly, it's good enough. Ideally, it'd just continue to work and forward data as much as possible. Demuxers should not assume that seeking works. Be prepared to work with unseekable input streams (e.g. network sources) as well. Sources and sinks should be prepared to be assigned another clock then the one they expose themselves. Always use the provided clock for synchronization, else you'll get A/V sync issues. GStreamer licensingHow to license the code you write for GStreamer GStreamer is a plugin-based framework licensed under the LGPL. The reason for this choice in licensing is to ensure that everyone can use GStreamer to build applications using licenses of their choice. To keep this policy viable, the GStreamer community has made a few licensing rules for code to be included in GStreamer's core or GStreamer's official modules, like our plugin packages. We require that all code going into our core package is LGPL. For the plugin code, we require the use of the LGPL for all plugins written from scratch or linking to external libraries. The only exception to this is when plugins contain older code under more liberal licenses (like the MPL or BSD). They can use those licenses instead and will still be considered for inclusion. We do not accept GPL code to be added to our plugins module, but we do accept LGPL-licensed plugins using an external GPL library. The reason for demanding plugins be licensed under the LGPL, even when using a GPL library, is that other developers might want to use the plugin code as a template for plugins linking to non-GPL libraries. We also plan on splitting out the plugins using GPL libraries into a separate package eventually and implement a system which makes sure an application will not be able to access these plugins unless it uses some special code to do so. The point of this is not to block GPL-licensed plugins from being used and developed, but to make sure people are not unintentionally violating the GPL license of said plugins. This advisory is part of a bigger advisory with a FAQ which you can find on the GStreamer website Done. Copying .css files: base.css make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' make[3]: Nothing to be done for `install-exec-am'. make[4]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' cd build && xmllint -noout -valid pwg.xml make[4]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' *** Generating HTML output *** Using catalogs: /etc/sgml/xml-docbook-4.2-1.0-30.cat Using stylesheet: /usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl#html Working on: /usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg/build/pwg.xml jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:73:W: cannot generate system identifier for public text "-//James Clark//DTD DSSSL Style Sheet//EN" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:11:0:E: reference to entity "STYLE-SHEET" for which no system identifier could be generated jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1:0: entity was defined here jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:5:0:E: notation "DSSSL" for entity "docbook.dsl" undefined jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:24:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:39:36:E: there is no attribute "USE" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:27:E: there is no attribute "ID" jade:/usr/share/sgml/docbook/utils-0.6.14/docbook-utils.dsl:1059:46:E: there is no attribute "DOCUMENT" jade:E: specification document does not have the DSSSL architecture as a base architecture jade:E: no style-specification or external-specification with ID "HTML" RichardJohnBoulton richard-gst@tartarus.org ErikWalthinsen omega@temple-baptist.com SteveBaker stevebaker_org@yahoo.co.uk LeifJohnson leif@ambient.2y.net RonaldS.Bultje rbultje@ronald.bitfreak.net This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). GStreamer Plugin Writer's Guide (0.8.11)Introduction GStreamer is an exremely powerful and versatile framework for creating streaming media applications. Many of the virtues of the GStreamer framework come from its modularity: GStreamer can seamlessly incorporate new plugin modules. But because modularity and power often come at a cost of greater complexity (consider, for example, CORBA), writing new plugins is not always easy. This guide is intended to help you understand the GStreamer framework (version 0.8.11) so you can develop new plugins to extend the existing functionality. The guide addresses most issues by following the development of an example plugin - an audio filter plugin - written in C. However, the later parts of the guide also present some issues involved in writing other types of plugins, and the end of the guide describes some of the Python bindings for GStreamer. PrefaceWho Should Read This Guide? This guide explains how to write new modules for GStreamer. The guide is relevant to several groups of people: Anyone who wants to add support for new ways of processing data in GStreamer. For example, a person in this group might want to create a new data format converter, a new visualization tool, or a new decoder or encoder. Anyone who wants to add support for new input and output devices. For example, people in this group might want to add the ability to write to a new video output system or read data from a digital camera or special microphone. Anyone who wants to extend GStreamer in any way. You need to have an understanding of how the plugin system works before you can understand the constraints that the plugin system places on the rest of the code. Also, you might be surprised after reading this at how much can be done with plugins. This guide is not relevant to you if you only want to use the existing functionality of GStreamer, or if you just want to use an application that uses GStreamer. If you are only interested in using existing plugins to write a new application - and there are quite a lot of plugins already - you might want to check the GStreamer Application Development Manual. If you are just trying to get help with a GStreamer application, then you should check with the user manual for that particular application. Preliminary Reading This guide assumes that you are somewhat familiar with the basic workings of GStreamer. For a gentle introduction to programming concepts in GStreamer, you may wish to read the GStreamer Application Development Manual first. Also check out the documentation available on the GStreamer web site. Since GStreamer adheres to the GObject programming model, this guide also assumes that you understand the basics of GObject programming. There are several good introductions to the GObject library, including the GTK+ Tutorial and the Glib Object system. Structure of This Guide To help you navigate through this guide, it is divided into several large parts. Each part addresses a particular broad topic concerning GStreamer plugin development. The parts of this guide are laid out in the following order: - Introduction to the structure of a plugin, using an example audio filter for illustration. This part covers all the basic steps you generally need to perform to build a plugin, such as registering the element with GStreamer and setting up the basics so it can receive data from and send data to neighbour elements. The discussion begins by giving examples of generating the basic structures and registering an element in . Then, you will learn how to write the code to get a basic filter plugin working in , and . After that, we will show some of the GObject concepts on how to make an element configurable for applications and how to do application-element interaction in and . Next, you will learn to build a quick test application to test all that you've just learned in . We will just touch upon basics here. For full-blown application development, you should look at the Application Development Manual. - Information on advanced features of GStreamer plugin development. After learning about the basic steps, you should be able to create a functional audio or video filter plugin with some nice features. However, GStreamer offers more for plugin writers. This part of the guide includes chapters on more advanced topics, such as scheduling, media type definitions in GStreamer, clocks, interfaces and tagging. Since these features are purpose-specific, you can read them in any order, most of them don't require knowledge from other sections. The first chapter, named , will explain some of the basics of element scheduling. It is not very in-depth, but is mostly some sort of an introduction on why other things work as they do. Read this chapter if you're interested in GStreamer internals. Next, we will apply this knowledge and discuss another type of data transmission than what you learned in : . Loop-based elements will give you more control over input rate. This is useful when writing, for example, muxers or demuxers. Next, we will discuss media identification in GStreamer in . You will learn how to define new media types and get to know a list of standard media types defined in GStreamer. In the next chapter, you will learn the concept of request- and sometimes-pads, which are pads that are created dynamically, either because the application asked for it (request) or because the media stream requires it (sometimes). This will be in . The next chapter, , will explain the concept of clocks in GStreamer. You need this information when you want to know how elements should achieve audio/video synchronization. The next few chapters will discuss advanced ways of doing application-element interaction. Previously, we learned on the GObject-ways of doing this in and . We will discuss dynamic parameters, which are a way of defining element behaviour over time in advance, in . Next, you will learn about interfaces in . Interfaces are very target- specific ways of application-element interaction, based on GObject's GInterface. Lastly, you will learn about how metadata is handled in GStreamer in . The last chapter, , will discuss the concept of events in GStreamer. Events are, on the one hand, another way of doing application-element interaction. It takes care of seeking, for example. On the other hand, it is also a way in which elements interact with each other, such as letting each other know about media stream discontinuities, forwarding tags inside a pipeline and so on. - Explanation of writing other plugin types. Because the first two parts of the guide use an audio filter as an example, the concepts introduced apply to filter plugins. But many of the concepts apply equally to other plugin types, including sources, sinks, and autopluggers. This part of the guide presents the issues that arise when working on these more specialized plugin types. The part includes chapters on , , , and . - Further information for plugin developers. The appendices contain some information that stubbornly refuses to fit cleanly in other sections of the guide. Most of this section is not yet finished. The remainder of this introductory part of the guide presents a short overview of the basic concepts involved in GStreamer plugin development. Topics covered include , , and . If you are already familiar with this information, you can use this short overview to refresh your memory, or you can skip to . As you can see, there a lot to learn, so let's get started! Creating compound and complex elements by extending from a GstBin. This will allow you to create plugins that have other plugins embedded in them. Adding new mime-types to the registry along with typedetect functions. This will allow your plugin to operate on a completely new media type. Basic Concepts This chapter of the guide introduces the basic concepts of GStreamer. Understanding these concepts will help you grok the issues involved in extending GStreamer. Many of these concepts are explained in greater detail in the GStreamer Application Development Manual; the basic concepts presented here serve mainly to refresh your memory. Elements and Plugins Elements are at the core of GStreamer. In the context of plugin development, an element is an object derived from the GstElement class. Elements provide some sort of functionality when linked with other elements: For example, a source element provides data to a stream, and a filter element acts on the data in a stream. Without elements, GStreamer is just a bunch of conceptual pipe fittings with nothing to link. A large number of elements ship with GStreamer, but extra elements can also be written. Just writing a new element is not entirely enough, however: You will need to encapsulate your element in a plugin to enable GStreamer to use it. A plugin is essentially a loadable block of code, usually called a shared object file or a dynamically linked library. A single plugin may contain the implementation of several elements, or just a single one. For simplicity, this guide concentrates primarily on plugins containing one element. A filter is an important type of element that processes a stream of data. Producers and consumers of data are called source and sink elements, respectively. Bin elements contain other elements. One type of bin is responsible for scheduling the elements that they contain so that data flows smoothly. Another type of bin, called autoplugger elements, automatically add other elements to the bin and links them together so that they act as a filter between two arbitary stream types. The plugin mechanism is used everywhere in GStreamer, even if only the standard packages are being used. A few very basic functions reside in the core library, and all others are implemented in plugins. A plugin registry is used to store the details of the plugins in an XML file. This way, a program using GStreamer does not have to load all plugins to determine which are needed. Plugins are only loaded when their provided elements are requested. See the GStreamer Library Reference for the current implementation details of GstElement and GstPlugin. Pads Pads are used to negotiate links and data flow between elements in GStreamer. A pad can be viewed as a place or port on an element where links may be made with other elements, and through which data can flow to or from those elements. Pads have specific data handling capabilities: A pad can restrict the type of data that flows through it. Links are only allowed between two pads when the allowed data types of the two pads are compatible. An analogy may be helpful here. A pad is similar to a plug or jack on a physical device. Consider, for example, a home theater system consisting of an amplifier, a DVD player, and a (silent) video projector. Linking the DVD player to the amplifier is allowed because both devices have audio jacks, and linking the projector to the DVD player is allowed because both devices have compatible video jacks. Links between the projector and the amplifier may not be made because the projector and amplifier have different types of jacks. Pads in GStreamer serve the same purpose as the jacks in the home theater system. For the most part, all data in GStreamer flows one way through a link between elements. Data flows out of one element through one or more source pads, and elements accept incoming data through one or more sink pads. Source and sink elements have only source and sink pads, respectively. See the GStreamer Library Reference for the current implementation details of a GstPad. Data, Buffers and Events All streams of data in GStreamer are chopped up into chunks that are passed from a source pad on one element to a sink pad on another element. Data are structures used to hold these chunks of data. Data contains the following important types: An exact type indicating what type of data (control, content, ...) this Data is. A reference count indicating the number of elements currently holding a reference to the buffer. When the buffer reference count falls to zero, the buffer will be unlinked, and its memory will be freed in some sense (see below for more details). There are two types of data defined: events (control) and buffers (content). Buffers may contain any sort of data that the two linked pads know how to handle. Normally, a buffer contains a chunk of some sort of audio or video data that flows from one element to another. Buffers also contain metadata describing the buffer's contents. Some of the important types of metadata are: A pointer to the buffer's data. An integer indicating the size of the buffer's data. A timestamp indicating the preferred display timestamp of the content in the buffer. Events contain information on the state of the stream flowing between the two linked pads. Events will only be sent if the element explicitely supports them, else the core will (try to) handle the events automatically. Events are used to indicate, for example, a clock discontinuity, the end of a media stream or that the cache should be flushed. Events may contain several of the following items: A subtype indicating the type of the contained event. The other contents of the event depend on the specific event type. Events will be discussed extensively in . Until then, the only event that will be used is the EOS event, which is used to indicate the end-of-stream (usually end-of-file). See the GStreamer Library Reference for the current implementation details of a GstData, GstBuffer and GstEvent. Buffer Allocation Buffers are able to store chunks of memory of several different types. The most generic type of buffer contains memory allocated by malloc(). Such buffers, although convenient, are not always very fast, since data often needs to be specifically copied into the buffer. Many specialized elements create buffers that point to special memory. For example, the filesrc element usually maps a file into the address space of the application (using mmap()), and creates buffers that point into that address range. These buffers created by filesrc act exactly like generic buffers, except that they are read-only. The buffer freeing code automatically determines the correct method of freeing the underlying memory. Downstream elements that recieve these kinds of buffers do not need to do anything special to handle or unreference it. Another way an element might get specialized buffers is to request them from a downstream peer. These are called downstream-allocated buffers. Elements can ask a peer connected to a source pad to create an empty buffer of a given size. If a downstream element is able to create a special buffer of the correct size, it will do so. Otherwise GStreamer will automatically create a generic buffer instead. The element that requested the buffer can then copy data into the buffer, and push the buffer to the source pad it was allocated from. Many sink elements have accelerated methods for copying data to hardware, or have direct access to hardware. It is common for these elements to be able to create downstream-allocated buffers for their upstream peers. One such example is ximagesink. It creates buffers that contain XImages. Thus, when an upstream peer copies data into the buffer, it is copying directly into the XImage, enabling ximagesink to draw the image directly to the screen instead of having to copy data into an XImage first. Filter elements often have the opportunity to either work on a buffer in-place, or work while copying from a source buffer to a destination buffer. It is optimal to implement both algorithms, since the GStreamer framework can choose the fastest algorithm as appropriate. Naturally, this only makes sense for strict filters -- elements that have exactly the same format on source and sink pads. Mimetypes and Properties GStreamer uses a type system to ensure that the data passed between elements is in a recognized format. The type system is also important for ensuring that the parameters required to fully specify a format match up correctly when linking pads between elements. Each link that is made between elements has a specified type and optionally a set of properties. The Basic Types GStreamer already supports many basic media types. Following is a table of a few of the the basic types used for buffers in GStreamer. The table contains the name ("mime type") and a description of the type, the properties associated with the type, and the meaning of each property. A full list of supported types is included in . Table of Basic TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Descriptionaudio/* All audio types rateintegergreater than 0 The sample rate of the data, in samples (per channel) per second. channelsintegergreater than 0 The number of channels of audio data. audio/x-raw-int Unstructured and uncompressed raw integer audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). signedbooleanTRUE or FALSE Whether the values of the integer samples are signed or not. Signed samples use one bit to indicate sign (negative or positive) of the value. Unsigned samples are always positive. widthintegergreater than 0 Number of bits allocated per sample. depthintegergreater than 0 The number of bits used per sample. This must be less than or equal to the width: If the depth is less than the width, the low bits are assumed to be the ones used. For example, a width of 32 and a depth of 24 means that each sample is stored in a 32 bit word, but only the low 24 bits are actually used. audio/mpeg Audio data compressed using the MPEG audio encoding scheme. mpegversioninteger1, 2 or 4 The MPEG-version used for encoding the data. The value 1 refers to MPEG-1, -2 and -2.5 layer 1, 2 or 3. The values 2 and 4 refer to the MPEG-AAC audio encoding schemes. framedboolean0 or 1 A true value indicates that each buffer contains exactly one frame. A false value indicates that frames and buffers do not necessarily match up. layerinteger1, 2, or 3 The compression scheme layer used to compress the data (only if mpegversion=1). bitrateintegergreater than 0 The bitrate, in bits per second. For VBR (variable bitrate) MPEG data, this is the average bitrate. audio/x-vorbisVorbis audio data There are currently no specific properties defined for this type. Building a Plugin You are now ready to learn how to build a plugin. In this part of the guide, you will learn how to apply basic GStreamer programming concepts to write a simple plugin. The previous parts of the guide have contained no explicit example code, perhaps making things a bit abstract and difficult to understand. In contrast, this section will present both applications and code by following the development of an example audio filter plugin called ExampleFilter. The example filter element will begin with a single input pad and a single output pad. The filter will, at first, simply pass media and event data from its sink pad to its source pad without modification. But by the end of this part of the guide, you will learn to add some more interesting functionality, including properties and signal handlers. And after reading the next part of the guide, , you will be able to add even more functionality to your plugins. The example code used in this part of the guide can be found in examples/pwg/examplefilter/ in your GStreamer directory. Constructing the Boilerplate In this chapter you will learn how to construct the bare minimum code for a new plugin. Starting from ground zero, you will see how to get the GStreamer template source. Then you will learn how to use a few basic tools to copy and modify a template plugin to create a new plugin. If you follow the examples here, then by the end of this chapter you will have a functional audio filter plugin that you can compile and use in GStreamer applications. Getting the GStreamer Plugin Templates There are currently two ways to develop a new plugin for GStreamer: You can write the entire plugin by hand, or you can copy an existing plugin template and write the plugin code you need. The second method is by far the simpler of the two, so the first method will not even be described here. (Errm, that is, it is left as an exercise to the reader.) The first step is to check out a copy of the gst-template CVS module to get an important tool and the source code template for a basic GStreamer plugin. To check out the gst-template module, make sure you are connected to the internet, and type the following commands at a command console: shell $ cvs -d:pserver:anoncvs@cvs.freedesktop.org/cvs/gstreamer login Logging in to :pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer CVS password: [ENTER] shell $ cvs -z3 -d:pserver:anoncvs@cvs.freedesktop.org:/cvs/gstreamer co gst-template U gst-template/README U gst-template/gst-app/AUTHORS U gst-template/gst-app/ChangeLog U gst-template/gst-app/Makefile.am U gst-template/gst-app/NEWS U gst-template/gst-app/README U gst-template/gst-app/autogen.sh U gst-template/gst-app/configure.ac U gst-template/gst-app/src/Makefile.am ... After the first command, you will have to press ENTER to log in to the CVS server. (You might have to log in twice.) The second command will check out a series of files and directories into ./gst-template. The template you will be using is in ./gst-template/gst-plugin/ directory. You should look over the files in that directory to get a general idea of the structure of a source tree for a plugin. Using the Project Stamp The first thing to do when making a new element is to specify some basic details about it: what its name is, who wrote it, what version number it is, etc. We also need to define an object to represent the element and to store the data the element needs. These details are collectively known as the boilerplate. The standard way of defining the boilerplate is simply to write some code, and fill in some structures. As mentioned in the previous section, the easiest way to do this is to copy a template and add functionality according to your needs. To help you do so, there are some tools in the ./gst-plugins/tools/ directory. One tool, gst-quick-stamp, is a quick command line tool. The other, gst-project-stamp, is a full GNOME druid application that takes you through the steps of creating a new project (either a plugin or an application). To use pluginstamp.sh, first open up a terminal window. Change to the gst-template directory, and then run the pluginstamp.sh command. The arguments to the pluginstamp.sh are: the name of the plugin, and the directory that should hold a new subdirectory for the source tree of the plugin. Note that capitalization is important for the name of the plugin. Under some operating systems, capitalization is also important when specifying directory names. For example, the following commands create the ExampleFilter plugin based on the plugin template and put the output files in a new directory called ~/src/examplefilter/: shell $ cd gst-template shell $ tools/pluginstamp.sh ExampleFilter ~/src Examining the Basic Code First we will examine the code you would be likely to place in a header file (although since the interface to the code is entirely defined by the plugin system, and doesn't depend on reading a header file, this is not crucial.) The code here can be found in examples/pwg/examplefilter/boiler/gstexamplefilter.h. Example Plugin Header File /* Definition of structure storing data for this element. */ typedef struct _GstExample GstExample; struct _GstExample { GstElement element; GstPad *sinkpad, *srcpad; gboolean silent; }; /* Standard definition defining a class for this element. */ typedef struct _GstExampleClass GstExampleClass; struct _GstExampleClass { GstElementClass parent_class; }; /* Standard macros for defining types for this element. */ #define GST_TYPE_EXAMPLE \ (gst_example_get_type()) #define GST_EXAMPLE(obj) \ (G_TYPE_CHECK_CAST((obj),GST_TYPE_EXAMPLE,GstExample)) #define GST_EXAMPLE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EXAMPLE,GstExample)) #define GST_IS_EXAMPLE(obj) \ (G_TYPE_CHECK_TYPE((obj),GST_TYPE_EXAMPLE)) #define GST_IS_EXAMPLE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE)) /* Standard function returning type information. */ GType gst_example_get_type (void); GstElementDetails The GstElementDetails structure gives a hierarchical type for the element, a human-readable description of the element, as well as author and version data. The entries are: A long, english, name for the element. The type of the element, as a hierarchy. The hierarchy is defined by specifying the top level category, followed by a "/", followed by the next level category, etc. The type should be defined according to the guidelines elsewhere in this document. (FIXME: write the guidelines, and give a better reference to them) A brief description of the purpose of the element. The name of the author of the element, optionally followed by a contact email address in angle brackets. For example: static GstElementDetails example_details = { "An example plugin", "Example/FirstExample", "Shows the basic structure of a plugin", "your name <your.name@your.isp>" }; The element details are registered with the plugin during the _base_init () function, which is part of the GObject system. The _base_init () function should be set for this GObject in the function where you register the type with Glib. static void gst_my_filter_base_init (GstMyFilterClass *klass) { static GstElementDetails my_filter_details = { [..] }; GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] gst_element_class_set_details (element_class, &my_filter_details); } GstStaticPadTemplate A GstStaticPadTemplate is a description of a pad that the element will (or might) create and use. It contains: A short name for the pad.Pad direction. Existence property. This indicates whether the pad exists always (an always pad), only in some cases (a sometimes pad) or only if the application requested such a pad (a request pad). Supported types by this element (capabilities). For example: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); Those pad templates are registered during the _base_init () function. Pads are created from these templates in the element's _init () function using gst_pad_new_from_template (). The template can be retrieved from the element class using gst_element_class_get_pad_template (). See below for more details on this. In order to create a new pad from this template using gst_pad_new_from_template (), you will need to declare the pad template as a global variable. More on this subject in . static GstStaticPadTemplate sink_factory = [..], src_factory = [..]; static void gst_my_filter_base_init (GstMyFilterClass *klass) { [..] GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory)); [..] } The last argument in a template is its type or list of supported types. In this example, we use 'ANY', which means that this element will accept all input. In real-life situations, you would set a mimetype and optionally a set of properties to make sure that only supported input will come in. This representation should be a string that starts with a mimetype, then a set of comma-separates properties with their supported values. In case of an audio filter that supports raw integer 16-bit audio, mono or stereo at any samplerate, the correct template would look like this: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ( "audio/x-raw-int, " "width = (int) 16, " "depth = (int) 16, " "endianness = (int) BYTE_ORDER, " "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]" ) ); Values surrounded by curly brackets ({ and }) are lists, values surrounded by square brackets ([ and ]) are ranges. Multiple sets of types are supported too, and should be separated by a semicolon (;). Later, in the chapter on pads, we will see how to use types to know the exact format of a stream: . Constructor Functions Each element has three functions which are used for construction of an element. These are the _base_init() function which is meant to initialize class and child class properties during each new child class creation; the _class_init() function, which is used to initialise the class only once (specifying what signals, arguments and virtual functions the class has and setting up global state); and the _init() function, which is used to initialise a specific instance of this type. The plugin_init function Once we have written code defining all the parts of the plugin, we need to write the plugin_init() function. This is a special function, which is called as soon as the plugin is loaded, and should return TRUE or FALSE depending on whether it loaded initialized any dependencies correctly. Also, in this function, any supported element type in the plugin should be registered. static gboolean plugin_init (GstPlugin *plugin) { return gst_element_register (plugin, "my_filter", GST_RANK_NONE, GST_TYPE_MY_FILTER); } GST_PLUGIN_DEFINE ( GST_VERSION_MAJOR, GST_VERSION_MINOR, "my_filter", "My filter plugin", plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/" ) Note that the information returned by the plugin_init() function will be cached in a central registry. For this reason, it is important that the same information is always returned by the function: for example, it must not make element factories available based on runtime conditions. If an element can only work in certain conditions (for example, if the soundcard is not being used by some other process) this must be reflected by the element being unable to enter the READY state if unavailable, rather than the plugin attempting to deny existence of the plugin. Specifying the pads As explained before, pads are the port through which data goes in and out of your element, and that makes them a very important item in the process of element creation. In the boilerplate code, we have seen how static pad templates take care of registering pad templates with the element class. Here, we will see how to create actual elements, use _link () and _getcaps () functions to let other elements know their capabilities and how to register functions to let data flow through the element. In the element _init () function, you create the pad from the pad template that has been registered with the element class in the _base_init () function. After creating the pad, you have to set a _link () function pointer and a _getcaps () function pointer. Optionally, you can set a _chain () function pointer (on sink pads in filter and sink elements) through which data will come in to the element, or (on source pads in source elements) a _get () function pointer through which data will be pulled from the element. After that, you have to register the pad with the element. This happens like this: static GstPadLinkReturn gst_my_filter_link (GstPad *pad, const GstCaps *caps); static GstCaps * gst_my_filter_getcaps (GstPad *pad); static void gst_my_filter_chain (GstPad *pad, GstData *data); static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); /* pad through which data comes in to the element */ filter->sinkpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink"); gst_pad_set_link_function (filter->sinkpad, gst_my_filter_link); gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps); gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain); gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); /* pad through which data goes out of the element */ filter->srcpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "src"), "src"); gst_pad_set_link_function (filter->srcpad, gst_my_filter_link); gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps); gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); [..] } The link function The _link () is called during caps negotiation. This is the process where the linked pads decide on the streamtype that will transfer between them. A full list of type-definitions can be found in . A _link () receives a pointer to a GstCaps struct that defines the proposed streamtype, and can respond with either yes (GST_PAD_LINK_OK), no (GST_PAD_LINK_REFUSED) or don't know yet (GST_PAD_LINK_DELAYED). If the element responds positively towards the streamtype, that type will be used on the pad. An example: static GstPadLinkReturn gst_my_filter_link (GstPad *pad, const GstCaps *caps) { GstStructure *structure = gst_caps_get_structure (caps, 0); GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; GstPadLinkReturn ret; const gchar *mime; /* Since we're an audio filter, we want to handle raw audio * and from that audio type, we need to get the samplerate and * number of channels. */ mime = gst_structure_get_name (structure); if (strcmp (mime, "audio/x-raw-int") != 0) { GST_WARNING ("Wrong mimetype %s provided, we only support %s", mime, "audio/x-raw-int"); return GST_PAD_LINK_REFUSED; } /* we're a filter and don't touch the properties of the data. * That means we can set the given caps unmodified on the next * element, and use that negotiation return value as ours. */ ret = gst_pad_try_set_caps (otherpad, gst_caps_copy (caps)); if (GST_PAD_LINK_FAILED (ret)) return ret; /* Capsnego succeeded, get the stream properties for internal * usage and return success. */ gst_structure_get_int (structure, "rate", &filter->samplerate); gst_structure_get_int (structure, "channels", &filter->channels); g_print ("Caps negotiation succeeded with %d Hz @ %d channels\n", filter->samplerate, filter->channels); return ret; } In here, we check the mimetype of the provided caps. Normally, you don't need to do that in your own plugin/element, because the core does that for you. We simply use it to show how to retrieve the mimetype from a provided set of caps. Types are stored in GstStructure internally. A GstCaps is nothing more than a small wrapper for 0 or more structures/types. From the structure, you can also retrieve properties, as is shown above with the function gst_structure_get_int (). If your _link () function does not need to perform any specific operation (i.e. it will only forward caps), you can set it to gst_pad_proxy_link. This is a link forwarding function implementation provided by the core. It is useful for elements such as identity. The getcaps function The _getcaps () funtion is used to request the list of supported formats and properties from the element. In some cases, this will be equal to the formats provided by the pad template, in which case this function can be omitted. In some cases, too, it will not depend on anything inside this element, but it will rather depend on the input from another element linked to this element's sink or source pads. In that case, you can use gst_pad_proxy_getcaps as implementation, it provides getcaps forwarding in the core. However, in many cases, the format supported by this element cannot be defined externally, but is more specific than those provided by the pad template. In this case, you should use a _getcaps () function. In the case as specified below, we assume that our filter is able to resample sound, so it would be able to provide any samplerate (indifferent from the samplerate specified on the other pad) on both pads. It explains how a _getcaps () can be used to do this. static GstCaps * gst_my_filter_getcaps (GstPad *pad) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps; gint n; if (gst_caps_is_empty (othercaps)) return othercaps; /* We support *any* samplerate, indifferent from the samplerate * supported by the linked elements on both sides. */ for (i = 0; i < gst_caps_get_size (othercaps); i++) { GstStructure *structure = gst_caps_get_structure (othercaps, i); gst_structure_remove_field (structure, "rate"); } caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad)); gst_caps_free (othercaps); return caps; } Explicit caps Obviously, many elements will not need this complex mechanism, because they are much simpler than that. They only support one format, or their format is fixed but the contents of the format depend on the stream or something else. In those cases, explicit caps are an easy way of handling caps. Explicit caps are an easy way of specifying one, fixed, supported format on a pad. Pads using explicit caps do not implement their own _getcaps () or _link () functions. When the exact format is known, an elements uses gst_pad_set_explicit_caps () to specify the exact format. This is very useful for demuxers, for example. static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); [..] filter->srcpad = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "src"), "src"); gst_pad_use_explicit_caps (filter->srcpad); [..] } static void gst_my_filter_somefunction (GstMyFilter *filter) { GstCaps *caps = ..; [..] gst_pad_set_explicit_caps (filter->srcpad, caps); [..] } The chain function The chain function is the function in which all data processing takes place. In the case of a simple filter, _chain () functions are mostly linear functions - so for each incoming buffer, one buffer will go out, too. Below is a very simple implementation of a chain function: static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstBuffer *buf = GST_BUFFER (data); if (!filter->silent) g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); } Obviously, the above doesn't do much useful. Instead of printing that the data is in, you would normally process the data there. Remember, however, that buffers are not always writable. In more advanced elements (the ones that do event processing), the incoming data might not even be a buffer. static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); GstBuffer *buf, *outbuf; if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (pad, event); break; } return; } buf = GST_BUFFER (data); outbuf = gst_my_filter_process_data (buf); gst_buffer_unref (buf); if (!outbuf) { /* something went wrong - signal an error */ gst_element_error (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL)); return; } gst_pad_push (filter->srcpad, GST_DATA (outbuf)); } In some cases, it might be useful for an element to have control over the input data rate, too. In that case, you probably want to write a so-called loop-based element. Source elements (with only source pads) can also be get-based elements. These concepts will be explained in the advanced section of this guide, and in the section that specifically discusses source pads. What are states? A state describes whether the element instance is initialized, whether it is ready to transfer data and whether it is currently handling data. There are four states defined in GStreamer: GST_STATE_NULL, GST_STATE_READY, GST_STATE_PAUSED and GST_STATE_PLAYING. GST_STATE_NULL (from now on referred to as NULL) is the default state of an element. In this state, it has not allocated any runtime resources, it has not loaded any runtime libraries and it can obviously not handle data. GST_STATE_READY (from now on referred to as READY) is the next state that an element can be in. In the READY state, an element has all default resources (runtime-libraries, runtime-memory) allocated. However, it has not yet allocated or defined anything that is stream-specific. When going from NULL to READY state (GST_STATE_NULL_TO_READY), an element should allocate any non-stream-specific resources and should load runtime-loadable libraries (if any). When going the other way around (from READY to NULL, GST_STATE_READY_TO_NULL), an element should unload these libraries and free all allocated resources. Examples of such resources are hardware devices. Note that files are generally streams, and these should thus be considered as stream-specific resources; therefore, they should not be allocated in this state. GST_STATE_PAUSED (from now on referred to as PAUSED) is a state in which an element is by all means able to handle data; the only 'but' here is that it doesn't actually handle any data. When going from the READY state into the PAUSED state (GST_STATE_READY_TO_PAUSED), the element will usually not do anything at all: all stream-specific info is generally handled in the _link (), which is called during caps negotiation. Exceptions to this rule are, for example, files: these are considered stream-specific data (since one file is one stream), and should thus be opened in this state change. When going from the PAUSED back to READY (GST_STATE_PAUSED_TO_READY), all stream-specific data should be discarded. GST_STATE_PLAYING (from now on referred to as PLAYING) is the highest state that an element can be in. It is similar to PAUSED, except that now, data is actually passing over the pipeline. The transition from PAUSED to PLAYING (GST_STATE_PAUSED_TO_PLAYING) should be as small as possible and would ideally cause no delay at all. The same goes for the reverse transition (GST_STATE_PLAYING_TO_PAUSED). Managing filter state An element can be notified of state changes through a virtual function pointer. Inside this function, the element can initialize any sort of specific data needed by the element, and it can optionally fail to go from one state to another. Do not g_assert for unhandled state changes; this is taken care of by the GstElement base class. static GstElementStateReturn gst_my_filter_change_state (GstElement *element); static void gst_my_filter_class_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); element_class->change_state = gst_my_filter_change_state; } static GstElementStateReturn gst_my_filter_change_state (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: if (!gst_my_filter_allocate_memory (filter)) return GST_STATE_FAILURE; break; case GST_STATE_READY_TO_NULL: gst_my_filter_free_memory (filter); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } Adding Arguments The primary and most important way of controlling how an element behaves, is through GObject properties. GObject properties are defined in the _class_init () function. The element optionally implements a _get_property () and a _set_property () function. These functions will be notified if an application changes or requests the value of a property, and can then fill in the value or take action required for that property to change value internally. /* properties */ enum { ARG_0, ARG_SILENT /* FILL ME */ }; static void gst_my_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_my_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gst_my_filter_class_init (GstMyFilterClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /* define properties */ g_object_class_install_property (object_class, ARG_SILENT, g_param_spec_boolean ("silent", "Silent", "Whether to be very verbose or not", FALSE, G_PARAM_READWRITE)); /* define virtual function pointers */ object_class->set_property = gst_my_filter_set_property; object_class->get_property = gst_my_filter_get_property; } static void gst_my_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (object); switch (prop_id) { case ARG_SILENT: filter->silent = g_value_get_boolean (value); g_print ("Silent argument was changed to %s\n", filter->silent ? "true" : "false"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_my_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (object); switch (prop_id) { case ARG_SILENT: g_value_set_boolean (value, filter->silent); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } The above is a very simple example of how arguments are used. Graphical applications - for example GStreamer Editor - will use these properties and will display a user-controlleable widget with which these properties can be changed. This means that - for the property to be as user-friendly as possible - you should be as exact as possible in the definition of the property. Not only in defining ranges in between which valid properties can be located (for integers, floats, etc.), but also in using very descriptive (better yet: internationalized) strings in the definition of the property, and if possible using enums and flags instead of integers. The GObject documentation describes these in a very complete way, but below, we'll give a short example of where this is useful. Note that using integers here would probably completely confuse the user, because they make no sense in this context. The example is stolen from videotestsrc. typedef enum { GST_VIDEOTESTSRC_SMPTE, GST_VIDEOTESTSRC_SNOW, GST_VIDEOTESTSRC_BLACK } GstVideotestsrcPattern; [..] #define GST_TYPE_VIDEOTESTSRC_PATTERN (gst_videotestsrc_pattern_get_type ()) static GType gst_videotestsrc_pattern_get_type (void) { static GType videotestsrc_pattern_type = 0; if (!videotestsrc_pattern_type) { static GEnumValue pattern_types[] = { { GST_VIDEOTESTSRC_SMPTE, "smpte", "SMPTE 100% color bars" }, { GST_VIDEOTESTSRC_SNOW, "snow", "Random (television snow)" }, { GST_VIDEOTESTSRC_BLACK, "black", "0% Black" }, { 0, NULL, NULL }, }; videotestsrc_pattern_type = g_enum_register_static ("GstVideotestsrcPattern", pattern_types); } return videotestsrc_pattern_type; } [..] static void gst_videotestsrc_class_init (GstvideotestsrcClass *klass) { [..] g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TYPE, g_param_spec_enum ("pattern", "Pattern", "Type of test pattern to generate", GST_TYPE_VIDEOTESTSRC_PATTERN, 1, G_PARAM_READWRITE)); [..] } Signals GObject signals can be used to notify applications of events specific to this object. Note, however, that the application needs to be aware of signals and their meaning, so if you're looking for a generic way for application-element interaction, signals are probably not what you're looking for. In many cases, however, signals can be very useful. See the GObject documentation for all internals about signals. Building a Test Application Often, you will want to test your newly written plugin in an as small setting as possible. Usually, gst-launch is a good first step at testing a plugin. However, you will often need more testing features than gst-launch can provide, such as seeking, events, interactivity and more. Writing your own small testing program is the easiest way to accomplish this. This section explains - in a few words - how to do that. For a complete application development guide, see the Application Development Manual. At the start, you need to initialize the GStreamer core library by calling gst_init (). You can alternatively call gst_init_with_popt_tables (), which will return a pointer to popt tables. You can then use libpopt to handle the given argument table, and this will finish the GStreamer intialization. You can create elements using gst_element_factory_make (), where the first argument is the element type that you want to create, and the second argument is a free-form name. The example at the end uses a simple filesource - decoder - soundcard output pipeline, but you can use specific debugging elements if that's necessary. For example, an identity element can be used in the middle of the pipeline to act as a data-to-application transmitter. This can be used to check the data for misbehaviours or correctness in your test application. Also, you can use a fakesink element at the end of the pipeline to dump your data to the stdout (in order to do this, set the dump property to TRUE). Lastly, you can use the efence element (indeed, an eletric fence memory debugger wrapper element) to check for memory errors. During linking, your test application can use fixation or filtered caps as a way to drive a specific type of data to or from your element. This is a very simple and effective way of checking multiple types of input and output in your element. Running the pipeline happens through the gst_bin_iterate () function. Note that during running, you should connect to at least the error and eos signals on the pipeline and/or your plugin/element to check for correct handling of this. Also, you should add events into the pipeline and make sure your plugin handles these correctly (with respect to clocking, internal caching, etc.). Never forget to clean up memory in your plugin or your test application. When going to the NULL state, your element should clean up allocated memory and caches. Also, it should close down any references held to possible support libraries. Your application should unref () the pipeline and make sure it doesn't crash. #include <gst/gst.h> gint main (gint arcg, gchar *argv[]) { GstElement *pipeline, *filesrc, *decoder, *filter, *sink; /* initialization */ gst_init (&argc, &argv); /* create elements */ pipeline = gst_pipeline_new ("my_pipeline"); filesrc = gst_element_factory_make ("filesrc", "my_filesource"); decoder = gst_element_factory_make ("mad", "my_decoder"); filter = gst_element_factory_make ("my_filter", "my_filter"); sink = gst_element_factory_make ("osssink", "audiosink"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); /* link everything together */ gst_element_link_many (filesrc, decoder, filter, sink, NULL); gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, filter, sink, NULL); /* run */ gst_element_set_state (pipeline, GST_STATE_PLAYING); while (gst_bin_iterate (GST_BIN (pipeline))); /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } Creating a Filter with a Filter Factory A plan for the future is to create a FilterFactory, to make the process of making a new filter a simple process of specifying a few details, and writing a small amount of code to perform the actual data processing. Ideally, a FilterFactory would perform the tasks of boilerplate creation, code functionality implementation, and filter registration. Unfortunately, this has not yet been implemented. Even when someone eventually does write a FilterFactory, this element will not be able to cover all the possibilities available for filter writing. Thus, some plugins will always need to be manually coded and registered. Here is a rough outline of what is planned: You run the FilterFactory and give the factory a list of appropriate function pointers and data structures to define a filter. With a reasonable measure of preprocessor magic, you just need to provide a name for the filter and definitions of the functions and data structures desired. Then you call a macro from within plugin_init() that registers the new filter. All the fluff that goes into the definition of a filter is thus be hidden from view. Advanced Filter Concepts By now, you should be able to create basic filter elements that can receive and send data. This is the simple model that GStreamer stands for. But GStreamer can do much more than only this! In this chapter, various advanced topics will be discussed, such as scheduling, special pad types, clocking, events, interfaces, tagging and more. These topics are the sugar that makes GStreamer so easy to use for applications. How scheduling works Scheduling is, in short, a method for making sure that every element gets called once in a while to process data and prepare data for the next element. Likewise, a kernel has a scheduler to for processes, and your brain is a very complex scheduler too in a way. Randomly calling elements' chain functions won't bring us far, however, so you'll understand that the schedulers in GStreamer are a bit more complex than this. However, as a start, it's a nice picture. GStreamer currently provides two schedulers: a basic scheduler and an optimal scheduler. As the name says, the basic scheduler (basic) is an unoptimized, but very complete and simple scheduler. The optimal scheduler (opt), on the other hand, is optimized for media processing, but therefore also more complex. Note that schedulers only operate on one thread. If your pipeline contains multiple threads, each thread will run with a separate scheduler. That is the reason why two elements running in different threads need a queue-like element (a DECOUPLED element) in between them. The Basic Scheduler The basic scheduler assumes that each element is its own process. We don't use UNIX processes or POSIX threads for this, however; instead, we use so-called co-threads. Co-threads are threads that run besides each other, but only one is active at a time. The advantage of co-threads over normal threads is that they're lightweight. The disadvantage is that UNIX or POSIX do not provide such a thing, so we need to include our own co-threads stack for this to run. The task of the scheduler here is to control which co-thread runs at what time. A well-written scheduler based on co-threads will let an element run until it outputs one piece of data. Upon pushing one piece of data to the next element, it will let the next element run, and so on. Whenever a running element requires data from the previous element, the scheduler will switch to that previous element and run that element until it has provided data for use in the next element. This method of running elements as needed has the disadvantage that a lot of data will often be queued in between two elements, as the one element has provided data but the other element hasn't actually used it yet. These storages of in-between-data are called bufpens, and they can be visualized as a light queue. Note that since every element runs in its own (co-)thread, this scheduler is rather heavy on your system for larger pipelines. The Optimal Scheduler The optimal scheduler takes advantage of the fact that several elements can be linked together in one thread, with one element controlling the other. This works as follows: in a series of chain-based elements, each element has a function that accepts one piece of data, and it calls a function that provides one piece of data to the next element. The optimal scheduler will make sure that the gst_pad_push () function of the first element directly calls the chain-function of the second element. This significantly decreases the latency in a pipeline. It takes similar advantage of other possibilities of short-cutting the data path from one element to the next. The disadvantage of the optimal scheduler is that it is not fully implemented. Also it is badly documented; for most developers, the opt scheduler is one big black box. Features that are not implemented include pad-unlinking within a group while running, pad-selecting (i.e. waiting for data to arrive on a list of pads), and it can't really cope with multi-input/-output elements (with the elements linked to each of these in-/outputs running in the same thread) right now. Some of our developers are intending to write a new scheduler, similar to the optimal scheduler (but better documented and more completely implemented). How a loopfunc works A _loop () function is a function that is called by the scheduler, but without providing data to the element. Instead, the element will become responsible for acquiring its own data, and it will still be responsible of sending data over to its source pads. This method noticeably complicates scheduling; you should only write loop-based elements when you need to. Normally, chain-based elements are preferred. Examples of elements that have to be loop-based are elements with multiple sink pads. Since the scheduler will push data into the pads as it comes (and this might not be synchronous), you will easily get asynchronous data on both pads, which means that the data that arrives on the first pad has a different display timestamp than the data arriving on the second pad at the same time. To get over these issues, you should write such elements in a loop-based form. Other elements that are easier to write in a loop-based form than in a chain-based form are demuxers and parsers. It is not required to write such elements in a loop-based form, though. Below is an example of the easiest loop-function that one can write: static void gst_my_filter_loopfunc (GstElement *element); static void gst_my_filter_init (GstMyFilter *filter) { [..] gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc); [..] } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstData *data; /* acquire data */ data = gst_pad_pull (filter->sinkpad); /* send data */ gst_pad_push (filter->srcpad, data); } Obviously, this specific example has no single advantage over a chain-based element, so you should never write such elements. However, it's a good introduction to the concept. Multi-Input Elements Elements with multiple sink pads need to take manual control over their input to assure that the input is synchronized. The following example code could (should) be used in an aggregator, i.e. an element that takes input from multiple streams and sends it out intermangled. Not really useful in practice, but a good example, again. typedef struct _GstMyFilterInputContext { gboolean eos; GstBuffer *lastbuf; } GstMyFilterInputContext; [..] static void gst_my_filter_init (GstMyFilter *filter) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); GstMyFilterInputContext *context; filter->sinkpad1 = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink_1"); context = g_new0 (GstMyFilterInputContext, 1); gst_pad_set_private_data (filter->sinkpad1, context); [..] filter->sinkpad2 = gst_pad_new_from_template ( gst_element_class_get_pad_template (klass, "sink"), "sink_2"); context = g_new0 (GstMyFilterInputContext, 1); gst_pad_set_private_data (filter->sinkpad2, context); [..] gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc); } [..] static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GList *padlist; GstMyFilterInputContext *first_context = NULL; /* Go over each sink pad, update the cache if needed, handle EOS * or non-responding streams and see which data we should handle * next. */ for (padlist = gst_element_get_padlist (element); padlist != NULL; padlist = g_list_next (padlist)) { GstPad *pad = GST_PAD (padlist->data); GstMyFilterInputContext *context = gst_pad_get_private_data (pad); if (GST_PAD_IS_SRC (pad)) continue; while (GST_PAD_IS_USABLE (pad) && !context->eos && !context->lastbuf) { GstData *data = gst_pad_pull (pad); if (GST_IS_EVENT (data)) { /* We handle events immediately */ GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: context->eos = TRUE; gst_event_unref (event); break; case GST_EVENT_DISCONTINUOUS: g_warning ("HELP! How do I handle this?"); /* fall-through */ default: gst_pad_event_default (pad, event); break; } } else { /* We store the buffer to handle synchronization below */ context->lastbuf = GST_BUFFER (data); } } /* synchronize streams by always using the earliest buffer */ if (context->lastbuf) { if (!first_context) { first_context = context; } else { if (GST_BUFFER_TIMESTAMP (context->lastbuf) < GST_BUFFER_TIMESTAMP (first_context->lastbuf)) first_context = context; } } } /* If we handle no data at all, we're at the end-of-stream, so * we should signal EOS. */ if (!first_context) { gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); return; } /* So we do have data! Let's forward that to our source pad. */ gst_pad_push (filter->srcpad, GST_DATA (first_context->lastbuf)); first_context->lastbuf = NULL; } Note that a loop-function is allowed to return. Better yet, a loop function has to return so the scheduler can let other elements run (this is particularly true for the optimal scheduler). Whenever the scheduler feels right, it will call the loop-function of the element again. The Bytestream Object A second type of elements that wants to be loop-based, are the so-called bytestream-elements. Until now, we've only dealt with elements that receive or pull full buffers of a random size from other elements. Often, however, it is wanted to have control over the stream at a byte-level, such as in stream parsers or demuxers. It is possible to manually pull buffers and merge them until a certain size; it is easier, however, to use bytestream, which wraps this behaviour. To use bytestream, you need to load the bytestream when your plugin is loaded; you should do this before registering the element, which you learned previously in . After that, all functions of the bytestream plugin are available in your plugin as well. #include <gst/bytestream/bytestream.h> static gboolean plugin_init (GstPlugin *plugin) { if (!gst_library_load ("gstbytestream")) return FALSE; /* and now, actually register the element */ [..] } Bytestream-using elements are usually stream parsers or demuxers. For now, we will take a parser as an example. Demuxers require some more magic that will be dealt with later in this guide: . The goal of this parser will be to parse a text-file and to push each line of text as a separate buffer over its source pad. static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); gint n, num; guint8 *data; for (n = 0; ; n++) { num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1); if (num != n + 1) { GstEvent *event = NULL; guint remaining; gst_bytestream_get_status (filter->bs, &remaining, &event); if (event) { if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)) { /* end-of-file */ gst_pad_push (filter->srcpad, GST_DATA (event)); gst_element_set_eos (element); return; } gst_event_unref (event); } /* failed to read - throw error and bail out */ gst_element_error (element, STREAM, READ, (NULL), (NULL)); return; } /* check if the last character is a newline */ if (data[n] == '\n') { GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); /* read the line of text without newline - then flush the newline */ gst_bytestream_peek_data (filter->bs, &data, n); memcpy (GST_BUFFER_DATA (buf), data, n); GST_BUFFER_DATA (buf)[n] = '\0'; gst_bytestream_flush_fast (filter->bs, n + 1); g_print ("Pushing '%s'\n", GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); return; } } } static void gst_my_filter_change_state (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_READY_TO_PAUSED: filter->bs = gst_bytestream_new (filter->sinkpad); break; case GST_STATE_PAUSED_TO_READY: gst_bytestream_destroy (filter->bs); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } In the above example, you'll notice how bytestream handles buffering of data for you. The result is that you can handle the same data multiple times. Event handling in bytestream is currently sort of wacky, but it works quite well. The one big disadvantage of bytestream is that it requires the element to be loop-based. Long-term, we hope to have a chain-based usable version of bytestream, too. Adding a second output WRITEME Modifying the test application WRITEME Types and Properties There is a very large set of possible types that may be used to pass data between elements. Indeed, each new element that is defined may use a new data format (though unless at least one other element recognises that format, it will be most likely be useless since nothing will be able to link with it). In order for types to be useful, and for systems like autopluggers to work, it is necessary that all elements agree on the type definitions, and which properties are required for each type. The GStreamer framework itself simply provides the ability to define types and parameters, but does not fix the meaning of types and parameters, and does not enforce standards on the creation of new types. This is a matter for a policy to decide, not technical systems to enforce. For now, the policy is simple: Do not create a new type if you could use one which already exists. If creating a new type, discuss it first with the other GStreamer developers, on at least one of: IRC, mailing lists. Try to ensure that the name for a new format is as unlikely to conflict with anything else created already, and is not a more generalised name than it should be. For example: "audio/compressed" would be too generalised a name to represent audio data compressed with an mp3 codec. Instead "audio/mp3" might be an appropriate name, or "audio/compressed" could exist and have a property indicating the type of compression used. Ensure that, when you do create a new type, you specify it clearly, and get it added to the list of known types so that other developers can use the type correctly when writing their elements. Building a Simple Format for Testing If you need a new format that has not yet been defined in our , you will want to have some general guidelines on mimetype naming, properties and such. A mimetype would ideally be one defined by IANA; else, it should be in the form type/x-name, where type is the sort of data this mimetype handles (audio, video, ...) and name should be something specific for this specific type. Audio and video mimetypes should try to support the general audio/video properties (see the list), and can use their own properties, too. To get an idea of what properties we think are useful, see (again) the list. Take your time to find the right set of properties for your type. There is no reason to hurry. Also, experimenting with this is generally a good idea. Experience learns that theoretically thought-out types are good, but they still need practical use to assure that they serve their needs. Make sure that your property names do not clash with similar properties used in other types. If they match, make sure they mean the same thing; properties with different types but the same names are not allowed. Typefind Functions and Autoplugging With only defining the types, we're not yet there. In order for a random data file to be recognized and played back as such, we need a way of recognizing their type out of the blue. For this purpose, typefinding was introduced. Typefinding is the process of detecting the type of a datastream. Typefinding consists of two separate parts: first, there's an unlimited number of functions that we call typefind functions, which are each able to recognize one or more types from an input stream. Then, secondly, there's a small engine which registers and calls each of those functions. This is the typefind core. On top of this typefind core, you would normally write an autoplugger, which is able to use this type detection system to dynamically build a pipeline around an input stream. Here, we will focus only on typefind functions. A typefind function ususally lives in gst-plugins/gst/typefind/gsttypefindfunctions.c, unless there's a good reason (like library dependencies) to put it elsewhere. The reason for this centralization is to decreate the number of plugins that need to be loaded in order to detect a stream's type. Below is an example that will recognize AVI files, which start with a RIFF tag, then the size of the file and then an AVI tag: static void gst_my_typefind_function (GstTypeFind *tf, gpointer data) { guint8 *data = gst_type_find_peek (tf, 0, 12); if (data && GUINT32_FROM_LE (&((guint32 *) data)[0]) == GST_MAKE_FOURCC ('R','I','F','F') && GUINT32_FROM_LE (&((guint32 *) data)[2]) == GST_MAKE_FOURCC ('A','V','I',' ')) { gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, gst_caps_new_simple ("video/x-msvideo", NULL)); } } static gboolean plugin_init (GstPlugin *plugin) { static gchar *exts[] = { "avi", NULL }; if (!gst_type_find_register (plugin, "", GST_RANK_PRIMARY, gst_my_typefind_function, exts, gst_caps_new_simple ("video/x-msvideo", NULL), NULL)) return FALSE; } Note that gst-plugins/gst/typefind/gsttypefindfunctions.c has some simplification macros to decrease the amount of code. Make good use of those if you want to submit typefinding patches with new typefind functions. Autoplugging will be discussed in great detail in the chapter called . List of Defined Types Below is a list of all the defined types in GStreamer. They are split up in separate tables for audio, video, container, subtitle and other types, for the sake of readability. Below each table might follow a list of notes that apply to that table. In the definition of each type, we try to follow the types and rules as defined by IANA for as far as possible. Jump directly to a specific table: Note that many of the properties are not required, but rather optional properties. This means that most of these properties can be extracted from the container header, but that - in case the container header does not provide these - they can also be extracted by parsing the stream header or the stream content. The policy is that your element should provide the data that it knows about by only parsing its own content, not another element's content. Example: the AVI header provides samplerate of the contained audio stream in the header. MPEG system streams don't. This means that an AVI stream demuxer would provide samplerate as a property for MPEG audio streams, whereas an MPEG demuxer would not. A decoder needing this data would require a stream parser in between two extract this from the header or calculate it from the stream. Table of Audio TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description All audio types. audio/* All audio types rateintegergreater than 0 The sample rate of the data, in samples (per channel) per second. channelsintegergreater than 0 The number of channels of audio data. All raw audio types. audio/x-raw-int Unstructured and uncompressed raw fixed-integer audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). signedbooleanTRUE or FALSE Whether the values of the integer samples are signed or not. Signed samples use one bit to indicate sign (negative or positive) of the value. Unsigned samples are always positive. widthintegergreater than 0 Number of bits allocated per sample. depthintegergreater than 0 The number of bits used per sample. This must be less than or equal to the width: If the depth is less than the width, the low bits are assumed to be the ones used. For example, a width of 32 and a depth of 24 means that each sample is stored in a 32 bit word, but only the low 24 bits are actually used. audio/x-raw-float Unstructured and uncompressed raw floating-point audio data. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). widthintegergreater than 0 The amount of bits used and allocated per sample. buffer-framesintegerAny The number of frames per buffer. The reason for this property is that the element does not need to reuse buffers or use data spanned over multiple buffers, so this property - when used rightly - will decrease latency. Note that some people think that this property is very ugly, whereas others think it is vital for the use of GStreamer in professional audio applications. The special value zero is reserved and implies that size is variable between buffers. All encoded audio types. audio/x-ac3AC-3 or A52 audio streams. There are currently no specific properties defined or needed for this type. audio/x-adpcmADPCM Audio streams.layoutstring quicktime, dvi, microsoft or 4xm. The layout defines the packing of the samples in the stream. In ADPCM, most formats store multiple samples per channel together. This number of samples differs per format, hence the different layouts. On the long term, we probably want this variable to die and use something more descriptive, but this will do for now. block_aligninteger Any Chunk buffer size. audio/x-cinepakAudio as provided in a Cinepak (Quicktime) stream. There are currently no specific properties defined or needed for this type. audio/x-dvAudio as provided in a Digital Video stream. There are currently no specific properties defined or needed for this type. audio/x-flacFree Lossless Audio codec (FLAC). There are currently no specific properties defined or needed for this type. audio/x-gsmData encoded by the GSM codec. There are currently no specific properties defined or needed for this type. audio/x-alawA-Law Audio. There are currently no specific properties defined or needed for this type. audio/x-mulawMu-Law Audio. There are currently no specific properties defined or needed for this type. audio/x-maceMACE Audio (used in Quicktime).maceversioninteger3 or 6 The version of the MACE audio codec used to encode the stream. audio/mpeg Audio data compressed using the MPEG audio encoding scehem. mpegversioninteger1, 2 or 4 The MPEG-version used for encoding the data. The value 1 refers to MPEG-1, -2 and -2.5 layer 1, 2 or 3. The values 2 and 4 refer to the MPEG-AAC audio encoding schemes. framedboolean0 or 1 A true value indicates that each buffer contains exactly one frame. A false value indicates that frames and buffers do not necessarily match up. layerinteger1, 2, or 3 The compression scheme layer used to compress the data (only if mpegversion=1). bitrateintegergreater than 0 The bitrate, in bits per second. For VBR (variable bitrate) MPEG data, this is the average bitrate. audio/x-qdm2Data encoded by the QDM version 2 codec. There are currently no specific properties defined or needed for this type. audio/x-pn-realaudioRealmedia Audio data.raversioninteger1 or 2 The version of the Real Audio codec used to encode the stream. 1 stands for a 14k4 stream, 2 stands for a 28k8 stream. audio/x-speexData encoded by the Speex audio codec There are currently no specific properties defined or needed for this type. audio/x-vorbisVorbis audio data There are currently no specific properties defined or needed for this type. audio/x-wmaWindows Media Audiowmaversioninteger1,2 or 3 The version of the WMA codec used to encode the stream. audio/x-parisEnsoniq PARIS audio There are currently no specific properties defined or needed for this type. audio/x-svxAmiga IFF / SVX8 / SV16 audio There are currently no specific properties defined or needed for this type. audio/x-nistSphere NIST audio There are currently no specific properties defined or needed for this type. audio/x-vocSound Blaster VOC audio There are currently no specific properties defined or needed for this type. audio/x-ircamBerkeley/IRCAM/CARL audio There are currently no specific properties defined or needed for this type. audio/x-w64Sonic Foundry's 64 bit RIFF/WAV There are currently no specific properties defined or needed for this type. Table of Video TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description All video types. video/* All video types widthintegergreater than 0The width of the video imageheightintegergreater than 0The height of the video imageframeratedoublegreater than 0 The (average) framerate in frames per second. Note that this property does not guarantee in any way that it will actually come close to this value. If you need a fixed framerate, please use an element that provides that (such as videodrop). All raw video types. video/x-raw-yuvYUV (or Y'Cb'Cr) video format.formatfourcc YUY2, YVYU, UYVY, Y41P, IYU2, Y42B, YV12, I420, Y41B, YUV9, YVU9, Y800 The layout of the video. See FourCC definition site for references and definitions. YUY2, YVYU and UYVY are 4:2:2 packed-pixel, Y41P is 4:1:1 packed-pixel and IYU2 is 4:4:4 packed-pixel. Y42B is 4:2:2 planar, YV12 and I420 are 4:2:0 planar, Y41B is 4:1:1 planar and YUV9 and YVU9 are 4:1:0 planar. Y800 contains Y-samples only (black/white). video/x-raw-rgbRed-Green-Blue (RBG) video.bppintegergreater than 0 The number of bits allocated per pixel. This is usually 16, 24 or 32. depthintegergreater than 0 The number of bits used per pixel by the R/G/B components. This is usually 15, 16 or 24. endiannessintegerG_BIG_ENDIAN (1234) or G_LITTLE_ENDIAN (4321) The order of bytes in a sample. The value G_LITTLE_ENDIAN (4321) means little-endian (byte-order is least significant byte first). The value G_BIG_ENDIAN (1234) means big-endian (byte order is most significant byte first). For 24/32bpp, this should always be big endian because the byte order can be given in both. red_mask, green_mask and blue_maskintegerany The masks that cover all the bits used by each of the samples. The mask should be given in the endianness specified above. This means that for 24/32bpp, the masks might be opposite to host byte order (if you are working on little-endian computers). All encoded video types. video/x-3ivx3ivx video. There are currently no specific properties defined or needed for this type. video/x-divxDivX video.divxversioninteger3, 4 or 5 Version of the DivX codec used to encode the stream. video/x-dxDigital Video.systemstreambooleanFALSE Indicates that this stream is not a system container stream. video/x-ffvFFMpeg video.ffvversioninteger1 Version of the FFMpeg video codec used to encode the stream. video/x-h263H-263 video. There are currently no specific properties defined or needed for this type. video/x-h264H-264 video. There are currently no specific properties defined or needed for this type. video/x-huffyuvHuffyuv video. There are currently no specific properties defined or needed for this type. video/x-indeoIndeo video.indeoversioninteger3 Version of the Indeo codec used to encode this stream. video/x-jpegMotion-JPEG video. There are currently no specific properties defined or needed for this type. Note that video/x-jpeg only applies to Motion-JPEG pictures (YUY2 colourspace). RGB colourspace JPEG images are referred to as image/jpeg (JPEG image). video/mpegMPEG video.mpegversioninteger1, 2 or 4 Version of the MPEG codec that this stream was encoded with. Note that we have different mimetypes for 3ivx, XviD, DivX and "standard" ISO MPEG-4. This is not a good thing and we're fully aware of this. However, we do not have a solution yet. systemstreambooleanFALSE Indicates that this stream is not a system container stream. video/x-msmpegMicrosoft MPEG-4 video deviations.msmpegversioninteger41, 42 or 43 Version of the MS-MPEG-4-like codec that was used to encode this version. A value of 41 refers to MS MPEG 4.1, 42 to 4.2 and 43 to version 4.3. video/x-msvideocodecMicrosoft Video 1 (oldish codec).msvideoversioninteger1 Version of the codec - always 1. video/x-pn-realvideoRealmedia video.rmversioninteger1, 2 or 3 Version of the Real Video codec that this stream was encoded with. video/x-rleRLE animation format.layoutstring"microsoft" or "quicktime" The RLE format inside the Microsoft AVI container has a different byte layout than the RLE format inside Apple's Quicktime container; this property keeps track of the layout. depthinteger1 to 64 Bitdepth of the used palette. This means that the palette that belongs to this format defines 2^depth colors. palette_dataGstBuffer Buffer containing a color palette (in native-endian RGBA) used by this format. The buffer is of size 4*2^depth. video/x-svqSorensen Video.svqversioninteger1 or 3 Version of the Sorensen codec that the stream was encoded with. video/x-tarkinTarkin video. There are currently no specific properties defined or needed for this type. video/x-theoraTheora video. There are currently no specific properties defined or needed for this type. video/x-vp3VP-3 video. There are currently no specific properties defined or needed for this type. Note that we have different mimetypes for VP-3 and Theora, which is not necessarily a good idea. This could probably be improved. video/x-wmvWindows Media Videowmvversioninteger1,2 or 3 Version of the WMV codec that the stream was encoded with. video/x-xvidXviD video. There are currently no specific properties defined or needed for this type. All image types. image/jpegJoint Picture Expert Group Image. There are currently no specific properties defined or needed for this type. Note that image/jpeg only applies to RGB-colourspace JPEG images; YUY2-colourspace JPEG pictures are referred to as video/x-jpeg ("Motion JPEG"). image/pngPortable Network Graphics Image. There are currently no specific properties defined or needed for this type. Table of Container TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Descriptionvideo/x-ms-asfAdvanced Streaming Format (ASF). There are currently no specific properties defined or needed for this type. video/x-msvideoAVI. There are currently no specific properties defined or needed for this type. video/x-dvDigital Video.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. video/x-matroskaMatroska. There are currently no specific properties defined or needed for this type. video/mpegMotion Pictures Expert Group System Stream.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. application/oggOgg. There are currently no specific properties defined or needed for this type. video/quicktimeQuicktime. There are currently no specific properties defined or needed for this type. video/x-pn-realvideoDigital Video.systemstreambooleanTRUE Indicates that this is a container system stream rather than an elementary video stream. audio/x-wavWAV. There are currently no specific properties defined or needed for this type. Table of Subtitle TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description None defined yet. Table of Other TypesMime TypeDescriptionPropertyProperty TypeProperty ValuesProperty Description None defined yet. Request and Sometimes pads Until now, we've only dealt with pads that are always available. However, there's also pads that are only being created in some cases, or only if the application requests the pad. The first is called a sometimes; the second is called a request pad. The availability of a pad (always, sometimes or request) can be seen in a pad's template. This chapter will discuss when each of the two is useful, how they are created and when they should be disposed. Sometimes pads A sometimes pad is a pad that is created under certain conditions, but not in all cases. This mostly depends on stream content: demuxers will generally parse the stream header, decide what elementary (video, audio, subtitle, etc.) streams are embedded inside the system stream, and will then create a sometimes pad for each of those elementary streams. At its own choice, it can also create more than one instance of each of those per element instance. The only limitation is that each newly created pad should have a unique name. Sometimes pads are disposed when the stream data is disposed, too (i.e. when going from PAUSED to the READY state). You should not dispose the pad on EOS, because someone might re-activate the pipeline and seek back to before the end-of-stream point. The stream should still stay valid after EOS, at least until the stream data is disposed. In any case, the element is always the owner of such a pad. The example code below will parse a text file, where the first line is a number (n). The next lines all start with a number (0 to n-1), which is the number of the source pad over which the data should be sent. 3 0: foo 1: bar 0: boo 2: bye The code to parse this file and create the dynamic sometimes pads, looks like this: typedef struct _GstMyFilter { [..] gboolean firstrun; GList *srcpadlist; } GstMyFilter; static void gst_my_filter_base_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ( "src_%02d", GST_PAD_SRC, GST_PAD_SOMETIMES, GST_STATIC_CAPS ("ANY") ); [..] gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); [..] } static void gst_my_filter_init (GstMyFilter *filter) { [..] filter->firstrun = TRUE; filter->srcpadlist = NULL; } /* * Get one line of data - without newline. */ static GstBuffer * gst_my_filter_getline (GstMyFilter *filter) { guint8 *data; gint n, num; /* max. line length is 512 characters - for safety */ for (n = 0; n < 512; n++) { num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1); if (num != n + 1) return NULL; /* newline? */ if (data[n] == '\n') { GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); gst_bytestream_peek_bytes (filter->bs, &data, n); memcpy (GST_BUFFER_DATA (buf), data, n); GST_BUFFER_DATA (buf)[n] = '\0'; gst_bytestream_flush_fast (filter->bs, n + 1); return buf; } } } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstBuffer *buf; GstPad *pad; gint num, n; /* parse header */ if (filter->firstrun) { GstElementClass *klass; GstPadTemplate *templ; gchar *padname; if (!(buf = gst_my_filter_getline (filter))) { gst_element_error (element, STREAM, READ, (NULL), ("Stream contains no header")); return; } num = atoi (GST_BUFFER_DATA (buf)); gst_buffer_unref (buf); /* for each of the streams, create a pad */ klass = GST_ELEMENT_GET_CLASS (filter); templ = gst_element_class_get_pad_template (klass, "src_%02d"); for (n = 0; n < num; n++) { padname = g_strdup_printf ("src_%02d", n); pad = gst_pad_new_from_template (templ, padname); g_free (padname); /* here, you would set _getcaps () and _link () functions */ gst_element_add_pad (element, pad); filter->srcpadlist = g_list_append (filter->srcpadlist, pad); } } /* and now, simply parse each line and push over */ if (!(buf = gst_my_filter_getline (filter))) { GstEvent *event = gst_event_new (GST_EVENT_EOS); GList *padlist; for (padlist = srcpadlist; padlist != NULL; padlist = g_list_next (padlist)) { pad = GST_PAD (padlist->data); gst_event_ref (event); gst_pad_push (pad, GST_DATA (event)); } gst_event_unref (event); gst_element_set_eos (element); return; } /* parse stream number and go beyond the ':' in the data */ num = atoi (GST_BUFFER_DATA (buf)); if (num >= 0 && num < g_list_length (filter->srcpadlist)) { pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num); /* magic buffer parsing foo */ for (n = 0; GST_BUFFER_DATA (buf)[n] != ':' && GST_BUFFER_DATA (buf)[n] != '\0'; n++) ; if (GST_BUFFER_DATA (buf)[n] != '\0') { GstBuffer *sub; /* create subbuffer that starts right past the space. The reason * that we don't just forward the data pointer is because the * pointer is no longer the start of an allocated block of memory, * but just a pointer to a position somewhere in the middle of it. * That cannot be freed upon disposal, so we'd either crash or have * a memleak. Creating a subbuffer is a simple way to solve that. */ sub = gst_buffer_create_sub (buf, n + 1, GST_BUFFER_SIZE (buf) - n - 1); gst_pad_push (pad, GST_DATA (sub)); } } gst_buffer_unref (buf); } Note that we use a lot of checks everywhere to make sure that the content in the file is valid. This has two purposes: first, the file could be erronous, in which case we prevent a crash. The second and most important reason is that - in extreme cases - the file could be used maliciously to cause undefined behaviour in the plugin, which might lead to security issues. Always assume that the file could be used to do bad things. Request pads Request pads are similar to sometimes pads, except that request are created on demand of something outside of the element rather than something inside the element. This concept is often used in muxers, where - for each elementary stream that is to be placed in the output system stream - one sink pad will be requested. It can also be used in elements with a variable number of input or outputs pads, such as the tee (multi-output), switch or aggregator (both multi-input) elements. At the time of writing this, it is unclear to me who is responsible for cleaning up the created pad and how or when that should be done. Below is a simple example of an aggregator based on request pads. static GstPad * gst_my_filter_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name); static void gst_my_filter_base_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( "sink_%d", GST_PAD_SINK, GST_PAD_REQUEST, GST_STATIC_CAPS ("ANY") ); [..] gst_element_class_add_pad_template (klass, gst_static_pad_template_get (&sink_factory)); } static void gst_my_filter_class_init (GstMyFilterClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); [..] element_class->request_new_pad = gst_my_filter_request_new_pad; } static GstPad * gst_my_filter_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name) { GstPad *pad; GstMyFilterInputContext *context; context = g_new0 (GstMyFilterInputContext, 1); pad = gst_pad_new_from_template (templ, name); gst_element_set_private_data (pad, context); /* normally, you would set _link () and _getcaps () functions here */ gst_element_add_pad (element, pad); return pad; } The _loop () function is the same as the one given previously in . Clocking When playing complex media, each sound and video sample must be played in a specific order at a specific time. For this purpose, GStreamer provides a syncrhonization mechanism. Types of time There are two kinds of time in GStreamer. Clock time is an absolute time. By contrast, element time is the relative time, usually to the start of the current media stream. The element time represents the time that should have a media sample that is being processed by the element at this time. The element time is calculated by adding an offset to the clock time. Clocks GStreamer can use different clocks. Though the system time can be used as a clock, soundcards and other devices provides a better time source. For this reason some elements provide a clock. The method get_clock is implemented in elements that provide one. As clocks return an absolute measure of time, they are not usually used directly. Instead, a reference to a clock is stored in any element that needs it, and it is used internaly by GStreamer to calculate the element time. Flow of data between elements and time Now we will see how time information travels the pipeline in different states. The pipeline starts playing. The source element typically knows the time of each sample. Sometimes it is a parser element the one that knows the time, for instance if a pipeline contains a filesrc element connected to a MPEG decoder element, the former is the one that knows the time of each sample, because the knowledge of when to play each sample is embedded in the MPEG format. In this case this element will be regarded as the source element for this discussion. First, the source element sends a discontinous event. This event carries information about the current relative time of the next sample. This relative time is arbitrary, but it must be consistent with the timestamp that will be placed in buffers. It is expected to be the relative time to the start of the media stream, or whatever makes sense in the case of each media. When receiving it, the other elements adjust their offset of the element time so that this time matches the time written in the event. Then the source element sends media samples in buffers. This element places a timestamp in each buffer saying when the sample should be played. When the buffer reachs the sink pad of the last element, this element compares the current element time with the timestamp of the buffer. If the timestamp is higher or equal it plays the buffer, otherwise it waits until the time to place the buffer arrives with gst_element_wait(). If the stream is seeked, the next samples sent will have a timestamp that is not adjusted with the element time. Therefore, the source element must send a discontinous event. Obligations of each element. Let us clarify the contract between GStreamer and each element in the pipeline. Source elements Source elements (or parsers of formats that provide notion of time, such as MPEG, as explained above) must place a timestamp in each buffer that they deliver. The origin of the time used is arbitrary, but it must match the time delivered in the discontinous event (see below). However, it is expected that the origin is the origin of the media stream. In order to initialize the element time of the rest of the pipeline, a source element must send a discontinous event before starting to play. In addition, after seeking, a discontinious event must be sent, because the timestamp of the next element does not match the element time of the rest of the pipeline. Sink elements If the element is intended to emit samples at a specific time (real time playing), the element should require a clock, and thus implement the method set_clock. In addition, before playing each sample, if the current element time is less than the timestamp in the sample, it wait until the current time arrives should call gst_element_wait() With some schedulers, gst_element_wait() blocks the pipeline. For instance, if there is one audio sink element and one video sink element, while the audio element is waiting for a sample the video element cannot play other sample. This behaviour is under discussion, and might change in a future release. See an example in Supporting Dynamic Parameters Sometimes object properties are not powerful enough to control the parameters that affect the behaviour of your element. When this is the case you can expose these parameters as Dynamic Parameters which can be manipulated by any Dynamic Parameters aware application. Throughout this section, the term dparams will be used as an abbreviation for "Dynamic Parameters". Comparing Dynamic Parameters with GObject Properties Your first exposure to dparams may be to convert an existing element from using object properties to using dparams. The following table gives an overview of the difference between these approaches. The significance of these differences should become apparent later on. Object PropertiesDynamic ParametersParameter definitionClass level at compile timeAny level at run timeGetting and settingImplemented by element subclass as functionsHandled entirely by dparams subsystemExtra objects requiredNone - all functionality is derived from base GObjectElement needs to create and store a GstDParamManager at object creationFrequency and resolution of updatesObject properties will only be updated between calls to _get, _chain or _loopdparams can be updated at any rate independent of calls to _get, _chain or _loop up to sample-level accuracyGetting Started The dparams subsystem is contained within the gstcontrol library. You need to include the header in your element's source file: #include <gst/control/control.h> Even though the gstcontrol library may be linked into the host application, you should make sure it is loaded in your plugin_init function: static gboolean plugin_init (GModule *module, GstPlugin *plugin) { ... /* load dparam support library */ if (!gst_library_load ("gstcontrol")) { gst_info ("example: could not load support library: 'gstcontrol'\n"); return FALSE; } ... } You need to store an instance of GstDParamManager in your element's struct: struct _GstExample { GstElement element; ... GstDParamManager *dpman; ... }; The GstDParamManager can be initialised in your element's init function: static void gst_example_init (GstExample *example) { ... example->dpman = gst_dpman_new ("example_dpman", GST_ELEMENT(example)); ... } Defining Parameter Specifications You can define the dparams you need anywhere within your element but will usually need to do so in only a couple of places: In the element init function, just after the call to gst_dpman_new Whenever a new pad is created so that parameters can affect data going into or out of a specific pad. An example of this would be a mixer element where a separate volume parameter is needed on every pad. There are three different ways the dparams subsystem can pass parameters into your element. Which one you use will depend on how that parameter is used within your element. Each of these methods has its own function to define a required dparam: gst_dpman_add_required_dparam_directgst_dpman_add_required_dparam_callbackgst_dpman_add_required_dparam_array These functions will return TRUE if the required dparam was added successfully. The following function will be used as an example. gboolean gst_dpman_add_required_dparam_direct (GstDParamManager *dpman, GParamSpec *param_spec, gboolean is_log, gboolean is_rate, gpointer update_data) The common parameters to these functions are: GstDParamManager *dpman the element's dparam manager GParamSpec *param_spec the param spec which defines the required dparam gboolean is_log whether this dparam value should be interpreted on a log scale (such as a frequency or a decibel value) gboolean is_rate whether this dparam value is a proportion of the sample rate. For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz. Direct Method This method is the simplest and has the lowest overhead for parameters which change less frequently than the sample rate. First you need somewhere to store the parameter - this will usually be in your element's struct. struct _GstExample { GstElement element; ... GstDParamManager *dpman; gfloat volume; ... }; Then to define the required dparam just call gst_dpman_add_required_dparam_direct and pass in the location of the parameter to change. In this case the location is &(example->volume). gst_dpman_add_required_dparam_direct ( example->dpman, g_param_spec_float("volume","Volume","Volume of the audio", 0.0, 1.0, 0.8, G_PARAM_READWRITE), FALSE, FALSE, &(example->volume) ); You can now use example->volume anywhere in your element knowing that it will always contain the correct value to use. Callback Method This should be used if the you have other values to calculate whenever a parameter changes. If you used the direct method you wouldn't know if a parameter had changed so you would have to recalculate the other values every time you needed them. By using the callback method, other values only have to be recalculated when the dparam value actually changes. The following code illustrates an instance where you might want to use the callback method. If you had a volume dparam which was represented by a gfloat number, your element may only deal with integer arithmetic. The callback could be used to calculate the integer scaler when the volume changes. First you will need somewhere to store these values. struct _GstExample { GstElement element; ... GstDParamManager *dpman; gfloat volume_f; gint volume_i; ... }; When the required dparam is defined, the callback function gst_example_update_volume and some user data (which in this case is our element instance) is passed in to the call to gst_dpman_add_required_dparam_callback. gst_dpman_add_required_dparam_callback ( example->dpman, g_param_spec_float("volume","Volume","Volume of the audio", 0.0, 1.0, 0.8, G_PARAM_READWRITE), FALSE, FALSE, gst_example_update_volume, example ); The callback function needs to conform to this signature typedef void (*GstDPMUpdateFunction) (GValue *value, gpointer data); In our example the callback function looks like this static void gst_example_update_volume(GValue *value, gpointer data) { GstExample *example = (GstExample*)data; g_return_if_fail(GST_IS_EXAMPLE(example)); example->volume_f = g_value_get_float(value); example->volume_i = example->volume_f * 8192; } Now example->volume_i can be used elsewhere and it will always contain the correct value. Array Method This method is quite different from the other two. It could be thought of as a specialised method which should only be used if you need the advantages that it provides. Instead of giving the element a single value it provides an array of values where each item in the array corresponds to a sample of audio in your buffer. There are a couple of reasons why this might be useful. Certain optimisations may be possible since you can iterate over your dparams array and your buffer data together. Some dparams may be able to interpolate changing values at the sample rate. This would allow the array to contain very smoothly changing values which may be required for the stability and quality of some DSP algorithms. The array method is currently the least mature of the three methods and is not yet ready to be used in elements, but plugin writers should be aware of its existence for the future. The Data Processing Loop This is the most critical aspect of the dparams subsystem as it relates to elements. In a traditional audio processing loop, a for loop will usually iterate over each sample in the buffer, processing one sample at a time until the buffer is finished. A simplified loop with no error checking might look something like this. static void example_chain (GstPad *pad, GstBuffer *buf) { ... gfloat *float_data; int j; GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad)); int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat); float_data = (gfloat *)GST_BUFFER_DATA(buf); ... for (j = 0; j < num_samples; j++) { float_data[j] *= example->volume; } ... } To make this dparams aware, a couple of changes are needed. static void example_chain (GstPad *pad, GstBuffer *buf) { ... int j = 0; GstExample *example = GST_EXAMPLE(GST_OBJECT_PARENT (pad)); int num_samples = GST_BUFFER_SIZE(buf)/sizeof(gfloat); gfloat *float_data = (gfloat *)GST_BUFFER_DATA(buf); int frame_countdown = GST_DPMAN_PREPROCESS(example->dpman, num_samples, GST_BUFFER_TIMESTAMP(buf)); ... while (GST_DPMAN_PROCESS_COUNTDOWN(example->dpman, frame_countdown, j)) { float_data[j++] *= example->volume; } ... } The biggest changes here are 2 new macros, GST_DPMAN_PREPROCESS and GST_DPMAN_PROCESS_COUNTDOWN. You will also notice that the for loop has become a while loop. GST_DPMAN_PROCESS_COUNTDOWN is called as the condition for the while loop so that any required dparams can be updated in the middle of a buffer if required. This is because one of the required behaviours of dparams is that they can be sample accurate. This means that parameters change at the exact timestamp that they are supposed to - not after the buffer has finished being processed. It may be alarming to see a macro as the condition for a while loop, but it is actually very efficient. The macro expands to the following. #define GST_DPMAN_PROCESS_COUNTDOWN(dpman, frame_countdown, frame_count) \ (frame_countdown-- || \ (frame_countdown = GST_DPMAN_PROCESS(dpman, frame_count))) So as long as frame_countdown is greater than 0, GST_DPMAN_PROCESS will not be called at all. Also in many cases, GST_DPMAN_PROCESS will do nothing and simply return 0, meaning that there is no more data in the buffer to process. The macro GST_DPMAN_PREPROCESS will do the following: Update any dparams which are due to be updated. Calculate how many samples should be processed before the next required update Return the number of samples until next update, or the number of samples in the buffer - whichever is less. In fact GST_DPMAN_PROCESS may do the same things as GST_DPMAN_PREPROCESS depending on the mode that the dparam manager is running in (see below). DParam Manager Modes A brief explanation of dparam manager modes might be useful here even though it doesn't generally affect the way your element is written. There are different ways media applications will be used which require that an element's parameters be updated in differently. These include: Timelined - all parameter changes are known in advance before the pipeline is run. Realtime low-latency - Nothing is known ahead of time about when a parameter might change. Changes need to be propagated to the element as soon as possible. When a dparam-aware application gets the dparam manager for an element, the first thing it will do is set the dparam manager mode. Current modes are "synchronous" and "asynchronous". If you are in a realtime low-latency situation then the "synchronous" mode is appropriate. During GST_DPMAN_PREPROCESS this mode will poll all dparams for required updates and propagate them. GST_DPMAN_PROCESS will do nothing in this mode. To then achieve the desired latency, the size of the buffers needs to be reduced so that the dparams will be polled for updates at the desired frequency. In a timelined situation, the "asynchronous" mode will be required. This mode hasn't actually been implemented yet but will be described anyway. The GST_DPMAN_PREPROCESS call will precalculate when and how often each dparam needs to update for the duration of the current buffer. From then on GST_DPMAN_PROCESS will propagate the calculated updates each time it is called until end of the buffer. If the application is rendering to disk in non-realtime, the render could be sped up by increasing the buffer size. In the "asynchronous" mode this could be done without affecting the sample accuracy of the parameter updates Dynamic Parameters for Video All of the explanation so far has presumed that the buffer contains audio data with many samples. Video should be regarded differently since a video buffer often contains only 1 frame. In this case some of the complexity of dparams isn't required but the other benefits still make it useful for video parameters. If a buffer only contains one frame of video, only a single call to GST_DPMAN_PREPROCESS should be required. For more than one frame per buffer, treat it the same as the audio case. MIDI WRITEME Interfaces Previously, in the chapter , we have introduced the concept of GObject properties of controlling an element's behaviour. This is very powerful, but it has two big disadvantages: first of all, it is too generic, and second, it isn't dynamic. The first disadvantage is related to the customizability of the end-user interface that will be built to control the element. Some properties are more important than others. Some integer properties are better shown in a spin-button widget, whereas others would be better represented by a slider widget. Such things are not possible because the UI has no actual meaning in the application. A UI widget that represents a bitrate property is the same as a UI widget that represents the size of a video, as long as both are of the same GParamSpec type. Another problem, is that things like parameter grouping, function grouping, or parameter coupling are not really possible. The second problem with parameters are that they are not dynamic. In many cases, the allowed values for a property are not fixed, but depend on things that can only be detected at runtime. The names of inputs for a TV card in a video4linux source element, for example, can only be retrieved from the kernel driver when we've opened the device; this only happens when the element goes into the READY state. This means that we cannot create an enum property type to show this to the user. The solution to those problems is to create very specialized types of controls for certain often-used controls. We use the concept of interfaces to achieve this. The basis of this all is the glib GTypeInterface type. For each case where we think it's useful, we've created interfaces which can be implemented by elements at their own will. We've also created a small extension to GTypeInterface (which is static itself, too) which allows us to query for interface availability based on runtime properties. This extension is called GstImplementsInterface. One important note: interfaces do not replace properties. Rather, interfaces should be built next to properties. There are two important reasons for this. First of all, properties can be saved in XML files. Second, properties can be specified on the commandline (gst-launch). How to Implement Interfaces Implementing interfaces is intiated in the _get_type () of your element. You can register one or more interfaces after having registered the type itself. Some interfaces have dependencies on other interfaces or can only be registered by certain types of elements. You will be notified of doing that wrongly when using the element: it will quit with failed assertions, which will explain what went wrong. In the case of GStreamer, the only dependency that some interfaces have is GstImplementsInterface. Per interface, we will indicate clearly when it depends on this extension. If it does, you need to register support for that interface before registering support for the interface that you're wanting to support. The example below explains how to add support for a simple interface with no further dependencies. For a small explanation on GstImplementsInterface, see the next section about the mixer interface: . static void gst_my_filter_some_interface_init (GstSomeInterface *iface); GType gst_my_filter_get_type (void) { static GType my_filter_type = 0; if (!my_filter_type) { static const GTypeInfo my_filter_info = { sizeof (GstMyFilterClass), (GBaseInitFunc) gst_my_filter_base_init, NULL, (GClassInitFunc) gst_my_filter_class_init, NULL, NULL, sizeof (GstMyFilter), 0, (GInstanceInitFunc) gst_my_filter_init }; static const GInterfaceInfo some_interface_info = { (GInterfaceInitFunc) gst_my_filter_some_interface_init, NULL, NULL }; my_filter_type = g_type_register_static (GST_TYPE_MY_FILTER, "GstMyFilter", &my_filter_info, 0); g_type_add_interface_static (my_filter_type, GST_TYPE_SOME_INTERFACE, &some_interface_info); } return my_filter_type; } static void gst_my_filter_some_interface_init (GstSomeInterface *iface) { /* here, you would set virtual function pointers in the interface */ } Mixer Interface The goal of the mixer interface is to provide a simple yet powerful API to applications for audio hardware mixer/volume control. Most soundcards have hardware mixers, where volume can be changed, they can be muted, inputs can be modified to mix their content into what will be read from the device by applications (in our case: audio source plugins). The mixer interface is the way to control those. The mixer interface can also be used for volume control in software (e.g. the volume element). The end goal of this interface is to allow development of hardware volume control applications and for the control of audio volume and input/output settings. The mixer interface requires the GstImplementsInterface interface to be implemented by the element. The example below will feature both, so it serves as an example for the GstImplementsInterface, too. In this interface, it is required to set a function pointer for the supported () function. If you don't, this function will always return FALSE (default implementation) and the mixer interface implementation will not work. For the mixer interface, the only required function is list_tracks (). All other function pointers in the mixer interface are optional, although it is strongly recommended to set function pointers for at least the get_volume () and set_volume () functions. The API reference for this interface documents the goal of each function, so we will limit ourselves to the implementation here. The following example shows a mixer implementation for a software N-to-1 element. It does not show the actual process of stream mixing, that is far too complicated for this guide. #include <gst/mixer/mixer.h> typedef struct _GstMyFilter { [..] gint volume; GList *tracks; } GstMyFilter; static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface); static void gst_my_filter_mixer_interface_init (GstMixerClass *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo implements_interface_info = { (GInterfaceInitFunc) gst_my_filter_implements_interface_init, NULL, NULL }; static const GInterfaceInfo mixer_interface_info = { (GInterfaceInitFunc) gst_my_filter_mixer_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); g_type_add_interface_static (my_filter_type, GST_TYPE_MIXER, &mixer_interface_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GstMixerTrack *track = NULL; [..] filter->volume = 100; filter->tracks = NULL; track = g_object_new (GST_TYPE_MIXER_TRACK, NULL); track->label = g_strdup ("MyTrack"); track->num_channels = 1; track->min_volume = 0; track->max_volume = 100; track->flags = GST_MIXER_TRACK_SOFTWARE; filter->tracks = g_list_append (filter->tracks, track); } static gboolean gst_my_filter_interface_supported (GstImplementsInterface *iface, GType iface_type) { g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); /* for the sake of this example, we'll always support it. However, normally, * you would check whether the device you've opened supports mixers. */ return TRUE; } static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface) { iface->supported = gst_my_filter_interface_supported; } /* * This function returns the list of support tracks (inputs, outputs) * on this element instance. Elements usually build this list during * _init () or when going from NULL to READY. */ static const GList * gst_my_filter_mixer_list_tracks (GstMixer *mixer) { GstMyFilter *filter = GST_MY_FILTER (mixer); return filter->tracks; } /* * Set volume. volumes is an array of size track->num_channels, and * each value in the array gives the wanted volume for one channel * on the track. */ static void gst_my_filter_mixer_set_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes) { GstMyFilter *filter = GST_MY_FILTER (mixer); filter->volume = volumes[0]; g_print ("Volume set to %d\n", filter->volume); } static void gst_my_filter_mixer_get_volume (GstMixer *mixer, GstMixerTrack *track, gint *volumes) { GstMyFilter *filter = GST_MY_FILTER (mixer); volumes[0] = filter->volume; } static void gst_my_filter_mixer_interface_init (GstMixerClass *iface) { /* the mixer interface requires a definition of the mixer type: * hardware or software? */ GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE; /* virtual function pointers */ iface->list_tracks = gst_my_filter_mixer_list_tracks; iface->set_volume = gst_my_filter_mixer_set_volume; iface->get_volume = gst_my_filter_mixer_get_volume; } The mixer interface is very audio-centric. However, with the software flag set, the mixer can be used to mix any kind of stream in a N-to-1 element to join (not aggregate!) streams together into one output stream. Conceptually, that's called mixing too. You can always use the element factory's category to indicate type of your element. In a software element that mixes random streams, you would not be required to implement the _get_volume () or _set_volume () functions. Rather, you would only implement the _set_record () to enable or disable tracks in the output stream. to make sure that a mixer-implementing element is of a certain type, check the element factory's category. Tuner Interface As opposed to the mixer interface, that's used to join together N streams into one output stream by mixing all streams together, the tuner interface is used in N-to-1 elements too, but instead of mixing the input streams, it will select one stream and push the data of that stream to the output stream. It will discard the data of all other streams. There is a flag that indicates whether this is a software-tuner (in which case it is a pure software implementation, with N sink pads and 1 source pad) or a hardware-tuner, in which case it only has one source pad, and the whole stream selection process is done in hardware. The software case can be used in elements such as switch. The hardware case can be used in elements with channel selection, such as video source elements (v4lsrc, v4l2src, etc.). If you need a specific element type, use the element factory's category to make sure that the element is of the type that you need. Note that the interface itself is highly analog-video-centric. This interface requires the GstImplemensInterface interface to work correctly. The following example shows how to implement the tuner interface in an element. It does not show the actual process of stream selection, that is irrelevant for this section. #include <gst/tuner/tuner.h> typedef struct _GstMyFilter { [..] gint active_input; GList *channels; } GstMyFilter; static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface); static void gst_my_filter_tuner_interface_init (GstTunerClass *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo implements_interface_info = { (GInterfaceInitFunc) gst_my_filter_implements_interface_init, NULL, NULL }; static const GInterfaceInfo tuner_interface_info = { (GInterfaceInitFunc) gst_my_filter_tuner_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); g_type_add_interface_static (my_filter_type, GST_TYPE_TUNER, &tunerr_interface_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GstTunerChannel *channel = NULL; [..] filter->active_input = 0; filter->channels = NULL; channel = g_object_new (GST_TYPE_TUNER_CHANNEL, NULL); channel->label = g_strdup ("MyChannel"); channel->flags = GST_TUNER_CHANNEL_INPUT; filter->channels = g_list_append (filter->channels, channel); } static gboolean gst_my_filter_interface_supported (GstImplementsInterface *iface, GType iface_type) { g_return_val_if_fail (iface_type == GST_TYPE_TUNER, FALSE); /* for the sake of this example, we'll always support it. However, normally, * you would check whether the device you've opened supports tuning. */ return TRUE; } static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface) { iface->supported = gst_my_filter_interface_supported; } static const GList * gst_my_filter_tuner_list_channels (GstTuner *tuner) { GstMyFilter *filter = GST_MY_FILTER (tuner); return filter->channels; } static GstTunerChannel * gst_my_filter_tuner_get_channel (GstTuner *tuner) { GstMyFilter *filter = GST_MY_FILTER (tuner); return g_list_nth_data (filter->channels, filter->active_input); } static void gst_my_filter_tuner_set_channel (GstTuner *tuner, GstTunerChannel *channel) { GstMyFilter *filter = GST_MY_FILTER (tuner); filter->active_input = g_list_index (filter->channels, channel); g_assert (filter->active_input >= 0); } static void gst_my_filter_tuner_interface_init (GstTunerClass *iface) { iface->list_channels = gst_my_filter_tuner_list_channels; iface->get_channel = gst_my_filter_tuner_get_channel; iface->set_channel = gst_my_filter_tuner_set_channel; } As said, the tuner interface is very analog video-centric. It features functions for selecting an input or output, and on inputs, it features selection of a tuning frequency if the channel supports frequency-tuning on that input. Likewise, it allows signal-strength-acquiring if the input supports that. Frequency tuning can be used for radio or cable-TV tuning. Signal-strength is an indication of the signal and can be used for visual feedback to the user or for autodetection. Next to that, it also features norm selection, which is only useful for analog video elements. Color Balance Interface WRITEME Property Probe Interface Property probing is a generic solution to the problem that properties' value lists in an enumeration are static. We've shown enumerations in . Property probing tries to accomplish a goal similar to enumeration lists: to have a limited, explicit list of allowed values for a property. There are two differences between enumeration lists and probing. Firstly, enumerations only allow strings as values; property probing works for any value type. Secondly, the contents of a probed list of allowed values may change during the life of an element. The contents of an enumeration list are static. Currently, property probing is being used for detection of devices (e.g. for OSS elements, Video4linux elements, etc.). It could - in theory - be used for any property, though. Property probing stores the list of allowed (or recommended) values in a GValueArray and returns that to the user. NULL is a valid return value, too. The process of property probing is separated over two virtual functions: one for probing the property to create a GValueArray, and one to retrieve the current GValueArray. Those two are separated because probing might take a long time (several seconds). Also, this simpliies interface implementation in elements. For the application, there are functions that wrap those two. For more information on this, have a look at the API reference for the GstPropertyProbe interface. Below is a example of property probing for the audio filter element; it will probe for allowed values for the silent property. Indeed, this value is a gboolean so it doesn't make much sense. Then again, it's only an example. #include <gst/propertyprobe/propertyprobe.h> static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface); GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo probe_interface_info = { (GInterfaceInitFunc) gst_my_filter_probe_interface_init, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_PROPERTY_PROBE, &probe_interface_info); [..] } static const GList * gst_my_filter_probe_get_properties (GstPropertyProbe *probe) { GObjectClass *klass = G_OBJECT_GET_CLASS (probe); static GList *props = NULL; if (!props) { GParamSpec *pspec; pspec = g_object_class_find_property (klass, "silent"); props = g_list_append (props, pspec); } return props; } static gboolean gst_my_filter_probe_needs_probe (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { gboolean res = FALSE; switch (prop_id) { case ARG_SILENT: res = FALSE; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } return res; } static void gst_my_filter_probe_probe_property (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { switch (prop_id) { case ARG_SILENT: /* don't need to do much here... */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } } static GValueArray * gst_my_filter_get_silent_values (GstMyFilter *filter) { GValueArray *array = g_value_array_new (2); GValue value = { 0 }; g_value_init (&value, G_TYPE_BOOLEAN); /* add TRUE */ g_value_set_boolean (&value, TRUE); g_value_array_append (array, &value); /* add FALSE */ g_value_set_boolean (&value, FALSE); g_value_array_append (array, &value); g_value_unset (&value); return array; } static GValueArray * gst_my_filter_probe_get_values (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) { GstMyFilter *filter = GST_MY_FILTER (probe); GValueArray *array = NULL; switch (prop_id) { case ARG_SILENT: array = gst_my_filter_get_silent_values (filter); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); break; } return array; } static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface) { iface->get_properties = gst_my_filter_probe_get_properties; iface->needs_probe = gst_my_filter_probe_needs_probe; iface->probe_property = gst_my_filter_probe_probe_property; iface->get_values = gst_my_filter_probe_get_values; } You don't need to support any functions for getting or setting values. All that is handled via the standard GObject _set_property () and _get_property () functions. X Overlay Interface An X Overlay is basically a video output in a XFree86 drawable. Elements implementing this interface will draw video in a X11 window. Through this interface, applications will be proposed 2 different modes to work with a plugin implemeting it. The first mode is a passive mode where the plugin owns, creates and destroys the X11 window. The second mode is an active mode where the application handles the X11 window creation and then tell the plugin where it should output video. Let's get a bit deeper in those modes... A plugin drawing video output in a X11 window will need to have that window at one stage or another. Passive mode simply means that no window has been given to the plugin before that stage, so the plugin created the window by itself. In that case the plugin is responsible of destroying that window when it's not needed anymore and it has to tell the applications that a window has been created so that the application can use it. This is done using the have_xwindow_id signal that can be emitted from the plugin with the gst_x_overlay_got_xwindow_id method. As you probably guessed already active mode just means sending a X11 window to the plugin so that video output goes there. This is done using the gst_x_overlay_set_xwindow_id method. It is possible to switch from one mode to another at any moment, so the plugin implementing this interface has to handle all cases. There are only 2 methods that plugins writers have to implement and they most probably look like that : static void gst_my_filter_set_xwindow_id (GstXOverlay *overlay, XID xwindow_id) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); if (my_filter->window) gst_my_filter_destroy_window (my_filter->window); my_filter->window = xwindow_id; } static void gst_my_filter_get_desired_size (GstXOverlay *overlay, guint *width, guint *height) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); *width = my_filter->width; *height = my_filter->height; } static void gst_my_filter_xoverlay_init (GstXOverlayClass *iface) { iface->set_xwindow_id = gst_my_filter_set_xwindow_id; iface->get_desired_size = gst_my_filter_get_desired_size; } You will also need to use the interface methods to fire signals when needed such as in the pad link function where you will know the video geometry and maybe create the window. static MyFilterWindow * gst_my_filter_window_create (GstMyFilter *my_filter, gint width, gint height) { MyFilterWindow *window = g_new (MyFilterWindow, 1); ... gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (my_filter), window->win); } static GstPadLinkReturn gst_my_filter_sink_link (GstPad *pad, const GstCaps *caps) { GstMyFilter *my_filter = GST_MY_FILTER (overlay); gint width, height; gboolean ret; ... ret = gst_structure_get_int (structure, "width", &width); ret &= gst_structure_get_int (structure, "height", &height); if (!ret) return GST_PAD_LINK_REFUSED; if (!my_filter->window) my_filter->window = gst_my_filter_create_window (my_filter, width, height); gst_x_overlay_got_desired_size (GST_X_OVERLAY (my_filter), width, height); ... } Navigation Interface WRITEME Tagging (Metadata and Streaminfo) Tags are pieces of information stored in a stream that are not the content itself, but they rather describe the content. Most media container formats support tagging in one way or another. Ogg uses VorbisComment for this, MP3 uses ID3, AVI and WAV use RIFF's INFO list chunk, etc. GStreamer provides a general way for elements to read tags from the stream and expose this to the user. The tags (at least the metadata) will be part of the stream inside the pipeline. The consequence of this is that transcoding of files from one format to another will automatically preserve tags, as long as the input and output format elements both support tagging. Tags are separated in two categories in GStreamer, even though applications won't notice anything of this. The first are called metadata, the second are called streaminfo. Metadata are tags that describe the non-technical parts of stream content. They can be changed without needing to re-encode the stream completely. Examples are author, title or album. The container format might still need to be re-written for the tags to fit in, though. Streaminfo, on the other hand, are tags that describe the stream contents technically. To change them, the stream needs to be re-encoded. Examples are codec or bitrate. Note that some container formats (like ID3) store various streaminfo tags as metadata in the file container, which means that they can be changed so that they don't match the content in the file anymore. Still, they are called metadata because technically, they can be changed without re-encoding the whole stream, even though that makes them invalid. Files with such metadata tags will have the same tag twice: once as metadata, once as streaminfo. A tag reading element is called TagGetter in GStreamer. A tag writer is called TagSetter. An element supporting both can be used in a tag editor for quick tag changing. Reading Tags from Streams The basic object for tags is a GstTagList . An element that is reading tags from a stream should create an empty taglist and fill this with individual tags. Empty tag lists can be created with gst_tag_list_new (). Then, the element can fill the list using gst_tag_list_add_values () . Note that an element probably reads metadata as strings, but values might not necessarily be strings. Be sure to use gst_value_transform () to make sure that your data is of the right type. After data reading, the application can be notified of the new taglist by calling gst_element_found_tags (). The tags should also be part of the datastream, so they should be pushed over all source pads. The function gst_event_new_tag () creates an event from a taglist. This can be pushed over source pads using gst_pad_push (). Simple elements with only one source pad can combine all these steps all-in-one by using the function gst_element_found_tags_for_pad (). The following example program will parse a file and parse the data as metadata/tags rather than as actual content-data. It will parse each line as name:value, where name is the type of metadata (title, author, ...) and value is the metadata value. The _getline () is the same as the one given in . static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstBuffer *buf; GstTagList *taglist = gst_tag_list_new (); /* get each line and parse as metadata */ while ((buf = gst_my_filter_getline (filter))) { gchar *line = GST_BUFFER_DATA (buf), *colon_pos, *type = NULL;a /* get the position of the ':' and go beyond it */ if (!(colon_pos = strchr (line, ':'))) goto next: /* get the string before that as type of metadata */ type = g_strndup (line, colon_pos - line); /* content is one character beyond the ':' */ colon_pos = &colon_pos[1]; if (*colon_pos == '\0') goto next; /* get the metadata category, it's value type, store it in that * type and add it to the taglist. */ if (gst_tag_exists (type)) { GValue from = { 0 }, to = { 0 }; GType to_type; to_type = gst_tag_get_type (type); g_value_init (&from, G_TYPE_STRING); g_value_set_string (&from, colon_pos); g_value_init (&to, to_type); g_value_transform (&from, &to); g_value_unset (&from); gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND, type, &to, NULL); g_value_unset (&to); } next: g_free (type); gst_buffer_unref (buf); } /* signal metadata */ gst_element_found_tags_for_pad (element, filter->srcpad, 0, taglist); gst_tag_list_free (taglist); /* send EOS */ gst_pad_send_event (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); } We currently assume the core to already know the mimetype (gst_tag_exists ()). You can add new tags to the list of known tags using gst_tag_register (). If you think the tag will be useful in more cases than just your own element, it might be a good idea to add it to gsttag.c instead. That's up to you to decide. If you want to do it in your own element, it's easiest to register the tag in one of your class init functions, preferrably _class_init (). static void gst_my_filter_class_init (GstMyFilterClass *klass) { [..] gst_tag_register ("my_tag_name", GST_TAG_FLAG_META, G_TYPE_STRING, _("my own tag"), _("a tag that is specific to my own element"), NULL); [..] } Writing Tags to Streams Tag writers are the opposite of tag readers. Tag writers only take metadata tags into account, since that's the only type of tags that have to be written into a stream. Tag writers can receive tags in three ways: internal, application and pipeline. Internal tags are tags read by the element itself, which means that the tag writer is - in that case - a tag reader, too. Application tags are tags provided to the element via the TagSetter interface (which is just a layer). Pipeline tags are tags provided to the element from within the pipeline. The element receives such tags via the GST_EVENT_TAG event, which means that tags writers should automatically be event aware. The tag writer is responsible for combining all these three into one list and writing them to the output stream. The example below will receive tags from both application and pipeline, combine them and write them to the output stream. It implements the tag setter so applications can set tags, and retrieves pipeline tags from incoming events. GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_TAG_SETTER, &tag_setter_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GST_FLAG_SET (filter, GST_ELEMENT_EVENT_AWARE); [..] } /* * Write one tag. */ static void gst_my_filter_write_tag (const GstTagList *taglist, const gchar *tagname, gpointer data) { GstMyFilter *filter = GST_MY_FILTER (data); GstBuffer *buffer; guint num_values = gst_tag_list_get_tag_size (list, tag_name), n; const GValue *from; GValue to = { 0 }; g_value_init (&to, G_TYPE_STRING); for (n = 0; n < num_values; n++) { from = gst_tag_list_get_value_index (taglist, tagname, n); g_value_transform (from, &to); buf = gst_buffer_new (); GST_BUFFER_DATA (buf) = g_strdup_printf ("%s:%s", tagname, g_value_get_string (&to)); GST_BUFFER_SIZE (buf) = strlen (GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); } g_value_unset (&to); } static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstTagSetter *tagsetter = GST_TAG_SETTER (element); GstData *data; GstEvent *event; gboolean eos = FALSE; GstTagList *taglist = gst_tag_list_new (); while (!eos) { data = gst_pad_pull (filter->sinkpad); /* We're not very much interested in data right now */ if (GST_IS_BUFFER (data)) gst_buffer_unref (GST_BUFFER (data)); event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG: gst_tag_list_insert (taglist, gst_event_tag_get_list (event), GST_TAG_MERGE_PREPEND); gst_event_unref (event); break; case GST_EVENT_EOS: eos = TRUE; gst_event_unref (event); break; default: gst_pad_event_default (filter->sinkpad, event); break; } } /* merge tags with the ones retrieved from the application */ if (gst_tag_setter_get_list (tagsetter)) { gst_tag_list_insert (taglist, gst_tag_setter_get_list (tagsetter), gst_tag_setter_get_merge_mode (tagsetter)); } /* write tags */ gst_tag_list_foreach (taglist, gst_my_filter_write_tag, filter); /* signal EOS */ gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); } Note that normally, elements would not read the full stream before processing tags. Rather, they would read from each sinkpad until they've received data (since tags usually come in before the first data buffer) and process that. Events: Seeking, Navigation and More There are many different event types but only 2 ways they can travel across the pipeline: downstream or upstream. It is very important to understand how both of those methods work because if one element in the pipeline is not handling them correctly the whole event system of the pipeline is broken. We will try to explain here how these methods work and how elements are supposed to implement them. Downstream events Downstream events are received through the sink pad's dataflow. Depending if your element is loop or chain based you will receive events in your loop/chain function as a GstData with gst_pad_pull or directly in the function call arguments. So when receiving dataflow from the sink pad you have to check first if this data chunk is an event. If that's the case you check what kind of event it is to react on relevant ones and then forward others downstream using gst_pad_event_default. Here is an example for both loop and chain based elements. /* Chain based element */ static void gst_my_filter_chain (GstPad *pad, GstData *data) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); ... if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (pad, event); break; } return; } ... } /* Loop based element */ static void gst_my_filter_loop (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstData *data = NULL; data = gst_pad_pull (filter->sinkpad); if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); /* fall-through to default event handling */ default: gst_pad_event_default (filter->sinkpad, event); break; } return; } ... } Upstream events Upstream events are generated by an element somewhere in the pipeline and sent using the gst_pad_send_event function. This function simply realizes the pad and call the default event handler of that pad. The default event handler of pads is gst_pad_event_default , it basically sends the event to the peer pad. So upstream events always arrive on the src pad of your element and are handled by the default event handler except if you override that handler to handle it yourself. There are some specific cases where you have to do that : If you have multiple sink pads in your element. In that case you will have to decide which one of the sink pads you will send the event to. If you need to handle that event locally. For example a navigation event that you will want to convert before sending it upstream. The processing you will do in that event handler does not really matter but there are important rules you have to absolutely respect because one broken element event handler is breaking the whole pipeline event handling. Here they are : Always forward events you won't handle upstream using the default gst_pad_event_default method. If you are generating some new event based on the one you received don't forget to gst_event_unref the event you received. Event handler function are supposed to return TRUE or FALSE indicating if the event has been handled or not. Never simply return TRUE/FALSE in that handler except if you really know that you have handled that event. Here is an example of correct upstream event handling for a plugin that wants to modify navigation events. static gboolean gst_my_filter_handle_src_event (GstPad *pad, GstEvent *event) { GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: GstEvent *new_event = gst_event_new (GST_EVENT_NAVIGATION);; /* Create a new event based on received one and then send it */ ... gst_event_unref (event); return gst_pad_event_default (pad, new_event); default: /* Falling back to default event handling for that pad */ return gst_pad_event_default (pad, event); } } All Events Together In this chapter follows a list of all defined events that are currently being used, plus how they should be used/interpreted. Events are stored in a GstEvent structure, which is simply a big C union with the types for each event in it. For the next development cycle, we intend to switch events over to GstStructure , but you don't need to worry about that too much for now. In this chapter, we will discuss the following events: End of Stream (EOS) End-of-stream events are sent if the stream that an element sends out is finished. An element receiving this event (from upstream, so it receives it on its sinkpad) will generally forward the event further downstream and set itself to EOS (gst_element_set_eos ()). gst_pad_event_default () takes care of all this, so most elements do not need to support this event. Exceptions are elements that explicitly need to close a resource down on EOS, and N-to-1 elements. Note that the stream itself is not a resource that should be closed down on EOS! Applications might seek back to a point before EOS and set the pipeline to PLAYING again. N-to-1 elements have been discussed previously in . The EOS event (GST_EVENT_EOS) has no properties, and that makes it one of the simplest events in GStreamer. It is created using gst_event_new (GST_EVENT_EOS);. Some elements support the EOS event upstream, too. This signals the element to go into EOS as soon as possible and signal the EOS event forward downstream. This is useful for elements that have no concept of end-of-stream themselves. Examples are TV card sources, audio card sources, etc. This is not (yet) part of the official specifications of this event, though. Flush The flush event is being sent downstream if all buffers and caches in the pipeline should be emptied. Queue elements will empty their internal list of buffers when they receive this event, for example. File sink elements (e.g. filesink) will flush the kernel-to-disk cache (fdatasync () or fflush ()) when they receive this event. Normally, elements receiving this event will simply just forward it, since most filter or filter-like elements don't have an internal cache of data. gst_pad_event_default () does just that, so for most elements, it is enough to forward the event using the default event handler. The flush event is created with gst_event_new (GST_EVENT_FLUSH);. Like the EOS event, it has no properties. Stream Discontinuity A discontinuity event is sent downstream to indicate a discontinuity in the data stream. This can happen because the application used the seek event to seek to a different position in the stream, but it can also be because a real-time network source temporarily lost the connection. After the connection is restored, the data stream will continue, but not at the same point where it got lost. Therefore, a discontinuity event is being sent downstream, too. Depending on the element type, the event can simply be forwarded using gst_pad_event_default (), or it should be parsed and a modified event should be sent on. The last is true for demuxers, which generally have a byte-to-time conversion concept. Their input is usually byte-based, so the incoming event will have an offset in byte units (GST_FORMAT_BYTES), too. Elements downstream, however, expect discontinuity events in time units, so that it can be used to update the pipeline clock. Therefore, demuxers and similar elements should not forward the event, but parse it, free it and send a new discontinuity event (in time units, GST_FORMAT_TIME) further downstream. The discontinuity event is created using the function gst_event_new_discontinuous (). It should set a boolean value which indicates if the discontinuity event is sent because of a new media type (this can happen if - during iteration - a new location was set on a network source or on a file source). then, it should give a list of formats and offsets in that format. The list should be terminated by 0 as format. static void my_filter_some_function (GstMyFilter *filter) { GstEvent *event; [..] event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, 0, GST_FORMAT_TIME, 0, 0); gst_pad_push (filter->srcpad, GST_DATA (event)); [..] } Elements parsing this event can use macros and functions to access the various properties. GST_EVENT_DISCONT_NEW_MEDIA (event) checks the new-media boolean value. gst_event_discont_get_value (event, format, &value) gets the offset of the new stream position in the specified format. If that format was not specified when creating the event, the function returns FALSE. Seek Request Seek events are meant to request a new stream position to elements. This new position can be set in several formats (time, bytes or units [a term indicating frames for video, samples for audio, etc.]). Seeking can be done with respect to the end-of-file, start-of-file or current position, and can happen in both upstream and downstream direction. Elements receiving seek events should, depending on the element type, either forward it (filters, decoders), change the format in which the event is given and forward it (demuxers), handle the event by changing the file pointer in their internal stream resource (file sources) or something else. Seek events are, like discontinuity events, built up using positions in specified formats (time, bytes, units). They are created using the function gst_event_new_seek (), where the first argument is the seek type (indicating with respect to which position [current, end, start] the seek should be applied, and the format in which the new position is given (time, bytes, units), and an offset which is the requested position in the specified format. static void my_filter_some_function (GstMyFilter *filter) { GstEvent *event; [..] /* seek to the start of a resource */ event = gst_event_new_seek (GST_SEEK_SET | GST_FORMAT_BYTES, 0); gst_pad_push (filter->srcpad, GST_DATA (event)); [..] } Elements parsing this event can use macros and functions to access the properties. The seek type can be retrieved using GST_EVENT_SEEK_TYPE (event). This seek type contains both the indicator of with respect to what position the seek should be applied, and the format in which the seek event is given. To get either one of these properties separately, use GST_EVENT_SEEK_FORMAT (event) or GST_EVENT_SEEK_METHOD (event). The requested position is available through GST_EVENT_SEEK_OFFSET (event), and is given in the specified format. Stream Filler The filler event is, as the name says, a filler of the stream which has no special meaning associated with itself. It is used to provide data to downstream elements and should be interpreted as a way of assuring that the normal data flow will continue further downstream. The event is especially intended for real-time MIDI source elements, which only generate data when something changes. MIDI decoders will therefore stall if nothing changes for several seconds, and therefore playback will stop. The filler event is sent downstream to assure the MIDI decoder that nothing changed, so that the normal decoding process will continue and playback will, too. Unless you intend to work with MIDI or other control-language-based data types, you don't need this event. You can mostly simply forward it with gst_pad_event_default (). The stream filler is created using gst_event_new (GST_EVENT_FILLER);. It has no properties. Interruption The interrupt event is generated by queue elements and sent downstream if a timeout occurs on the stream. The scheduler will use this event to get back in its own main loop and schedule other elements. This prevents deadlocks or a stream stall if no data is generated over a part of the pipeline for a considerable amount of time. The scheduler will process this event internally, so any normal elements do not need to generate or handle this event at all. The difference between the filler event and the interrupt event is that the filler event is a real part of a pipeline, so it will reach fellow elements, which can use it to "do nothing else than what I used to do". The interrupt event never reaches fellow elements. The interrupt event (gst_event_new (GST_EVENT_INTERRUPT);) has no properties. Navigation WRITEME Tag (metadata) Tagging events are being sent downstream to indicate the tags as parsed from the stream data. This is currently used to preserve tags during stream transcoding from one format to the other. Tags are discussed extensively in . Most elements will simply forward the event by calling gst_pad_event_default (). The tag event is created using the function gst_event_new_tag (). It requires a filled taglist as argument. Elements parsing this event can use the function gst_event_tag_get_list (event) to acquire the taglist that was parsed. Other Element Types By now, we have looked at pretty much any feature that can be embedded into a GStreamer element. However, we have limited ourselves to the simple model of a filter element. In this chapter, we will look at the specific difficulties and things to keep in mind when writing specific types of elements. We will discuss output elements (sinks), input elements (sources), 1-to-N elements, N-to-1 elements, N-to-N elements, autopluggers and managers. Some of these represent elements that don't actually exist. Rather, they represent a general concept. Writing a Source Source elements are the start of a data streaming pipeline. Source elements have no sink pads and have one or more source pads. We will focus on single-sourcepad elements here, but the concepts apply equally well to multi-sourcepad elements. This chapter will explain the essentials of source elements, which features it should implement and which it doesn't have to, and how source elements will interact with other elements in a pipeline. The get()-function Source elements have the special option of having a _get ()-function rather than a _loop ()- or _chain ()-function. A _get ()-function is called by the scheduler every time the next elements needs data. Apart from corner cases, every source element will want to be _get ()-based. static GstData * gst_my_source_get (GstPad *pad); static void gst_my_source_init (GstMySource *src) { [..] gst_pad_set_get_function (src->srcpad, gst_my_source_get); } static GstData * gst_my_source_get (GstPad *pad) { GstBuffer *buffer; buffer = gst_buffer_new (); GST_BUFFER_DATA (buf) = g_strdup ("hello pipeline!"); GST_BUFFER_SIZE (buf) = strlen (GST_BUFFER_DATA (buf)); /* terminating '/0' */ GST_BUFFER_MAZSIZE (buf) = GST_BUFFER_SIZE (buf) + 1; return GST_DATA (buffer); } Events, querying and converting One of the most important functions of source elements is to implement correct query, convert and event handling functions. Those will continuously describe the current state of the stream. Query functions can be used to get stream properties such as current position and length. This can be used by fellow elements to convert this same value into a different unit, or by appliations to provide information about the length/position of the stream to the user. Conversion functions are used to convert such values from one unit to another. Lastly, events are mostly used to seek to positions inside the stream. Any function is essentially optional, but the element should try to provide as much information as it knows. Note that elements providing an event function should also list their supported events in an _get_event_mask () function. Elements supporting query operations should list the supported operations in a _get_query_types () function. Elements supporting either conversion or query operations should also implement a _get_formats () function. An example source element could, for example, be an element that continuously generates a wave tone at 44,1 kHz, mono, 16-bit. This element will generate 44100 audio samples per second or 88,2 kB/s. This information can be used to implement such functions: static GstFormat * gst_my_source_format_list (GstPad *pad); static GstQueryType * gst_my_source_query_list (GstPad *pad); static gboolean gst_my_source_convert (GstPad *pad, GstFormat from_fmt, gint64 from_val, GstFormat *to_fmt, gint64 *to_val); static gboolean gst_my_source_query (GstPad *pad, GstQueryType type, GstFormat *to_fmt, gint64 *to_val); static void gst_my_source_init (GstMySource *src) { [..] gst_pad_set_convert_function (src->srcpad, gst_my_source_convert); gst_pad_set_formats_function (src->srcpad, gst_my_source_format_list); gst_pad_set_query_function (src->srcpad, gst_my_source_query); gst_pad_set_query_type_function (src->srcpad, gst_my_source_query_list); } /* * This function returns an enumeration of supported GstFormat * types in the query() or convert() functions. See gst/gstformat.h * for a full list. */ static GstFormat * gst_my_source_format_list (GstPad *pad) { static const GstFormat formats[] = { GST_FORMAT_TIME, GST_FORMAT_DEFAULT, /* means "audio samples" */ GST_FORMAT_BYTES, 0 }; return formats; } /* * This function returns an enumeration of the supported query() * operations. Since we generate audio internally, we only provide * an indication of how many samples we've played so far. File sources * or such elements could also provide GST_QUERY_TOTAL for the total * stream length, or other things. See gst/gstquery.h for details. */ static GstQueryType * gst_my_source_query_list (GstPad *pad) { static const GstQueryType query_types[] = { GST_QUERY_POSITION, 0, }; return query_types; } /* * And below are the logical implementations. */ static gboolean gst_my_source_convert (GstPad *pad, GstFormat from_fmt, gint64 from_val, GstFormat *to_fmt, gint64 *to_val) { gboolean res = TRUE; GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (from_fmt) { case GST_FORMAT_TIME: switch (*to_fmt) { case GST_FORMAT_TIME: /* nothing */ break; case GST_FORMAT_BYTES: *to_val = from_val / (GST_SECOND / (44100 * 2)); break; case GST_FORMAT_DEFAULT: *to_val = from_val / (GST_SECOND / 44100); break; default: res = FALSE; break; } break; case GST_FORMAT_BYTES: switch (*to_fmt) { case GST_FORMAT_TIME: *to_val = from_val * (GST_SECOND / (44100 * 2)); break; case GST_FORMAT_BYTES: /* nothing */ break; case GST_FORMAT_DEFAULT: *to_val = from_val / 2; break; default: res = FALSE; break; } break; case GST_FORMAT_DEFAULT: switch (*to_fmt) { case GST_FORMAT_TIME: *to_val = from_val * (GST_SECOND / 44100); break; case GST_FORMAT_BYTES: *to_val = from_val * 2; break; case GST_FORMAT_DEFAULT: /* nothing */ break; default: res = FALSE; break; } break; default: res = FALSE; break; } return res; } static gboolean gst_my_source_query (GstPad *pad, GstQueryType type, GstFormat *to_fmt, gint64 *to_val) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); gboolean res = TRUE; switch (type) { case GST_QUERY_POSITION: res = gst_pad_convert (pad, GST_FORMAT_BYTES, src->total_bytes, to_fmt, to_val); break; default: res = FALSE; break; } return res; } Be sure to increase src->total_bytes after each call to your _get () function. Event handling has already been explained previously in the events chapter. Time, clocking and synchronization The above example does not provide any timing info, but will suffice for elementary data sources such as a file source or network data source element. Things become slightly more complicated, but still very simple, if we create artificial video or audio data sources, such as a video test image source or an artificial audio source (e.g. sinesrc or silence). It will become more complicated if we want the element to be a realtime capture source, such as a video4linux source (for reading video frames from a TV card) or an ALSA source (for reading data from soundcards supported by an ALSA-driver). Here, we will need to make the element aware of timing and clocking. Timestamps can essentially be generated from all the information given above without any difficulty. We could add a very small amount of code to generate perfectly timestamped buffers from our _get ()-function: static void gst_my_source_init (GstMySource *src) { [..] src->total_bytes = 0; } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; GstFormat fmt = GST_FORMAT_TIME; [..] GST_BUFFER_DURATION (buf) = GST_BUFFER_SIZE (buf) * (GST_SECOND / (44100 * 2)); GST_BUFFER_TIMESTAMP (buf) = src->total_bytes * (GST_SECOND / (44100 * 2)); src->total_bytes += GST_BUFFER_SIZE (buf); return GST_DATA (buf); } static GstStateReturn gst_my_source_change_state (GstElement *element) { GstMySource *src = GST_MY_SOURCE (element); switch (GST_STATE_PENDING (element)) { case GT_STATE_PAUSED_TO_READY: src->total_bytes = 0; break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } That wasn't too hard. Now, let's assume real-time elements. Those can either have hardware-timing, in which case we can rely on backends to provide sync for us (in which case you probably want to provide a clock), or we will have to emulate that internally (e.g. to acquire sync in artificial data elements such as sinesrc). Let's first look at the second option (software sync). The first option (hardware sync + providing a clock) does not require any special code with respect to timing, and the clocking section already explained how to provide a clock. enum { ARG_0, [..] ARG_SYNC, [..] }; static void gst_my_source_class_init (GstMySourceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); [..] g_object_class_install_property (object_class, ARG_SYNC, g_param_spec_boolean ("sync", "Sync", "Synchronize to clock", FALSE, G_PARAM_READWRITE)); [..] } static void gst_my_source_init (GstMySource *src) { [..] src->sync = FALSE; } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; [..] if (src->sync) { /* wait on clock */ gst_element_wait (GST_ELEMENT (src), GST_BUFFER_TIMESTAMP (buf)); } return GST_DATA (buf); } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: g_value_set_boolean (value, src->sync); break; [..] } } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, const GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: src->sync = g_value_get_boolean (value); break; [..] } } Most of this is GObject wrapping code. The actual code to do software-sync (in the _get ()-function) is relatively small. Using special memory In some cases, it might be useful to use specially allocated memory (e.g. mmap ()'ed DMA'able memory) in your buffers, and those will require special handling when they are being dereferenced. For this, GStreamer uses the concept of buffer-free functions. Those are special functions pointers that an element can set on buffers that it created itself. The given function will be called when the buffer has been dereferenced, so that the element can clean up or re-use memory internally rather than using the default implementation (which simply calls g_free () on the data pointer). static void gst_my_source_buffer_free (GstBuffer *buf) { GstMySource *src = GST_MY_SOURCE (GST_BUFFER_PRIVATE (buf)); /* do useful things here, like re-queueing the buffer which * makes it available for DMA again. The default handler will * not free this buffer because of the GST_BUFFER_DONTFREE * flag. */ } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; [..] buf = gst_buffer_new (); GST_BUFFER_FREE_DATA_FUNC (buf) = gst_my_source_buffer_free; GST_BUFFER_PRIVATE (buf) = src; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY | GST_BUFFER_DONTFREE); [..] return GST_DATA (buf); } Note that this concept should not be used to decrease the number of calls made to functions such as g_malloc () inside your element. We have better ways of doing that elsewhere (GStreamer core, Glib, Glibc, Linux kernel, etc.). Writing a Sink Sinks are output elements that, opposite to sources, have no source pads and one or more (usually one) sink pad. They can be sound card outputs, disk writers, etc. This chapter will discuss the basic implementation of sink elements. Data processing, events, synchronization and clocks Except for corner cases, sink elements will be _chain ()-based elements. The concept of such elements has been discussed before in detail, so that will be skipped here. What is very important in sink elements, specifically in real-time audio and video sources (such as osssink or ximagesink), is event handling in the _chain ()-function, because most elements rely on EOS-handling of the sink element, and because A/V synchronization can only be perfect if the element takes this into account. How to achieve synchronization between streams depends on whether you're a clock-providing or a clock-receiving element. If you're the clock provider, you can do with time whatever you want. Correct handling would mean that you check whether the end of the previous buffer (if any) and the start of the current buffer are the same. If so, there's no gap between the two and you can continue playing right away. If there is a gap, then you'll need to wait for your clock to reach that time. How to do that depends on the element type. In the case of audio output elements, you would output silence for a while. In the case of video, you would show background color. In case of subtitles, show no subtitles at all. In the case that the provided clock and the received clock are not the same (or in the case where your element provides no clock, which is the same), you simply wait for the clock to reach the timestamp of the current buffer and then you handle the data in it. A simple data handling function would look like this: static void gst_my_sink_chain (GstPad *pad, GstData *data) { GstMySink *sink = GST_MY_SINK (gst_pad_get_parent (pad)); GstBuffer *buf; GstClockTime time; /* only needed if the element is GST_EVENT_AWARE */ if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: [ if your element provides a clock, disable (inactivate) it here ] /* pass-through */ default: /* the default handler handles discontinuities, even if your * element provides a clock! */ gst_pad_event_default (pad, event); break; } return; } buf = GST_BUFFER (data); if (GST_BUFFER_TIME_IS_VALID (buf)) time = GST_BUFFER_TIMESTAMP (buf); else time = sink->expected_next_time; /* Synchronization - the property is only useful in case the * element has the option of not syncing. So it is not useful * for hardware-sync (clock-providing) elements. */ if (sink->sync) { /* This check is only needed if you provide a clock. Else, * you can always execute the 'else' clause. */ if (sink->provided_clock == sink->received_clock) { /* GST_SECOND / 10 is 0,1 sec, it's an arbitrary value. The * casts are needed because else it'll be unsigned and we * won't detect negative values. */ if (llabs ((gint64) sink->expected_next_time - (gint64) time) > (GST_SECOND / 10)) { /* so are we ahead or behind? */ if (time > sink->expected_time) { /* we need to wait a while... In case of audio, output * silence. In case of video, output background color. * In case of subtitles, display nothing. */ [..] } else { /* Drop data. */ [..] } } } else { /* You could do more sophisticated things here, but we'll * keep it simple for the purpose of the example. */ gst_element_wait (GST_ELEMENT (sink), time); } } /* And now handle the data. */ [..] } Special memory Like source elements, sink elements can sometimes provide externally allocated (such as X-provided or DMA'able) memory to elements earlier in the pipeline, and thereby prevent the need for memcpy () for incoming data. We do this by providing a pad-allocate-buffer function. static GstBuffer * gst_my_sink_buffer_allocate (GstPad *pad, guint64 offset, guint size); static void gst_my_sink_init (GstMySink *sink) { [..] gst_pad_set_bufferalloc_function (sink->sinkpad, gst_my_sink_buffer_allocate); } static void gst_my_sink_buffer_free (GstBuffer *buf) { GstMySink *sink = GST_MY_SINK (GST_BUFFER_PRIVATE (buf)); /* Do whatever is needed here. */ [..] } static GstBuffer * gst_my_sink_buffer_allocate (GstPad *pad, guint64 offset, guint size) { GstBuffer *buf = gst_buffer_new (); /* So here it's up to you to wrap your private buffers and * return that. */ GST_BUFFER_FREE_DATA_FUNC (buf) = gst_my_sink_buffer_free; GST_BUFFER_PRIVATE (buf) = sink; GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE); [..] return buf; } Writing a 1-to-N Element, Demuxer or Parser 1-to-N elements don't have much special needs or requirements that haven't been discussed already. The most important thing to take care of in 1-to-N elements (things like tee-elements or so) is to use proper buffer refcounting and caps negotiation. If those two are taken care of (see the tee element if you need example code), there's little that can go wrong. Demuxers are the 1-to-N elements that need very special care, though. They are responsible for timestamping raw, unparsed data into elementary video or audio streams, and there are many things that you can optimize or do wrong. Here, several culprits will be mentioned and common solutions will be offered. Parsers are demuxers with only one source pad. Also, they only cut the stream into buffers, they don't touch the data otherwise. Demuxer Caps Negotiation Demuxers will usually contain several elementary streams, and each of those streams' properties will be defined in a stream header at the start of the file (or, rather, stream) that you're parsing. Since those are fixed and there is no possibility to negotiate stream properties with elements earlier in the pipeline, you should always use explicit caps on demuxer source pads. This prevents a whole lot of caps negotiation or re-negotiation errors. Data processing and downstream events Data parsing, pulling this into subbuffers and sending that to the source pads of the elementary streams is the one single most important task of demuxers and parsers. Usually, an element will have a _loop () function using the bytestream object to read data. Try to have a single point of data reading from the bytestream object. In this single point, do proper event handling (in case there is any) and proper error handling in case that's needed. Make your element as fault-tolerant as possible, but do not go further than possible. Parsing versus interpreting One particular convention that GStreamer demuxers follow is that of separation of parsing and interpreting. The reason for this is maintainability, clarity and code reuse. An easy example of this is something like RIFF, which has a chunk header of 4 bytes, then a length indicator of 4 bytes and then the actual data. We write special functions to read one chunk, to peek a chunk ID and all those; that's the parsing part of the demuxer. Then, somewhere else, we like to write the main data processing function, which calls this parse function, reads one chunk and then does with the data whatever it needs to do. Some example code for RIFF-reading to illustrate the above two points: static gboolean gst_my_demuxer_peek (GstMyDemuxer *demux, guint32 *id, guint32 *size) { guint8 *data; while (gst_bytestream_peek_bytes (demux->bs, &data, 4) != 4) { guint32 remaining; GstEvent *event; gst_bytestream_get_status (demux->bs, &remaining, &event); if (event) { GstEventType type = GST_EVENT_TYPE (event); /* or maybe custom event handling, up to you - we lose reference! */ gst_pad_event_default (demux->sinkpad, event); if (type == GST_EVENT_EOS) return FALSE; } else { GST_ELEMENT_ERROR (demux, STREAM, READ, (NULL), (NULL)); return FALSE; } } *id = GUINT32_FROM_LE (((guint32 *) data)[0]); *size = GUINT32_FROM_LE (((guint32 *) data)[0]); return TRUE; } static void gst_my_demuxer_loop (GstElement *element) { GstMyDemuxer *demux = GST_MY_DEMUXER (element); guint32 id, size; if (!gst_my_demuxer_peek (demux, &id, &size)) return; switch (id) { [.. normal chunk handling ..] } } Reason for this is that event handling is now centralized in one place and the _loop () function is a lot cleaner and more readable. Those are common code practices, but since the mistake of not using such common code practices has been made too often, we explicitely mention this here. Simple seeking and indexes Sources will generally receive a seek event in the exact supported format by the element. Demuxers, however, can not seek in themselves directly, but need to convert from one unit (e.g. time) to the other (e.g. bytes) and send a new event to its sink pad. Given this, the _convert ()-function (or, more general: unit conversion) is the most important function in a demuxer. Some demuxers (AVI, Matroska) and parsers will keep an index of all chunks in a stream, firstly to improve seeking precision and secondly so they won't lose sync. Some other demuxers will seek the stream directly without index (e.g. MPEG, Ogg) - usually based on something like a cumulative bitrate - and then find the closest next chunk from their new position. The best choice depends on the format. Note that it is recommended for demuxers to implement event, conversion and query handling functions (using time units or so), in addition to the ones (usually in byte units) provided by the pipeline source element. Writing a N-to-1 Element or Muxer N-to-1 elements have been previously mentioned and discussed in both and in . The main noteworthy thing about N-to-1 elements is that they should always, without any single exception, be _loop ()-based. Apart from that, there is not much general that you need to know. We will discuss one special type of N-to-1 elements here, these being muxers. The first two of these sections apply to N-to-1 elements in general, though. The Data Loop Function As previously mentioned in , N-to-1 elements generally try to have one buffer from each sink pad and then handle the one with the earliest timestamp. There's some exceptions to this rule, we will come to those later. This only works if all streams actually continuously provide input. There might be cases where this is not true, for example subtitles (there might be no subtitle for a while), overlay images and so forth. For this purpose, there is a _select () function in GStreamer. It checks whether input is available on a (list of) pad(s). In this way, you can skip over the pads that are 'non- continuous'. /* Pad selection is currently broken, FIXME some day */ Events in the Loop Function N-to-1 elements using a cache will sometimes receive events, and it is often unclear how to handle those. For example, how do you seek to a frame in an output file (and what's the point of it anyway)? So, do discontinuity or seek events make sense, and should you use them? Discontinuities and flushes Don't do anything. They specify a discontinuity in the output, and you should continue to playback as you would otherwise. You generally do not need to put a discontinuity in the output stream in muxers; you would have to manually start adapting timestamps of output frames (if appliccable) to match the previous timescale, though. Note that the output data stream should be continuous. For other types of N-to-1-elements, it is generally fine to forward the discontinuity once it has been received from all pads. This depends on the specific element. Seeks Depends on the element. Muxers would generally not implement this, because the concept of seeking in an output stream at frame level is not very useful. Seeking at byte level can be useful, but that is more generally done by muxers on sink elements. End-of-Stream Speaks for itself. Negotiation Most container formats will have a fair amount of issues with changing content on an elementary stream. Therefore, you should not allow caps to be changed once you've started using data from them. The easiest way to achieve this is by using explicit caps, which have been explained before. However, we're going to use them in a slightly different way then what you're used to, having the core do all the work for us. The idea is that, as long as the stream/file headers have not been written yet and no data has been processed yet, a stream is allowed to renegotiate. After that point, the caps should be fixed, because we can only use a stream once. Caps may then only change within an allowed range (think MPEG, where changes in FPS are allowed), or sometimes not at all (such as AVI audio). In order to do that, we will, after data retrieval and header writing, set an explicit caps on each sink pad, that is the minimal caps describing the properties of the format that may not change. As an example, for MPEG audio inside an MPEG system stream, this would mean a wide caps of audio/mpeg with mpegversion=1 and layer=[1,2]. For the same audio type in MPEG, though, the samplerate, bitrate, layer and number of channels would become static, too. Since the (request) pads will be removed when the stream ends, the static caps will cease to exist too, then. While the explicit caps exist, the _link ()- function will not be called, since the core will do all necessary checks for us. Note that the property of using explicit caps should be added along with the actual explicit caps, not any earlier. Below here follows the simple example of an AVI muxer's audio caps negotiation. The _link ()-function is fairly normal, but the -Loop ()-function does some of the tricks mentioned above. There is no _getcaps ()- function since the pad template contains all that information already (not shown). static GstPadLinkReturn gst_avi_mux_audio_link (GstPad *pad, const GstCaps *caps) { GstAviMux *mux = GST_AVI_MUX (gst_pad_get_parent (pad)); GstStructure *str = gst_caps_get_structure (caps, 0); const gchar *mime = gst_structure_get_name (str); if (!strcmp (str, "audio/mpeg")) { /* get version, make sure it's 1, get layer, make sure it's 1-3, * then create the 2-byte audio tag (0x0055) and fill an audio * stream structure (strh/strf). */ [..] return GST_PAD_LINK_OK; } else if !strcmp (str, "audio/x-raw-int")) { /* See above, but now with the raw audio tag (0x0001). */ [..] return GST_PAD_LINK_OK; } else [..] [..] } static void gst_avi_mux_loop (GstElement *element) { GstAviMux *mux = GST_AVI_MUX (element); [..] /* As we get here, we should have written the header if we hadn't done * that before yet, and we're supposed to have an internal buffer from * each pad, also from the audio one. So here, we check again whether * this is the first run and if so, we set static caps. */ if (mux->first_cycle) { const GList *padlist = gst_element_get_pad_list (element); GList *item; for (item = padlist; item != NULL; item = item->next) { GstPad *pad = item->data; GstCaps *caps; if (!GST_PAD_IS_SINK (pad)) continue; /* set static caps here */ if (!strncmp (gst_pad_get_name (pad), "audio_", 6)) { /* the strf is the struct you filled in the _link () function. */ switch (strf->format) { case 0x0055: /* mp3 */ caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, "bitrate", G_TYPE_INT, strf->av_bps, "rate", G_TYPE_INT, strf->rate, "channels", G_TYPE_INT, strf->channels, NULL); break; case 0x0001: /* pcm */ caps = gst_caps_new_simple ("audio/x-raw-int", [..]); break; [..] } } else if (!strncmp (gst_pad_get_name (pad), "video_", 6)) { [..] } else { g_warning ("oi!"); continue; } /* set static caps */ gst_pad_use_explicit_caps (pad); gst_pad_set_explicit_caps (pad, caps); } } [..] /* Next runs will never be the first again. */ mux->first_cycle = FALSE; } Note that there are other ways to achieve that, which might be useful for more complex cases. This will do for the simple cases, though. This method is provided to simplify negotiation and renegotiation in muxers, it is not a complete solution, nor is it a pretty one. Markup vs. data processing As we noted on demuxers before, we love common programming paradigms such as clean, lean and mean code. To achieve that in muxers, it's generally a good idea to separate the actual data stream markup from the data processing. To illustrate, here's how AVI muxers should write out RIFF tag chunks: static void gst_avi_mux_write_chunk (GstAviMux *mux, guint32 id, GstBuffer *data) { GstBuffer *hdr; hdr = gst_buffer_new_and_alloc (8); ((guint32 *) GST_BUFFER_DATA (buf))[0] = GUINT32_TO_LE (id); ((guint32 *) GST_BUFFER_DATA (buf))[1] = GUINT32_TO_LE (GST_BUFFER_SIZE (data)); gst_pad_push (mux->srcpad, hdr); gst_pad_push (mux->srcpad, data); } static void gst_avi_mux_loop (GstElement *element) { GstAviMux *mux = GST_AVI_MUX (element); GstBuffer *buf; [..] buf = gst_pad_pull (mux->sinkpad[0]); [..] gst_avi_mux_write_chunk (GST_MAKE_FOURCC ('0','0','d','b'), buf); } In general, try to program clean code, that should cover pretty much everything. Writing a N-to-N element FIXME: write. Writing an Autoplugger FIXME: write. Writing a Manager Managers are elements that add a function or unify the function of another (series of) element(s). Managers are generally a GstBin with one or more ghostpads. Inside them is/are the actual element(s) that matters. There is several cases where this is useful. For example: To add support for private events with custom event handling to another element. To add support for custom pad _query () or _convert () handling to another element. To add custom data handling before or after another element's data handler function (generally its _chain () function). This chapter will explain the setup of managers. As a specific example, we will try to add EOS event support to source elements. This can be used to finish capturing an audio stream to a file. Source elements normally don't do any EOS handling at all, so a manager is perfect to extend those element's functionalities. Specifically, this element will contain two child elements: the actual source element and a helper element that implement an event handler on its source pad. This event handler will respond to EOS events by storing them internally and returning the event (rather than data) on the next call to the _get () function. After that, it will go into EOS and set the parent (and thereby the contained source element) to EOS as well. Other events will be forwarded to the source element, which will handle them as usual. .. Appendices This chapter contains things that don't belong anywhere else. Things to check when writing an element This chapter contains a fairly random selection of things to take care of when writing an element. It's up to you how far you're going to stick to those guidelines. However, keep in mind that when you're writing an element and hope for it to be included in the mainstream GStreamer distribution, it has to meet those requirements. As far as possible, we will try to explain why those requirements are set. About states Make sure the state of an element gets reset when going to NULL. Ideally, this should set all object properties to their original state. This function should also be called from _init. Make sure an element forgets everything about its contained stream when going from PAUSED to READY. In READY, all stream states are reset. An element that goes from PAUSED to READY and back to PAUSED should start reading the stream from he start again. People that use gst-launch for testing have the tendency to not care about cleaning up. This is wrong. An element should be tested using various applications, where testing not only means to make sure it doesn't crash, but also to test for memory leaks using tools such as valgrind. Elements have to be reusable in a pipeline after having been reset. Debugging Elements should never use their standard output for debugging (using functions such as printf () or g_print ()). Instead, elements should use the logging functions provided by GStreamer, named GST_DEBUG (), GST_LOG (), GST_INFO (), GST_WARNING () and GST_ERROR (). The various logging levels can be turned on and off at runtime and can thus be used for solving issues as they turn up. Instead of GST_LOG () (as an example), you can also use GST_LOG_OBJECT () to print the object that you're logging output for. Ideally, elements should use their own debugging category. Most elements use the following code to do that: GST_DEBUG_CATEGORY_STATIC (myelement_debug); #define GST_CAT_DEFAULT myelement_debug [..] static void gst_myelement_class_init (GstMyelementClass *klass) { [..] GST_DEBUG_CATEGORY_INIT (myelement_debug, "myelement", 0, "My own element"); } At runtime, you can turn on debugging using the commandline option --gst-debug=myelement:5. Querying, events and the like All elements to which it applies (sources, sinks, demuxers) should implement query functions on their pads, so that applications and neighbour elements can request the current position, the stream length (if known) and so on. All elements that are event-aware (their GST_ELEMENT_EVENT_AWARE flag is set) should implement event handling for all events, either specifically or using gst_pad_event_default (). Elements that you should handle specifically are the interrupt event, in order to properly bail out as soon as possible if state is changed. Events may never be dropped unless specifically intended. Loop-based elements should always implement event handling, in order to prevent hangs (infinite loop) on state changes. Testing your element gst-launch is not a good tool to show that your element is finished. Applications such as Rhythmbox and Totem (for GNOME) or AmaroK (for KDE) are. gst-launch will not test various things such as proper clean-up on reset, interrupt event handling, querying and so on. Parsers and demuxers should make sure to check their input. Input cannot be trusted. Prevent possible buffer overflows and the like. Feel free to error out on unrecoverable stream errors. Test your demuxer using stream corruption elements such as breakmydata (included in gst-plugins). It will randomly insert, delete and modify bytes in a stream, and is therefore a good test for robustness. If your element crashes when adding this element, your element needs fixing. If it errors out properly, it's good enough. Ideally, it'd just continue to work and forward data as much as possible. Demuxers should not assume that seeking works. Be prepared to work with unseekable input streams (e.g. network sources) as well. Sources and sinks should be prepared to be assigned another clock then the one they expose themselves. Always use the provided clock for synchronization, else you'll get A/V sync issues. GStreamer licensingHow to license the code you write for GStreamer GStreamer is a plugin-based framework licensed under the LGPL. The reason for this choice in licensing is to ensure that everyone can use GStreamer to build applications using licenses of their choice. To keep this policy viable, the GStreamer community has made a few licensing rules for code to be included in GStreamer's core or GStreamer's official modules, like our plugin packages. We require that all code going into our core package is LGPL. For the plugin code, we require the use of the LGPL for all plugins written from scratch or linking to external libraries. The only exception to this is when plugins contain older code under more liberal licenses (like the MPL or BSD). They can use those licenses instead and will still be considered for inclusion. We do not accept GPL code to be added to our plugins module, but we do accept LGPL-licensed plugins using an external GPL library. The reason for demanding plugins be licensed under the LGPL, even when using a GPL library, is that other developers might want to use the plugin code as a template for plugins linking to non-GPL libraries. We also plan on splitting out the plugins using GPL libraries into a separate package eventually and implement a system which makes sure an application will not be able to access these plugins unless it uses some special code to do so. The point of this is not to block GPL-licensed plugins from being used and developed, but to make sure people are not unintentionally violating the GPL license of said plugins. This advisory is part of a bigger advisory with a FAQ which you can find on the GStreamer website Done. Copying .css files: base.css /bin/sh ../../mkinstalldirs /usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc cp -pr html /usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc test -z "/usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc" || mkdir -p -- "/usr/src/rpm/BUILD/gstreamer-0.8.11/installed-doc" make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/pwg' Making install in gst make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/gst' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/gst' make[3]: Nothing to be done for `install-exec-am'. /bin/sh ../../mkinstalldirs /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-0.8 mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-0.8 (installfiles=`echo ./html/*.html`; \ if test "$installfiles" = './html/*.html'; \ then echo '-- Nothing to install' ; \ else \ for i in $installfiles; do \ echo '-- Installing '$i ; \ /usr/bin/install -c -m 644 $i /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-0.8; \ done; \ pngfiles=`echo ./html/*.png`; \ if test "$pngfiles" != './html/*.png'; then \ for i in $pngfiles; do \ echo '-- Installing '$i ; \ /usr/bin/install -c -m 644 $i /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-0.8; \ done; \ fi; \ echo '-- Installing ./html/gstreamer.devhelp' ; \ /usr/bin/install -c -m 644 ./html/gstreamer.devhelp \ /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-0.8/gstreamer-0.8.devhelp; \ echo '-- Installing ./html/index.sgml' ; \ /usr/bin/install -c -m 644 ./html/index.sgml /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-0.8; \ if test -e ./html/style.css; then \ echo '-- Installing ./html/style.css' ; \ /usr/bin/install -c -m 644 ./html/style.css /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-0.8; \ fi; \ fi) -- Installing ./html/GstBin.html -- Installing ./html/GstClock.html -- Installing ./html/GstElement.html -- Installing ./html/GstElementFactory.html -- Installing ./html/GstGhostPad.html -- Installing ./html/GstImplementsInterface.html -- Installing ./html/GstIndex.html -- Installing ./html/GstIndexFactory.html -- Installing ./html/GstObject.html -- Installing ./html/GstPad.html -- Installing ./html/GstPadTemplate.html -- Installing ./html/GstPipeline.html -- Installing ./html/GstPluginFeature.html -- Installing ./html/GstQueue.html -- Installing ./html/GstRealPad.html -- Installing ./html/GstRegistry.html -- Installing ./html/GstScheduler.html -- Installing ./html/GstSchedulerFactory.html -- Installing ./html/GstTagSetter.html -- Installing ./html/GstThread.html -- Installing ./html/GstTypeFindFactory.html -- Installing ./html/GstXML.html -- Installing ./html/api-index.html -- Installing ./html/gstreamer-Gst.html -- Installing ./html/gstreamer-GstAtomic.html -- Installing ./html/gstreamer-GstBuffer.html -- Installing ./html/gstreamer-GstCPU.html -- Installing ./html/gstreamer-GstCaps.html -- Installing ./html/gstreamer-GstCompat.html -- Installing ./html/gstreamer-GstData.html -- Installing ./html/gstreamer-GstElementDetails.html -- Installing ./html/gstreamer-GstEvent.html -- Installing ./html/gstreamer-GstFilter.html -- Installing ./html/gstreamer-GstFormat.html -- Installing ./html/gstreamer-GstGError.html -- Installing ./html/gstreamer-GstInfo.html -- Installing ./html/gstreamer-GstMacros.html -- Installing ./html/gstreamer-GstMemChunk.html -- Installing ./html/gstreamer-GstParse.html -- Installing ./html/gstreamer-GstPlugin.html -- Installing ./html/gstreamer-GstProbe.html -- Installing ./html/gstreamer-GstQuery.html -- Installing ./html/gstreamer-GstRegistryPool.html -- Installing ./html/gstreamer-GstStructure.html -- Installing ./html/gstreamer-GstSystemClock.html -- Installing ./html/gstreamer-GstTagList.html -- Installing ./html/gstreamer-GstTypeFind.html -- Installing ./html/gstreamer-GstTypes.html -- Installing ./html/gstreamer-GstUriHandler.html -- Installing ./html/gstreamer-GstUriType.html -- Installing ./html/gstreamer-GstUtils.html -- Installing ./html/gstreamer-GstValue.html -- Installing ./html/gstreamer-GstVersion.html -- Installing ./html/gstreamer-compat.html -- Installing ./html/gstreamer-gstconfig.html -- Installing ./html/gstreamer-hierarchy.html -- Installing ./html/gstreamer-support.html -- Installing ./html/gstreamer.html -- Installing ./html/index.html -- Installing ./html/home.png -- Installing ./html/left.png -- Installing ./html/right.png -- Installing ./html/up.png -- Installing ./html/gstreamer.devhelp -- Installing ./html/index.sgml -- Installing ./html/style.css make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/gst' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/gst' Making install in libs make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/libs' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/libs' make[3]: Nothing to be done for `install-exec-am'. /bin/sh ../../mkinstalldirs /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-libs-0.8 mkdir /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-libs-0.8 (installfiles=`echo ./html/*.html`; \ if test "$installfiles" = './html/*.html'; \ then echo '-- Nothing to install' ; \ else \ for i in $installfiles; do \ echo '-- Installing '$i ; \ /usr/bin/install -c -m 644 $i /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-libs-0.8; \ done; \ pngfiles=`echo ./html/*.png`; \ if test "$pngfiles" != './html/*.png'; then \ for i in $pngfiles; do \ echo '-- Installing '$i ; \ /usr/bin/install -c -m 644 $i /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-libs-0.8; \ done; \ fi; \ echo '-- Installing ./html/gstreamer-libs.devhelp' ; \ /usr/bin/install -c -m 644 ./html/gstreamer-libs.devhelp \ /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-libs-0.8/gstreamer-libs-0.8.devhelp; \ echo '-- Installing ./html/index.sgml' ; \ /usr/bin/install -c -m 644 ./html/index.sgml /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-libs-0.8; \ if test -e ./html/style.css; then \ echo '-- Installing ./html/style.css' ; \ /usr/bin/install -c -m 644 ./html/style.css /var/tmp/gstreamer08-0.8.11-root/usr/share/gtk-doc/html/gstreamer-libs-0.8; \ fi; \ fi) -- Installing ./html/GstDParam.html -- Installing ./html/GstDParamLinInterp.html -- Installing ./html/GstDParamManager.html -- Installing ./html/GstDParamSmooth.html -- Installing ./html/GstUnitConvert.html -- Installing ./html/api-index.html -- Installing ./html/gstreamer-control.html -- Installing ./html/gstreamer-libs-GstControl.html -- Installing ./html/gstreamer-libs-gstadapter.html -- Installing ./html/gstreamer-libs-gstbytestream.html -- Installing ./html/gstreamer-libs-gstdataprotocol.html -- Installing ./html/gstreamer-libs-gstgetbits.html -- Installing ./html/gstreamer-libs-hierarchy.html -- Installing ./html/gstreamer-libs.html -- Installing ./html/index.html -- Installing ./html/home.png -- Installing ./html/left.png -- Installing ./html/right.png -- Installing ./html/up.png -- Installing ./html/gstreamer-libs.devhelp -- Installing ./html/index.sgml -- Installing ./html/style.css make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/libs' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs/libs' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[3]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[3]: Nothing to be done for `install-exec-am'. make[3]: Nothing to be done for `install-data-am'. make[3]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11/docs' make[1]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' make[2]: Entering directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' make[2]: Nothing to be done for `install-exec-am'. test -z "/var/tmp/gstreamer08-0.8.11-root/usr/share/aclocal" || mkdir -p -- "/var/tmp/gstreamer08-0.8.11-root/usr/share/aclocal" /usr/bin/install -c -m 644 'gst-element-check-0.8.m4' '/var/tmp/gstreamer08-0.8.11-root/usr/share/aclocal/gst-element-check-0.8.m4' make[2]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' make[1]: Leaving directory `/usr/src/rpm/BUILD/gstreamer-0.8.11' + mkdir -p /var/tmp/gstreamer08-0.8.11-root/var/cache/gstreamer-0.8 + /bin/rm -f /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.a + /bin/rm -f /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.la + /bin/rm -f /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.a /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.a + /bin/rm -f /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.la /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.la + /bin/rm -f '/var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstmedia-info*.so.0.0.0' + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-launch + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-inspect + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-register + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmllaunch + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-complete + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-compprep + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-feedback + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-md5sum + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-typefind + for a in launch inspect register xmllaunch complete compprep feedback md5sum typefind xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmlinspect + rm /var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-i686 + rm /var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-x86_64 rm: cannot remove `/var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-x86_64': No such file or directory + true + rm /var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-ppc rm: cannot remove `/var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-ppc': No such file or directory + true + /usr/lib/rpm/redhat/find-lang.sh /var/tmp/gstreamer08-0.8.11-root gstreamer-0.8 + /usr/lib/rpm/find-debuginfo.sh /usr/src/rpm/BUILD/gstreamer-0.8.11 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstreamer-0.8.so.1.4.0 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstfairgthreadscheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentrygthreadscheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicomegascheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstentryomegascheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstgetbits.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstindexers.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstspider.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbytestream.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptgthreadscheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstelements.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstdataprotocol.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptscheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstoptomegascheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/gstreamer-0.8/libgstbasicgthreadscheduler.so extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/lib/libgstcontrol-0.8.so.1.4.0 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-inspect-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-typefind-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmlinspect-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-launch-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-compprep-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-xmllaunch-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-md5sum-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/bin/gst-complete-0.8 extracting debug info from /var/tmp/gstreamer08-0.8.11-root/usr/libexec/gst-register-i686-0.8 8563 blocks + /usr/lib/rpm/redhat/brp-compress + /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump + /usr/lib/rpm/brp-python-bytecompile Processing files: gstreamer08-0.8.11-1 Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.78359 + umask 022 + cd /usr/src/rpm/BUILD + cd gstreamer-0.8.11 + DOCDIR=/var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-0.8.11 + export DOCDIR + rm -rf /var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-0.8.11 + /bin/mkdir -p /var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-0.8.11 + cp -pr AUTHORS COPYING README TODO ABOUT-NLS REQUIREMENTS DOCBUILDING /var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-0.8.11 + exit 0 Provides: libgstbasicgthreadscheduler.so libgstbasicomegascheduler.so libgstbytestream.so libgstcontrol-0.8.so.1 libgstdataprotocol.so libgstelements.so libgstentrygthreadscheduler.so libgstentryomegascheduler.so libgstfairgthreadscheduler.so libgstgetbits.so libgstindexers.so libgstoptgthreadscheduler.so libgstoptomegascheduler.so libgstoptscheduler.so libgstreamer-0.8.so.1 libgstspider.so Requires(interp): /bin/sh /sbin/ldconfig Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Requires(post): /bin/sh /sbin/ldconfig Requires(postun): /sbin/ldconfig Requires: /bin/sh glib2 >= 2.3.0 libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1) libc.so.6(GLIBC_2.1.3) libc.so.6(GLIBC_2.2) libc.so.6(GLIBC_2.3) libc.so.6(GLIBC_2.3.4) libc.so.6(GLIBC_2.4) libdl.so.2 libdl.so.2(GLIBC_2.0) libglib-2.0.so.0 libgmodule-2.0.so.0 libgobject-2.0.so.0 libgstcontrol-0.8.so.1 libgstreamer-0.8.so.1 libgthread-2.0.so.0 libm.so.6 libm.so.6(GLIBC_2.0) libpopt.so.0 libpthread.so.0 libpthread.so.0(GLIBC_2.0) libpthread.so.0(GLIBC_2.2) libxml2 >= 2.4.9 libxml2.so.2 libz.so.1 popt > 1.6 Processing files: gstreamer08-devel-0.8.11-1 Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.78359 + umask 022 + cd /usr/src/rpm/BUILD + cd gstreamer-0.8.11 + DOCDIR=/var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-devel-0.8.11 + export DOCDIR + rm -rf /var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-devel-0.8.11 + /bin/mkdir -p /var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-devel-0.8.11 + cp -pr installed-doc/html /var/tmp/gstreamer08-0.8.11-root/usr/share/doc/gstreamer08-devel-0.8.11 + exit 0 Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Requires: glib2-devel >= 2.3.0 gstreamer08 = 0.8.11-1 libxml2-devel >= 2.4.9 Processing files: gstreamer08-debuginfo-0.8.11-1 Provides: libgstbasicgthreadscheduler.so.debug libgstbasicomegascheduler.so.debug libgstbytestream.so.debug libgstcontrol-0.8.so.1.4.0.debug libgstdataprotocol.so.debug libgstelements.so.debug libgstentrygthreadscheduler.so.debug libgstentryomegascheduler.so.debug libgstfairgthreadscheduler.so.debug libgstgetbits.so.debug libgstindexers.so.debug libgstoptgthreadscheduler.so.debug libgstoptomegascheduler.so.debug libgstoptscheduler.so.debug libgstreamer-0.8.so.1.4.0.debug libgstspider.so.debug Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/tmp/gstreamer08-0.8.11-root warning: Could not canonicalize hostname: ana Wrote: /usr/src/rpm/SRPMS/gstreamer08-0.8.11-1.src.rpm Wrote: /usr/src/rpm/RPMS/gstreamer08-0.8.11-1.i386.rpm Wrote: /usr/src/rpm/RPMS/gstreamer08-devel-0.8.11-1.i386.rpm Wrote: /usr/src/rpm/RPMS/gstreamer08-debuginfo-0.8.11-1.i386.rpm Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.2520 + umask 022 + cd /usr/src/rpm/BUILD + cd gstreamer-0.8.11 + rm -rf /var/tmp/gstreamer08-0.8.11-root + exit 0